2011-04-03 102 views
1

我有一个类似于XML结构的文件系统,现在我想获取一个节点的“文件路径”。我尝试了以下XSLT,但它不起作用。我只得到这些错误:返回一个节点的所有父节点

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

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

警告: XSLTProcessor中:: transformToXml():#1 名//文件中 C:\用户\卢德格尔\文件\ XAMPP \ htdocs中\ CloudAmp \线60上devel的\ PHP中\ localAudioFileLocationScanner.php

[ ...]

警告:XSLTProcessor中:: transformToXml(): xsltApplyXSLTTemplate:潜在 无限递归模板是检测 。您可以调整xsltMaxDepth (--maxdepth),以便将嵌套模板的最大数量 调用和变量/参数(当前为 设置为3000)提高为 。在 C:\用户\卢德格尔\ 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> 

我无法让它工作。如果你能帮助我,这将是一件好事。

+0

好问题,+1。查看我的答案,获得比其他当前答案更短的完整解决方案(包括模板数量和非空行数量)。 :) – 2011-04-03 22:47:42

回答

1

发生了什么事是,你匹配任何file元素,然后应用模板到其父dir,这是由元素的默认模板,它适用模板所有的孩子,导致在相同的另一场比赛匹配file并开始无限递归。

(请注意,您的dir元素模板永远不匹配任何东西,因为它看起来仅dir元素是根节点,其中你有没有一个孩子。)

以下样式:

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

太好了,非常感谢! – 2011-04-03 22:56:06

+0

正确但开始的'//'运算符不需要模式或第一个'dir'规则(与任何元素的内置规则相同的行为) – 2011-04-03 23:07:02

+0

@Ajjandro - '//'是复制/粘贴的遗迹。不知道我在用'dir'模板想什么。我认为这是应该重构出来的早期解决方案的剩余部分。一如既往,感谢您的改进。 – 2011-04-04 14:03:21

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 
相关问题