XSLT 2.0:在不使用foreach的情况下转换包含所有祖先的元素

时间:2013-06-04 21:07:55

标签: xml xslt xpath xslt-2.0 xpath-2.0

我目前正在尝试将XML文件转换为多个输出XML文件,方法是获取它的某些元素并遍历所选元素的祖先。

例如:

源XML:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <level_a> 
    <level_b> 
      <level_c> 
        <level_d> 
          <level_e/> 
        </level_d> 
      </level_c> 
    </level_b> 
    <level_b> 
      <level_c> 
        <level_d> 
          <level_e/> 
        </level_d> 
      </level_c> 
    </level_b> 
    <level_b> 
      <level_c> 
        <level_d> 
          <level_e/> 
          <level_e/> 
          <level_e/> 
        </level_d> 
      </level_c> 
    </level_b> 
    <level_b> 
      <level_c> 
        <level_d> 
          <level_d> 
            <level_e/> 
          </level_d> 
        </level_d> 
      </level_c> 
    </level_b>
  </level_a>
</root>

输出XML文件:

1:

 <output>
        <output level="b"> 
          <output level="c"> 
            <output level="d"> 
              <output level="e"/> 
            </output> 
          </output> 
        </output> 
 </output>

2:

 <output>
        <output level="b"> 
          <output level="c"> 
            <output level="d"> 
              <output level="e"/> 
            </output> 
          </output> 
        </output> 
 </output>

3:

 <output>
        <output level="b"> 
          <output level="c"> 
            <output level="d"> 
              <output level="e"/>
              <output level="e"/> 
              <output level="e"/>  
            </output> 
          </output> 
        </output> 
 </output>

4:

 <output>
      <output level="b"> 
        <output level="c"> 
          <output level="d"> 
            <output level="d"> 
              <output level="e"/> 
            </output> 
          </output> 
        </output> 
      </output>
 </output>

我知道我可以在使用以下XPath生成序列的过程中做一些事情:

(// level_d [否(level_d)])[最后一个()] /祖先:: * [自:: level_c |自:: level_b]

然后使用foreach迭代它,我将按文档顺序获取结果。

但我真正感兴趣的是如何在不使用foreach的情况下实现同样的目标,我能想到的任何解决方案都会使所有元素都反转...

非常感谢任何提示

最诚挚的问候 明经

2 个答案:

答案 0 :(得分:3)

不确定为什么你会自下而上而不是自上而下。我会匹配/*/*并在那里创建结果文档。

示例...

XML输入

<root>
    <level_a> 
        <level_b> 
            <level_c> 
                <level_d> 
                    <level_e/> 
                </level_d> 
            </level_c> 
        </level_b> 
    </level_a>
    <level_b> 
        <level_c> 
            <level_d> 
                <level_d> 
                    <level_e/> 
                </level_d> 
            </level_d> 
        </level_c> 
    </level_b>
</root>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" encoding="UTF-8"/>
    <xsl:strip-space elements="*"/>

    <xsl:template name="output">
        <output level="{substring-after(name(),'level_')}">
            <xsl:apply-templates/>
        </output>       
    </xsl:template>

    <xsl:template match="/*/*" priority="1">
        <xsl:result-document href="{generate-id()}.xml">
            <output>
                <xsl:call-template name="output"/>              
            </output>
        </xsl:result-document>
    </xsl:template>

    <xsl:template match="*[starts-with(name(),'level_')]">
        <xsl:call-template name="output"/>
    </xsl:template>

</xsl:stylesheet>

文件1 (由于generate-id()

,名称会有所不同
<output>
   <output level="a">
      <output level="b">
         <output level="c">
            <output level="d">
               <output level="e"/>
            </output>
         </output>
      </output>
   </output>
</output>

文件2 (由于generate-id()

,名称会有所不同
<output>
   <output level="b">
      <output level="c">
         <output level="d">
            <output level="d">
               <output level="e"/>
            </output>
         </output>
      </output>
   </output>
</output>

答案 1 :(得分:0)

作为变量解决方案,如果level_a或level_d发生变化,您可以在此处调整值:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="//level_d[not(ancestor::level_d)]">
            <xsl:result-document href="{concat('file_', count(preceding::*[self::level_d])+1,'.xml')}">
                <output>
                    <xsl:apply-templates select="ancestor-or-self::node()[parent::level_a]" mode="output"></xsl:apply-templates>
                </output>
            </xsl:result-document>
    </xsl:template>

    <xsl:template match="*" mode="output">
        <output level="{substring-after(local-name(),'level_')}">
            <xsl:apply-templates mode="output"/>
        </output>
    </xsl:template>
</xsl:stylesheet>

它与预期的结果相同。