Как создать свои теги через XSLT

Есть xml:

<?xml version="1.0" encoding="utf-8"?>
<Records count="2">
  <Metadata>
    <FieldDefinitions>
      <FieldDefinition id="123" guid="ef0ce125-ca87-4f13-92f6-988eefcb389e" name="Наименование1" alias="Наименование1" />
      <FieldDefinition id="456" guid="524f9b49-316e-4dd8-ae49-7a3e58b67adf" name="Наименование2" alias="Наименование2" />
      <FieldDefinition id="789" guid="62c6d1d3-8b49-4128-a758-ec383894c432" name="Наименование3" alias="Наименование3" />
    </FieldDefinitions>
  </Metadata>
  <LevelCounts>
    <LevelCount id="111" guid="ac53e54a-b5b3-4f92-aba1-b67e4156a868" count="2" />
  </LevelCounts>
  <Record contentId="253172" levelId="329" levelGuid="ad31d387-af1a-4642-9bbf-719f9b3ab251" moduleId="222" parentId="0">
    <Field id="123" guid="ef0ce125-ca87-4f13-92f6-988eefcb389e" type="6">1223445</Field>
    <Field id="456" guid="524f9b49-316e-4dd8-ae49-7a3e58b67adf" type="1">Имя чего нибудь</Field>
    <Field id="789" guid="62c6d1d3-8b49-4128-a758-ec383894c432" type="1">аааааааа</Field>
  </Record>
  <Record contentId="253195" levelId="329" levelGuid="ad31d387-af1a-4642-9bbf-719f9b3ab251" moduleId="222" parentId="0">
    <Field id="123" guid="ef0ce125-ca87-4f13-92f6-988eefcb389e" type="6">1233</Field>
    <Field id="456" guid="524f9b49-316e-4dd8-ae49-7a3e58b67adf" type="1">Имя чего нибудь2</Field>
    <Field id="789" guid="62c6d1d3-8b49-4128-a758-ec383894c432" type="1">бббббббббб</Field>
  </Record>
</Records>

Как преобразовать это в это?

<?xml version="1.0" encoding="utf-8"?>
<Records>
   <Record>
      <id>1223445</id>
      <name>Имя чего нибудь</name>
      <comment>аааааааа</comment>
   </Record>
   <Record>
      <id>1233</id>
      <name>Имя чего нибудь2</name>
      <comment>бббббббббб</comment>
   </Record>
</Records>

Я использую вот такой xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Records">
  <Records>
    <xsl:apply-templates select="Record"/>
  </Records>
</xsl:template>
<xsl:template match="Record">
  <Record>
    <xsl:for-each select="Field">
      <xsl:element name="{/Records/Metadata/FieldDefinitions/FieldDefinition[@guid=current()/@guid]/@alias}">
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:for-each>
  </Record>
</xsl:template>
</xsl:stylesheet>

мне нужно сделать собственные наименования полей, заполнить их по guid. Т.к. в системе могут измениться наименования, поэтому нужно сделать привязку по guid. Но guid использовать в качестве наименования нельзя(XSLT интерпретатор ругается на это).


Ответы (2 шт):

Автор решения: Yitzhak Khabinsky

Вот решение на основе XSLT 2.0 или более поздней версии.

XSLT использует идею Lookup для присвоения желаемых имен XML-элементов.

Полезная ссылка для XSLT 3.0 для Python

Вы можете скачать Saxon Home Edition (HE) бесплатно.

Входной XML

