通过重复除一个元素之外的所有其他元素在XSLT中构造xml

时间:2014-02-07 18:53:26

标签: xml xslt

我是XSLT的新手,并尝试谷歌搜索找到解决方案,但不能。我需要通过重复除重复元素之外的所有其他元素在XSLT中构造一个xml。

输入XML:这里元素D是重复的。它可能不止一次发生。根据它出现的次数,我的输出XML应该多次包含整个输入XML,除了元素D是分布式的。 如果答案对于D个重复次数是通用的,那将是非常有用的。

    <ABCD>
       <A> 
        <B> 
         <C>
            <D>d1</D>
            <D>d2</D>
            <D>d3</D>
         </C> 
        </B> 
       </A>
     </ABCD>

输出XML:

      <ABCD>
       <A> 
        <B> 
         <C>
            <D>d1</D>         
         </C> 
        </B> 
       </A>

       <A> 
        <B> 
         <C>
            <D>d2</D>
         </C> 
        </B> 
       </A>

       <A> 
        <B> 
         <C>
            <D>d3</D>
         </C> 
        </B> 
       </A>
     </ABCD>

1 个答案:

答案 0 :(得分:1)

以下是使用Saxon 9.5 HE测试的XSLT 2.0样式表:

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

<xsl:variable name="nodes" as="node()*" select="//D"/>


<xsl:output indent="yes"/>

<xsl:template match="/*">
  <xsl:copy>
    <xsl:apply-templates select="$nodes" mode="copy"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="*" mode="copy">
  <xsl:variable name="ancestors" select="ancestor::*[position() ne last()]"/>
  <xsl:variable name="anchor" select="."/>
  <xsl:apply-templates select="$ancestors[1]">
    <xsl:with-param name="ancestors" select="$ancestors"/>
    <xsl:with-param name="anchor" select="$anchor"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="*">
  <xsl:param name="ancestors"/>
  <xsl:param name="anchor"/>
  <xsl:choose>
    <xsl:when test=". is $anchor">
      <xsl:copy-of select="."/>
    </xsl:when>
    <xsl:when test=". intersect $ancestors">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="($ancestors[2], $anchor)[1]">
          <xsl:with-param name="ancestors" select="$ancestors[position() gt 1]"/>
          <xsl:with-param name="anchor" select="$anchor"/>
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:when>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

它适用于任意数量的D元素,但您需要决定操作哪些元素,因此我在代码中定义了一个变量。但是如果需要,您还可以定义一个参数来获取元素名称:

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

<xsl:param name="name" select="'D'"/>

<xsl:variable name="nodes" as="node()*" select="//*[local-name() eq $name]"/>

<xsl:output indent="yes"/>

<xsl:template match="/*">
  <xsl:copy>
    <xsl:apply-templates select="$nodes" mode="copy"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="*" mode="copy">
  <xsl:variable name="ancestors" select="ancestor::*[position() ne last()]"/>
  <xsl:variable name="anchor" select="."/>
  <xsl:apply-templates select="$ancestors[1]">
    <xsl:with-param name="ancestors" select="$ancestors"/>
    <xsl:with-param name="anchor" select="$anchor"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="*">
  <xsl:param name="ancestors"/>
  <xsl:param name="anchor"/>
  <xsl:choose>
    <xsl:when test=". is $anchor">
      <xsl:copy-of select="."/>
    </xsl:when>
    <xsl:when test=". intersect $ancestors">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="($ancestors[2], $anchor)[1]">
          <xsl:with-param name="ancestors" select="$ancestors[position() gt 1]"/>
          <xsl:with-param name="anchor" select="$anchor"/>
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:when>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

如果您只想拍摄多次出现的元素,可以使用

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

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

<xsl:variable name="nodes" as="node()*" select="//*[key('name', node-name(.))[2]]"/>

<xsl:output indent="yes"/>

<xsl:template match="/*">
  <xsl:copy>
    <xsl:apply-templates select="$nodes" mode="copy"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="*" mode="copy">
  <xsl:variable name="ancestors" select="ancestor::*[position() ne last()]"/>
  <xsl:variable name="anchor" select="."/>
  <xsl:apply-templates select="$ancestors[1]">
    <xsl:with-param name="ancestors" select="$ancestors"/>
    <xsl:with-param name="anchor" select="$anchor"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="*">
  <xsl:param name="ancestors"/>
  <xsl:param name="anchor"/>
  <xsl:choose>
    <xsl:when test=". is $anchor">
      <xsl:copy-of select="."/>
    </xsl:when>
    <xsl:when test=". intersect $ancestors">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="($ancestors[2], $anchor)[1]">
          <xsl:with-param name="ancestors" select="$ancestors[position() gt 1]"/>
          <xsl:with-param name="anchor" select="$anchor"/>
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:when>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>