Замените значение в узле, сохраняющем структуру XML, используя XSLT - PullRequest
0 голосов
/ 20 февраля 2020

У меня есть требование, где мне нужно заменить значение узла на основе атрибутов другим значением, сохранив исходную структуру XML. По сути, мне нужно скопировать весь XML только путем замены определенных значений, когда указанные атрибуты c встречаются в оригинале XML.

Ниже приведен пример XML до преобразования и после преобразования.

Оригинал XML:

<root>
    <body>
        <node_level1>
            <node_level2>
                <node_level3>
                    <value animal="cat">Munchkin</value>
                </node_level3>
                <node_level3>
                    <value animal="cat">Turkish Angora</value>
                </node_level3>
                <node_level3>
                    <value animal="cat">La Perm</value>
                </node_level3>
            </node_level2>
            <node_level2>
                <node_level3>
                    <node_level4>
                        <value animal="dog">Siberian Husky</value>
                    </node_level4>
                    <node_level4>
                        <value animal="dog">Pug</value>
                    </node_level4>
                    <node_level4>
                        <value animal="dog">Beagle</value>
                    </node_level4>
                </node_level3>
            </node_level2>
        </node_level1>
    </body>
</root>

После преобразования данных с использованием XSLT мне нужно XML, как показано ниже:

<root>
    <body>
        <node_level1>
            <node_level2>
                <node_level3>
                    <value animal="cat">Cat Family</value>
                </node_level3>
                <node_level3>
                    <value animal="cat">Cat Family</value>
                </node_level3>
                <node_level3>
                    <value animal="cat">Cat Family</value>
                </node_level3>
            </node_level2>
            <node_level2>
                <node_level3>
                    <node_level4>
                        <value animal="dog">Dog Family</value>
                    </node_level4>
                    <node_level4>
                        <value animal="dog">Dog Family</value>
                    </node_level4>
                    <node_level4>
                        <value animal="dog">Dog Family</value>
                    </node_level4>
                </node_level3>
            </node_level2>
        </node_level1>
    </body>
</root>

Вот код, который работает для указанных атрибутов, мне нужно обобщить его.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl" version="2.0">
    <xsl:template match="/">
        <root>
            <xsl:for-each select="//*[value[@animal = 'cat']]">
                <xsl:copy>
                    <xsl:value-of select="@*"/>
                    <xsl:value-of select="'Cat Family'"/>
                </xsl:copy>
            </xsl:for-each>
        </root>
    </xsl:template>
</xsl:stylesheet>

Ответы [ 2 ]

3 голосов
/ 20 февраля 2020

Это очень простая задача, вам нужно использовать шаблон идентификации для копирования всех xml узлов, как есть:

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

Затем вы можете использовать отдельный шаблон элемента value согласно вашему требование:

<xsl:template match="value">
    <xsl:choose>
        <xsl:when test="@animal = 'cat'">
            <value animal="cat">Cat Family</value>
        </xsl:when>
        <xsl:when test="@animal = 'dog'">
            <value animal="dog">Dog Family</value>
        </xsl:when>
    </xsl:choose>
</xsl:template>

Окончательный XSL-файл:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl" version="2.0">

    <!-- indent elements to see properly -->
    <xsl:output indent="yes"/>

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

    <xsl:template match="value">
        <xsl:choose>
            <xsl:when test="@animal = 'cat'">
                <value animal="cat">Cat Family</value>
            </xsl:when>
            <xsl:when test="@animal = 'dog'">
                <value animal="dog">Dog Family</value>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>
1 голос
/ 20 февраля 2020

В XSLT 3 вы можете объявить преобразование идентичности с xsl:mode on-no-match="shallow-copy" в качестве обработки по умолчанию, а затем сопоставить value[@animal]:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="value[@animal]">
      <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:value-of select="@animal || ' family'"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/94Acsmj

...