XSL - заменить одноименное значение узла другими значениями. - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь заменить узлы (D) с тем же именем, но в разных структурах (Body / C и Body / E) в соответствии с соответствием их значений значениям из Rule / Item. Может быть, что-то вроде для каждого.

Я использую два ключа, один с новыми значениями, а другой со старыми (возможно, бесполезными), затем я для каждого каждого, но тот, у которого новые значения, мне ничего не дает. Разве не должен работать?

Еще одна проблема, я хочу продублировать родителя соответствующего узла, и мой XSLT также удваивает «Элементы».

Input

<Message>
<XMLNSC>
    <Translator>
        <Rule>
            <Item>
                <D>RuleD1</D>
                <New>RuleD1</New> <!-- I guess I don't need an element for this -->
                <Original>valD1</Original>
            </Item>
            <Item>
                <D>RuleD2</D>
                <New>RuleD2</New> <!-- I guess I don't need an element for this -->
                <Original>valD2</Original>
            </Item>
        </Rule>
        <Body>
            <A>valA</A>
            <B>valB</B>
            <C>
                <D>valD1</D>
            </C>
            <E>
                <D>valD2</D>
            </E>
        </Body>
    </Translator>
</XMLNSC>

Ожидаемое

<Message>
<XMLNSC>
    <Translator>
        <Rule>
            <Item>
                <D>RuleD1</D>
                <New>RuleD1</New> <!-- I guess I don't need an element for this -->
                <Original>valD1</Original>
            </Item>
            <Item>
                <D>RuleD2</D>
                <New>RuleD2</New> <!-- I guess I don't need an element for this -->
                <Original>valD2</Original>
            </Item>
        </Rule>
        <Body>
            <A>valA</A>
            <B>valB</B>
            <C>
                <D>RuleD1</D>
                <D_Agg>val1</D_Agg>
            </C>
            <C>
                <D>RuleD1</D>
                <D_Agg>val1</D_Agg>
            </C>
            <E>
                <D>RuleD2</D>
                <D_Agg>val2</D_Agg>
            </E>
            <E>
                <D>RuleD2</D>
                <D_Agg>val2</D_Agg>
            </E>
        </Body>
    </Translator>
</XMLNSC>

Это мой XSLT:

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

    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>

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

    <xsl:key name="ref" match="Translator/Rule//*" use="concat(generate-id(ancestor::Translator), '|', name())"/>

    <xsl:key name="ref_new"     match="New" use="text()"/>
    <xsl:key name="ref_origin"  match="Original" use="text()"/>


    <!-- duplicate matched node's parent -->
    <xsl:template match="Translator//*[not(self::Rule)][*[key('ref', concat(generate-id(ancestor::Translator), '|', name()))]]">
        <xsl:call-template name="identity"/>
        <xsl:call-template name="identity"/>
    </xsl:template>

    <!-- replace matched node's value -->
    <xsl:template match="Body//*[key('ref', concat(generate-id(ancestor::Translator), '|', name()))]">

        <xsl:variable name="fieldName" select="name()"/>
        <xsl:variable name="fieldValue" select="."/>

        <!-- <xsl:copy> -->
            <!-- <xsl:value-of select="key('ref', concat(generate-id(ancestor::Translator), '|', name()))"/> -->
        <!-- </xsl:copy> -->


        <xsl:for-each select="key('ref_new', text())">
            <xsl:element name="{$fieldName}">
                <xsl:value-of select="$fieldValue"/>
            </xsl:element>
        </xsl:for-each>

        <xsl:for-each select="key('ref_origin', text())">
            <xsl:element name="{$fieldName}_Agg">
                <xsl:value-of select="$fieldValue"/>
            </xsl:element>
        </xsl:for-each>

    </xsl:template>
</xsl:stylesheet>

Всего как скрипка:
https://xsltfiddle.liberty -development.net / pPqsHTM / 2

1 Ответ

0 голосов
/ 31 августа 2018

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

  1. Я изменил ваш второй xsl:key на

    <xsl:key name="ref_origin"  match="Item" use="Original"/>
    

    Это делает доступным дочерний элемент D, который используется в последнем xsl:for-each, но сохраняет значение вашего ключа.

  2. Я изменил ваш идентификатор шаблон вызывающего абонента, чтобы избежать дублирования элементов Item, добавив xsl:if вокруг второго вызова

    <!-- duplicate matched node's parent -->
    <xsl:template match="Translator//*[not(self::Rule)][*[key('ref', concat(generate-id(ancestor::Translator), '|', name()))]]">
        <xsl:call-template name="identity" />
        <xsl:if test="not(self::Item)">
            <xsl:call-template name="identity" />
        </xsl:if>
    </xsl:template>
    
  3. Я добавил еще один элемент к последнему xsl:for-each, чтобы добавить элемент D, доступ к которому осуществляется из xsl:key, упомянутого выше

    <xsl:for-each select="key('ref_origin', text())">
        <xsl:element name="{$fieldName}">
            <xsl:value-of select="D"/>       <!-- Using the D child of the Item from the key -->
        </xsl:element>
        <xsl:element name="{$fieldName}_Agg">
            <xsl:value-of select="$fieldValue"/>
        </xsl:element>
    </xsl:for-each>
    

Теперь вывод должен быть таким, как ожидалось.

...