XSL - заменить значение узла из другой структуры, но с тем же именем - PullRequest
0 голосов
/ 24 августа 2018

Я пытаюсь заменить некоторые значения узлов.Идея заключается в поиске узла с таким же именем в другой структуре и замене значения.

Здесь я меняю значения с Body / A на Rule / A и Body / C / D на Rule / D.

Примерно так.

<Message>
<XMLNSC>
    <MaXML>
        <Rule>
            <A>RuleA</A>
            <D>RuleD</D>
            <E>RuleE</E>
        </Rule>
        <Body>
            <A>valA</A>
            <B>valB</B>
            <C>
                <D>valD</D>
            </C>
        </Body>
    </MaXML>
</XMLNSC>

К этому.

<Message>
<XMLNSC>
    <MaXML>
        <Rule>
            <A>RuleA</A>
            <D>RuleD</D>
            <E>RuleE</E>
        </Rule>
        <Body>
            <A>RuleA</A>
            <B>valB</B>
            <C>
                <D>RuleD</D>
            </C>
        </Body>
    </MaXML>
</XMLNSC>

В настоящее время я перебираю всех детей, ища совпадение имен узлов, но как мне сохранить ту же структуру и просто изменить значение?

<?xml version="1.0" encoding="utf-8"?>

<xsl:output method="xml" indent="yes"/>

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

<!-- match Body -->
<xsl:template match="Body">
    <Body>
        <!-- all children from body -->
        <xsl:for-each select="descendant::*">
            <xsl:variable name="maNode" select="."/>
            <xsl:variable name="nodeName" select="name()"/>
            <!-- all rules -->
            <xsl:for-each select="//Rule/*">
                <xsl:variable name="varRuleName" select="name()"/>  
                <xsl:choose>
                    <!-- match rule -->
                    <xsl:when test="$nodeName = $varRuleName">
                        <element name="match"/>
                        <xsl:copy>
                            <xsl:apply-templates select="@* | node()"/>
                        </xsl:copy>
                    </xsl:when>
                    <xsl:otherwise>
                        <element name="unmatch"/>
                        <xsl:copy>
                            <xsl:apply-templates select="@* | node()"/>
                        </xsl:copy>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </xsl:for-each>
    </Body>
</xsl:template>

1 Ответ

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

Подход с шаблоном идентификации

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

вполне подходит, теперь для использования вам просто нужно добавить шаблоны для тех элементов, которые вы хотите изменить, например,

  <xsl:template match="Body/A">
      <xsl:copy>
          <xsl:value-of select="ancestor::MaXML/Rule/A"/>
      </xsl:copy>
  </xsl:template>

https://xsltfiddle.liberty -development.net / pPqsHTK

Должно быть понятно, я надеюсь, как добавить третий шаблон, соответствующий Body/C/D и выбрав значение из соответствующего Rule при необходимости.

Если вам нужен универсальный подход, то в XSLT 2 или 3 это просто с помощью клавиши и вызова ключевой функции в поддереве:

  <xsl:key name="ref" match="MaXML/Rule/*" use="node-name()"/>

  <xsl:template match="Body//*[key('ref', node-name(), ancestor::MaXML)]">
      <xsl:copy>
          <xsl:value-of select="key('ref', node-name(), ancestor::MaXML)"/>
      </xsl:copy>
  </xsl:template>

Полный XSLT 3 в https://xsltfiddle.liberty-development.net/pPqsHTK/3 равен

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0">

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

  <xsl:key name="ref" match="MaXML/Rule/*" use="node-name()"/>

  <xsl:template match="Body//*[key('ref', node-name(), ancestor::MaXML)]">
      <xsl:copy>
          <xsl:value-of select="key('ref', node-name(), ancestor::MaXML)"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

К сожалению, XSLT 1 не имеет третьего аргумента для функции key, поэтому для реализации общего подхода с ключом вам необходимовключите generate-id(ancestor::MaXML) в значение ключа:

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

  <xsl:template match="Body//*[key('ref', concat(generate-id(ancestor::MaXML), '|', name()))]">
      <xsl:copy>
          <xsl:value-of select="key('ref', concat(generate-id(ancestor::MaXML), '|', name()))"/>
      </xsl:copy>
  </xsl:template>

Пример на https://xsltfiddle.liberty -development.net / pPqsHTK / 4 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...