返回节点的所有父节点

时间:2011-04-03 22:02:20

标签: xml xslt

我有一个像XML结构的文件系统,现在我想得到一个“文件路径”。我尝试了以下XSLT,但它不起作用。我只得到这些错误:

  

警告:   XSLTProcessor中:: transformToXml():   模板:in   C:\ Users \用户卢德格尔\文件\ XAMPP \ htdocs中\ CloudAmp \ devel的\ PHP \ localAudioFileLocationScanner.php   在第60行

     

警告:   XSLTProcessor :: transformToXml():#0   名称//文件   C:\ Users \用户卢德格尔\文件\ XAMPP \ htdocs中\ CloudAmp \ devel的\ PHP \ localAudioFileLocationScanner.php   在第60行

     

警告:   XSLTProcessor :: transformToXml():#1   名称//文件   第60行的C:\ Users \ Ludger \ Documents \ XAMPP \ htdocs \ CloudAmp \ devel \ php \ localAudioFileLocationScanner.php

     

[...]

     

警告:XSLTProcessor :: transformToXml():   xsltApplyXSLTTemplate:潜力   无限模板递归   检测。您可以调整xsltMaxDepth   (--maxdepth)为了提高   嵌套模板的最大数量   调用和变量/参数(目前   设为3000)。在   C:\ Users \用户卢德格尔\ DocumentsXA   MPP \ htdocs中\ CloudAmp \ devel的\ PHP \ localAudioFileLocationScanner.php   在第60行

XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/dir">
        <xsl:apply-templates select="@name" />
        <xsl:apply-templates select="parent::dir" />
    </xsl:template>

    <xsl:template match="//file">
        <xsl:apply-templates select="@name" />
        <xsl:apply-templates select="parent::dir" />
    </xsl:template>
</xsl:stylesheet>

源XML:

<root>
  <path val="C:/Users/">
    <file name="a.txt"/>
    <dir name="aaa">
      <file name="b.txt"/>
      <file name="c.txt"/>
    </dir>
    <dir name="bbb">
      <dir name="ccc">
        <file name="d.txt"/>
      </dir>
    </dir>
  </path>
</root>

我无法让它发挥作用。如果你可以帮助我,那就太棒了。

2 个答案:

答案 0 :(得分:1)

正在发生的事情是,您匹配任何file元素,然后将模板应用于其父dir,后者与元素的默认模板匹配,后者将模板应用于其所有子元素,导致另一个匹配file并开始无限递归。

(请注意,dir元素的模板永远不会匹配任何内容,因为它只查找作为根节点子节点的dir元素,但是没有。{ / em>的

以下样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="dir" mode="path">
        <xsl:value-of select="@name" />
        <xsl:text>/</xsl:text>
    </xsl:template>
    <xsl:template match="file">
        <xsl:apply-templates select="ancestor::dir" mode="path"/>
        <xsl:value-of select="@name" />
    </xsl:template>
</xsl:stylesheet>

产生以下输出:

a.txt
aaa/b.txt
aaa/c.txt
bbb/ccc/d.txt

编辑:我认为,当可以避免回溯时,推进文档通常会更好。以下样式表生成与上面相同的输出,但更高效和更优雅:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="dir">
        <xsl:param name="prev" select="''" />
        <xsl:apply-templates>
            <xsl:with-param name="prev" select="concat($prev, @name, '/')" />
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="file">
        <xsl:param name="prev" select="''" />
        <xsl:value-of select="concat($prev, @name)" />
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:0)

此转化:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="file">
  <xsl:apply-templates mode="buildPath"
   select="ancestor::*[not(self::root or self::path)]"/>
  <xsl:value-of select="concat(@name, '&#xA;')"/>
 </xsl:template>

 <xsl:template match="*" mode="buildPath">
  <xsl:value-of select="concat(@name,'/')"/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<root>
    <path val="C:/Users/">
        <file name="a.txt"/>
        <dir name="aaa">
            <file name="b.txt"/>
            <file name="c.txt"/>
        </dir>
        <dir name="bbb">
            <dir name="ccc">
                <file name="d.txt"/>
            </dir>
        </dir>
    </path>
</root>

会产生想要的正确结果:

a.txt
aaa/b.txt
aaa/c.txt
bbb/ccc/d.txt