<?xml version="1.0" encoding="utf-8"?>
<Records count="2">
    <Metadata>
        <FieldDefinitions>
            <FieldDefinition id="123"
                             guid="ef0ce125-ca87-4f13-92f6-988eefcb389e"
                             name="Наименование1" alias="Наименование1"/>
            <FieldDefinition id="456"
                             guid="524f9b49-316e-4dd8-ae49-7a3e58b67adf"
                             name="Наименование2" alias="Наименование2"/>
            <FieldDefinition id="789"
                             guid="62c6d1d3-8b49-4128-a758-ec383894c432"
                             name="Наименование3" alias="Наименование3"/>
        </FieldDefinitions>
    </Metadata>
    <LevelCounts>
        <LevelCount id="111" guid="ac53e54a-b5b3-4f92-aba1-b67e4156a868"
                    count="2"/>
    </LevelCounts>
    <Record contentId="253172" levelId="329"
            levelGuid="ad31d387-af1a-4642-9bbf-719f9b3ab251" moduleId="222"
            parentId="0">
        <Field id="123" guid="ef0ce125-ca87-4f13-92f6-988eefcb389e" type="6">1223445</Field>
        <Field id="456" guid="524f9b49-316e-4dd8-ae49-7a3e58b67adf" type="1">Имя чего нибудь</Field>
        <Field id="789" guid="62c6d1d3-8b49-4128-a758-ec383894c432" type="1">аааааааа</Field>
    </Record>
    <Record contentId="253195" levelId="329"
            levelGuid="ad31d387-af1a-4642-9bbf-719f9b3ab251" moduleId="222"
            parentId="0">
        <Field id="123" guid="ef0ce125-ca87-4f13-92f6-988eefcb389e" type="6">1233</Field>
        <Field id="456" guid="524f9b49-316e-4dd8-ae49-7a3e58b67adf" type="1">Имя чего нибудь2</Field>
        <Field id="789" guid="62c6d1d3-8b49-4128-a758-ec383894c432" type="1">бббббббббб</Field>
    </Record>
</Records>

XSLT 2.0

<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

    <xsl:key name="lookup" match="row" use="@alias"/>

    <xsl:variable name="lookup">
        <row alias="Наименование1" elem="id"/>
        <row alias="Наименование2" elem="name"/>
        <row alias="Наименование3" elem="comment"/>
    </xsl:variable>

    <xsl:template match="/Records">
        <xsl:copy>
            <xsl:for-each select="Record">
                <xsl:copy>
                    <xsl:for-each select="Field">
                        <xsl:variable name="alias"
                                      select="/Records/Metadata/FieldDefinitions/FieldDefinition[@guid=current()/@guid]/@alias"/>
                        <xsl:element name="{key('lookup', $alias, $lookup)/@elem}">
                            <xsl:value-of select="."/>
                        </xsl:element>
                    </xsl:for-each>
                </xsl:copy>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Результат

<?xml version='1.0' encoding='UTF-8' ?>
<Records>
  <Record>
    <id>1223445</id>
    <name>Имя чего нибудь</name>
    <comment>аааааааа</comment>
  </Record>
  <Record>
    <id>1233</id>
    <name>Имя чего нибудь2</name>
    <comment>бббббббббб</comment>
  </Record>
</Records>
→ Ссылка
Автор решения: Don Perez

Мой конечный результат получился таким:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

    <xsl:key name="lookup" match="row" use="@guid"/>

    <xsl:variable name="lookup">
        <row guid="ef0ce125-ca87-4f13-92f6-988eefcb389e" elem="id"/>
        <row guid="524f9b49-316e-4dd8-ae49-7a3e58b67adf" elem="name"/>
        <row guid="62c6d1d3-8b49-4128-a758-ec383894c432" elem="comment"/>
    </xsl:variable>

    <xsl:template match="/Records">
        <xsl:copy>
            <xsl:for-each select="Record">
                <xsl:copy>
                    <xsl:for-each select="Field">
                        <xsl:variable name="guid"
                                      select="/Records/Metadata/FieldDefinitions/FieldDefinition[@guid=current()/@guid]/@guid"/>
                        <xsl:element name="{key('lookup', $guid, $lookup)/@elem}">
                            <xsl:value-of select="."/>
                        </xsl:element>
                    </xsl:for-each>
                </xsl:copy>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
→ Ссылка