代码之家  ›  专栏  ›  技术社区  ›  developer

使用xpath和xslt选择所有匹配的节点(不需要额外的模板或每个模板)

  •  3
  • developer  · 技术社区  · 14 年前

    我有一个我似乎无法解决的问题。

    是否可以使用xpath和xslt选择所有节点,而不使用其他模板或每个模板?

    <aaa id="11">
        <aaa id="21"></aaa>
        <bbb id="22">
            <aaa id="31"></aaa>
            <bbb id="32"></bbb>
            <ccc id="33"></ccc>
            <ddd id="34"></ddd>
            <ddd id="35"></ddd>
            <ddd id="36"></ddd>
        </bbb>
        <ccc id="23"></ccc>
        <ccc id="24"></ccc>
    </aaa>
    

    用户可以通过表单键入xpath表达式,例如:

    //aaa/bbb/ddd/@id
    

    <ddd id="34"></ddd>
    <ddd id="35"></ddd>
    <ddd id="36"></ddd>
    

    输出:

    34 35 36
    

    我能做到这一点的唯一方法是使用额外的模板,并针对每个模板:

    对于每种方式:

    <xsl:template match="/">
        <html>
            <body>
                <xsl:for-each select="//aaa/bbb/ddd">
                    <tr>
                        <td>
                            <xsl:value-of select="@id" />
                        </td>
                    </tr>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
    

        <xsl:template match="/">
        <html>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    
    <xsl:template match="//aaa/bbb/ddd">
        <xsl:value-of select="@id"/>
    </xsl:template>
    

    这些示例中的每一个都需要额外的工作来将@id与原始表达式分离。我想按原样使用用户输入的表达式,并将其插入某个地方。

    我尝试了以下方法,我认为可以选择all,但它只返回第一个实例:

    <xsl:template match="/">
        <html>
            <body>
                <xsl:value-of select="//aaa/bbb/ddd/@id"/>
            </body>
        </html>
    </xsl:template>
    

    有没有解决我的问题的方法(例如,直接插入用户输入的表达式的方法?)

    编辑:注意-我需要一个解决方案,可以处理用户给定的任何xpath表达式。。不管有多复杂。

    谢谢!:)

    4 回复  |  直到 14 年前
        1
  •  2
  •   user357812 user357812    14 年前

    使用此样式表:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:param name="node-set" select="/aaa/bbb//ddd/@id"/>
        <xsl:template match="/">
            <html>
                <body>
                    <table>
                        <tr>
                            <th>Type</th>
                            <th>Name</th>
                            <th>Value</th>
                        </tr>
                        <xsl:apply-templates select="$node-set" mode="result"/>
                    </table>
                </body>
            </html>
        </xsl:template>
        <xsl:template match="@*|node()" mode="result">
            <tr>
                <td>
                    <xsl:choose>
                        <xsl:when test="self::*">Element</xsl:when>
                        <xsl:when test="self::text()">Text</xsl:when>
                        <xsl:when test="self::comment()">Comment</xsl:when>
                        <xsl:when test="self::processing-instruction()">PI</xsl:when>
                        <xsl:when test="count(.|/)=1">Root</xsl:when>
                        <xsl:when test="count(.|../@*)=count(../@*)">Attribute</xsl:when>
                        <xsl:when test="count(.|../namespace::*)=count(../namespace::*)">Namespace</xsl:when>
                    </xsl:choose>
                </td>
                <td>
                    <xsl:value-of select="name()"/>
                </td>
                <th>
                    <xsl:value-of select="."/>
                </th>
            </tr>
        </xsl:template>
    </xsl:stylesheet>
    

    结果:

    <html>
        <body>
            <table>
                <tr>
                    <th>Type</th>
                    <th>Name</th>
                    <th>Value</th>
                </tr>
                <tr>
                    <td>Attribute</td>
                    <td>id</td>
                    <th>34</th>
                </tr>
                <tr>
                    <td>Attribute</td>
                    <td>id</td>
                    <th>35</th>
                </tr>
                <tr>
                    <td>Attribute</td>
                    <td>id</td>
                    <th>36</th>
                </tr>
            </table>
        </body>
    </html>
    

    注意 :如果$node set不是节点集,则会出错。

    编辑 :添加了完整的节点类型测试,以证明此样式表适用于任何对节点集求值的XPath表达式。

    编辑2 :已添加 template/@mode 为了不错过根。

        2
  •  2
  •   Dimitre Novatchev    14 年前

    在XSLT1.0中,这可能是生成所需结果的最简单方法,而无需“从原始表达式分离@id的额外工作”:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
    
     <xsl:template match="node()|@*">
       <xsl:apply-templates select="node()|@*"/>
     </xsl:template>
    
     <xsl:template match="aaa/bbb/ddd/@id">
       <xsl:value-of select="concat(., ' ')"/>
     </xsl:template>
    </xsl:stylesheet>
    

    下面是XPath2.0的一行代码

    //aaa/bbb/ddd/@id/string(.)
    

    :

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
    
     <xsl:template match="/">
       <xsl:sequence select="//aaa/bbb/ddd/@id/string(.)"/>
     </xsl:template>
    </xsl:stylesheet>
    
        3
  •  0
  •   Drew Wills    14 年前

    当你使用 <xsl:copy-of> <xsl:value-of> ?

        4
  •  0
  •   nearlymonolith    14 年前

    就我的XSL知识/经验而言, @id 是非常特定于上下文的,这意味着要访问这些信息,您必须首先获得适当的上下文,正如您在上面通过 select="foo" template match="foo" . 我以前在自己的工作中遇到过这个问题,这些是我能找到的唯一解决办法。