Преобразовать элемент с атрибутом в новые элементы с помощью xslt - PullRequest
0 голосов
/ 25 октября 2018

Как преобразовать элемент с определенным атрибутом в новый родительский элемент с дочерними элементами в xslt?Более конкретно, каждый раз, когда появляется элемент с атрибутом «WeightUOM» или «VolumeUOM», должен быть создан новый элемент.

Желание состоит в преобразовании следующих элементов с атрибутами:

  <anyWeightElementName WeightUOM="LBS">123.45</anyWeightElementName>
  <anyVolumeElementName VolumeUOM="CUF">0.65</anyVolumeElementName>

к этому, родительский элемент (без значения), новый элемент "Weight" или "Volume" и новый элемент "WeightUOM" или "VolumeUOM" со значением атрибута.

        <anyWeightElementName >
            <Weight>123.45</Weight>
            <WeightUOM>LBS</WeightUOM>
        </anyWeightElementName >
        <anyVolumeElementName>
            <Volume>0.65</Volume>
            <VolumeUOM>CUF</VolumeUOM>
        </anyVolumeElementName>

входной XML

<Response>
<Deliveries>
    <Delivery>
        <EstimatedWeight WeightUOM="LBS">123.45</EstimatedWeight>
        <EstimatedVolume VolumeUOM="CUF">0.65</EstimatedVolume>
        <Customers>
            <Customer>
                <Name>Smith</Name>
                <Zip>12345</Zip>
                <ActualWeight WeightUOM="TON">1.00</ActualWeight>
                <ActualVolume VolumeUOM="CUI">400.00</ActualVolume>
            </Customer>
            <Customer>
                <Name>Jones</Name>
                <Zip>54321</Zip>
                <ActualWeight WeightUOM="TON">0.024</ActualWeight>
                <ActualVolume VolumeUOM="CUF">0.45</ActualVolume>
            </Customer>
        </Customers>
    </Delivery>
</Deliveries>
</Response>

желаемый выход

<Response>
<Deliveries>
    <Delivery>
        <EstimatedWeight>
            <Weight>123.45</Weight>
            <WeightUOM>LBS</WeightUOM>
        </EstimatedWeight>
        <EstimatedVolume>
            <Volume>0.65</Volume>
            <VolumeUOM>CUF</VolumeUOM>
        </EstimatedVolume>
        <Customers>
            <Customer>
                <Name>Smith</Name>
                <Zip>12345</Zip>
                <ActualWeight>
                    <Weight>1.00</Weight>
                    <WeightUOM>TON</WeightUOM>
                </ActualWeight>
                <ActualVolume>
                    <Volume>400.00</Volume>
                    <VolumeUOM>CUI</VolumeUOM>
                </ActualVolume>
            </Customer>
            <Customer>
                <Name>Jones</Name>
                <Zip>54321</Zip>
                <ActualWeight>
                    <Weight>0.024</Weight>
                    <WeightUOM>TON</WeightUOM>
                </ActualWeight>
                <ActualVolume>
                    <Volume>0.45</Volume>
                    <VolumeUOM>CUF</VolumeUOM>
                </ActualVolume>
            </Customer>
        </Customers>
    <Delivery>
</Deliveries>
</Response>

попытка XSLT

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

<xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="@WeightUOM">
    <xsl:element name="{name(.)}">
        <xsl:element name="Weight">
            <xsl:value-of select="."/>
        </xsl:element>
        <xsl:element name="WeightUOM">
            <xsl:value-of select="@WeightUOM"/>
        </xsl:element>
    </xsl:element>
</xsl:template>

<xsl:template match="@VolumeUOM">
    <xsl:element name="{name(.)}">
        <xsl:element name="Volume">
            <xsl:value-of select="."/>
        </xsl:element>
        <xsl:element name="VolumeUOM">
            <xsl:value-of select="@VolumeUOM"/>
        </xsl:element>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

Это текущий вывод из списка xslt.Xslt не создает новые элементы.

<Response>
<Deliveries>
    <Delivery>
        <EstimatedWeight>123.45</EstimatedWeight>
        <EstimatedVolume>0.65</EstimatedVolume>
        <Customers>
            <Customer>
                <Name>Smith</Name>
                <Zip>12345</Zip>
                <ActualWeight>1.00</ActualWeight>
                <ActualVolume>400.00</ActualVolume>
            </Customer>
            <Customer>
                <Name>Jones</Name>
                <Zip>54321</Zip>
                <ActualWeight>0.024</ActualWeight>
                <ActualVolume>0.45</ActualVolume>
            </Customer>
        </Customers>
    </Delivery>
</Deliveries>
</Response>

1 Ответ

0 голосов
/ 25 октября 2018

Проблема с использованием <xsl:apply-templates/>;это сокращение от <xsl:apply-templates select="node()" />, поэтому он выбирает узлы, но не атрибуты.Без каких-либо атрибутов выбранного элемента ваши шаблоны для них просто никогда не будут совпадать.

Вместо этого вам нужно сделать следующее:

<xsl:apply-templates select="@*|node()" />

На самом деле, вы все равно, возможно, захотите использовать здесь «шаблон личности»

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

Кроме того, всопоставление с шаблоном @WeightUOM вы в настоящее время делаете <xsl:value-of select="@WeightUOM"/>, но так как вы уже сопоставляете @WeightUOM, то это ничего не даст, так как оно будет пытаться выбрать атрибут текущего атрибута.Вы должны сделать это, чтобы получить значение текущего атрибута

<xsl:value-of select="."/>

И сделать это, чтобы получить значение родительского элемента

<xsl:value-of select="../text()"/>

Вам также не нужно делать<xsl:element name="{name(.)}"> потому что шаблон, соответствующий *, создаст содержащий элемент.(И name(.) получает имя атрибута. В любом случае, вам, вероятно, следовало бы сделать name(..) здесь.)

Наконец, вам, вероятно, нужны шаблоны, явно совпадающие с дочерними текстовыми узлами, чтобы они не выводились дважды

<xsl:template match="*[@WeightUOM]/text()" /> 

Попробуйте это XSLT

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

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

<xsl:template match="*[@WeightUOM]/text()" />
<xsl:template match="*[@VolumeUOM]/text()" />

<xsl:template match="@WeightUOM">
    <Weight>
        <xsl:value-of select="../text()"/>
    </Weight>
    <WeightUOM>
        <xsl:value-of select="."/>
    </WeightUOM>
</xsl:template>

<xsl:template match="@VolumeUOM">
    <Volume>
        <xsl:value-of select="../text()"/>
    </Volume>
    <VolumeUOM>
        <xsl:value-of select="."/>
    </VolumeUOM>
</xsl:template>
</xsl:stylesheet>

Обратите внимание, что нет необходимости использовать xsl:element, если имя элемента статическое.

Или объединить шаблоны,если тебе нравится ...

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

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
</xsl:template>

<xsl:template match="*[@WeightUOM|@VolumeUOM]/text()" />

<xsl:template match="@WeightUOM|@VolumeUOM">
    <xsl:element name="{substring-before(name(), 'UOM')}">
        <xsl:value-of select="../text()"/>
    </xsl:element>
    <xsl:element name="{name()}">
        <xsl:value-of select="."/>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...