简体   繁体   English

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

[英]Construct an xml in XSLT by repeating all other elements except one element

I am new to XSLT and tried googling to find solution but couldn't. 我是XSLT的新手,并尝试使用Google搜索来寻找解决方案,但没有找到。 I need to construct an xml in XSLT by repeating all other elements except the repetitive element. 我需要通过重复除重复元素之外的所有其他元素来在XSLT中构造xml。

Input XML: Here element D is repetitive. 输入XML:这里的元素D是重复的。 It might occur more than once. 它可能会发生多次。 Depending on the number of times it appears, my output XML should contain the entire input XML multiple times except that element D is distributed. 根据它出现的次数,我的输出XML应该多次包含整个输入XML,除了元素D是分布式的。 It would be really helpful if the answer is generic for n number of repetitions of D. 如果答案是D的n次重复的泛型,那将非常有帮助。

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

Output XML: 输出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>

Here is an XSLT 2.0 stylesheet tested with Saxon 9.5 HE: 这是经过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>

It work for any number of D elements but you somehow need to decide which elements to operate on so I defined a variable in the code. 它适用于任意数量的D元素,但您需要以某种方式决定要对哪些元素进行操作,因此我在代码中定义了一个变量。 But if needed you could also define a parameter to take the element name: 但是,如果需要,您还可以定义一个参数以采用元素名称:

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

If you simply want to take the elements that occur several times you could use 如果您只想采用多次出现的元素,则可以使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM