XSL-复制子节点的父节点

时间:2018-08-27 15:02:08

标签: xml xslt

在其他结构中搜索具有相同名称的节点并替换其值之后,如何复制匹配节点的父节点?

我可以在模板中为每个孩子的父母设置密钥吗?

从此

<Message>
<XMLNSC>
    <MaXML>
        <Rule>
            <A>RuleA</A>
            <D>RuleD</D>
        </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>
        </Rule>
        <Body>
            <A>RuleA</A>
            <A>RuleA</A>
            <B>valB</B>
            <C>
                <D>RuleD</D>
                <D>RuleD</D>
            </C>
            <C>
                <D>RuleD</D>
                <D>RuleD</D>
            </C>
        </Body>
        <Body>
            <A>RuleA</A>
            <A>RuleA</A>
            <B>valB</B>
            <C>
                <D>RuleD</D>
                <D>RuleD</D>
            </C>
            <C>
                <D>RuleD</D>
                <D>RuleD</D>
            </C>
        </Body>
    </MaXML>
</XMLNSC>

我的XSLT, https://xsltfiddle.liberty-development.net/pPqsHTK/5

1 个答案:

答案 0 :(得分:1)

如果您为MaXML的后代编写模板,这些子代具有一个键匹配的子元素,则只需在这些后代元素上使用两次身份模板,我就排除了Rule元素然后明确地:

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

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

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

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

  <xsl:template match="MaXML//*[not(self::Rule)][*[key('ref', concat(generate-id(ancestor::MaXML), '|', name()))]]">
      <xsl:call-template name="identity"/>
      <xsl:call-template name="identity"/>
  </xsl:template>

  <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>

      <!-- duplicate matched node -->
        <xsl:element name="{name()}">
            <xsl:value-of select="key('ref', concat(generate-id(ancestor::MaXML), '|', name()))"/>
        </xsl:element>
  </xsl:template>

</xsl:stylesheet>

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

使用XSLT 3,它会更容易一些:

  <xsl:template match="MaXML//*[not(self::Rule)][*[key('ref', node-name(), ancestor::MaXML)]]">
      <xsl:next-match/>
      <xsl:next-match/>
  </xsl:template>

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