2009-09-30 57 views
3

我有下面的代码块获取节点的名称下的树,像这样:获取XSLT当前节点,格式为XPath查询?

section/page/subPage

但是我想能够得到它归结为以下(只是使它达):

section[@id='someId']/page/subPage[@user='UserA']/@title

我发现下面的代码从这些StackOverflow的职位之一:


<xsl:attribute name="path"> <xsl:for-each select="ancestor-or-self::*"> <xsl:if test="name() != 'root'"> <xsl:value-of select="name()"> <xsl:if test="not(position()=last())"> <xsl:text>/</xsl:text> </xsl:if> </xsl:value-of> </xsl:if> </xsl:for-each> </xsl:attribute> 

这给了我直线路径,但我想运行更多的逻辑来使它包含@id(或相关属性),也许还有一些我现在无法想到的东西。

这样做的最好方法是什么?

我检查了EXSLT函数,这可能工作,但也许你们已经解决了这个问题更好的方法。

任何想法?

我使用Ruby的引入nokogiri解析XML/XSLT是否有帮助。

非常感谢, 兰斯

回答

4

该解决方案你想要做什么:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" /> 

    <xsl:template match="/"> 
    <root> 
     <xsl:attribute name="path"> 
     <xsl:apply-templates select="(//@title)[1]" mode="make-path" /> 
     </xsl:attribute> 
    </root> 
    </xsl:template> 

    <xsl:template match="*|@*" mode="make-path"> 
    <xsl:apply-templates select="parent::*" mode="make-path" /> 
    <xsl:text>/</xsl:text> 
    <xsl:apply-templates select="." mode="make-name" /> 
    <xsl:choose> 
     <xsl:when test="self::section"> 
     <xsl:apply-templates select="@id" mode="make-predicate" /> 
     </xsl:when> 
     <xsl:when test="self::subPage"> 
     <xsl:apply-templates select="@user" mode="make-predicate" /> 
     </xsl:when> 
    </xsl:choose> 
    </xsl:template> 

    <xsl:template match="*|@*" mode="make-predicate"> 
    <xsl:text>[</xsl:text> 
    <xsl:apply-templates select="." mode="make-name" /> 
    <xsl:text> = '</xsl:text> 
    <xsl:value-of select="." /> 
    <xsl:text>']</xsl:text> 
    </xsl:template> 

    <xsl:template match="*" mode="make-name"> 
    <xsl:value-of select="name()" /> 
    </xsl:template> 

    <xsl:template match="@*" mode="make-name"> 
    <xsl:text>@</xsl:text> 
    <xsl:value-of select="name()" /> 
    </xsl:template> 

</xsl:stylesheet> 

当应用于

<section id="someId"> 
    <page> 
    <subPage user="UserA" title="test" /> 
    <subPage user="UserB" title="blah" /> 
    </page> 
    <page> 
    <subPage user="UserC" title="fooh" /> 
    </page> 
</section> 

你:

<root path="/section[@id = 'someId']/page/subPage[@user = 'UserA']/@title" /> 

<xsl:choose>是配置点(添加尽可能多的<xsl:when> S作为您喜欢):

<!-- test for element name --> 
<xsl:when test="self::section"> 
    <!-- make predicates out of selected attributes --> 
    <xsl:apply-templates select="@id" mode="make-predicate" /> 
</xsl:when> 

也可以:

<xsl:when test="self::section"> 
    <xsl:apply-templates select="@name|@category|subElement" mode="make-predicate" /> 
</xsl:when> 

,这将导致

<root path="/section[@name = 'someName'][@category = 'somecat'][subElement = 'xyz']/..." /> 

我看到的唯一问题是与包含单引号谓词值。他们会打破XPath。

+0

很好用的模式 – 2009-09-30 16:47:11

+0

铁杆男,谢谢你。 – 2009-10-01 00:26:09

1

对于每个祖先节点,你可以遍历用简单的XSL所有属性:对,每个

<xsl:for-each select="@*"> 

然后,您可以使用的属性建立起来的XPath字符串

<xsl:for-each select="ancestor-or-self::*"> 
    <xsl:if test="name() != 'root'"> 
     <xsl:value-of select="name()"/> 
     <xsl:if test="@*"> 
     <xsl:text>[</xsl:text> 
     <xsl:for-each select="@*"> 
      <xsl:text>@</xsl:text> 
      <xsl:value-of select="name()"/> 
      <xsl:text>='</xsl:text> 
      <xsl:value-of select="."/> 
      <xsl:text>'</xsl:text> 
      <xsl:if test="not(position()=last())"> 
       <xsl:text> and </xsl:text> 
      </xsl:if> 
     </xsl:for-each> 
     <xsl:text>]</xsl:text> 
     </xsl:if> 
     <xsl:if test="not(position()=last())"> 
     <xsl:text>/</xsl:text> 
     </xsl:if> 
    </xsl:if> 
</xsl:for-each>