使用 xpath 和 xslt 选择所有匹配的节点(没有额外的模板或 for-each) [英] select all matching nodes using xpath and xslt (without additional templates or for-each)

查看:27
本文介绍了使用 xpath 和 xslt 选择所有匹配的节点(没有额外的模板或 for-each)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个我似乎无法解决的特殊问题.

I have a particular problem that I can't seem to solve.

是否可以在不使用额外模板或 for-each 的情况下使用 xpath 和 xslt 选择所有节点?

Is it possible to select all nodes using xpath and xslt without the use of additional templates or for-each?

示例 xml:

<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 表达式,例如:

A user has the ability to type in an xpath expression through a form, such as:

//aaa/bbb/ddd/@id

用户希望从以下位置接收 ID:

The user would expect to receive the ids from:

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

输出:

34 35 36

我能够实现这一目标的唯一方法是使用额外的模板和 for-each:

The only ways I have been able to achieve this is by using additional templates and for-each:

For-each way:

For-each way:

<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 从原始表达式中分离出来.我想按原样使用用户输入的表达式,然后将其插入某处.

Each of these examples require extra work to detach the @id from the original expression. I would like to use the user inputted expression as is, and just plug it in somewhere.

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

I have tried the following, which I thought would select all, but it only returns the first instance:

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

是否有解决我的问题的方法(即按原样插入用户输入的表达式的方法?)

Is there a solution to my problem (i.e. a way to just plug in the user inputted expression as is?)

注意 - 我需要一个可以处理用户给出的任何 xpath 表达式的解决方案......无论多么复杂.

如果您需要进一步说明,请告诉我.我已尽力解释,但可能我做得不太好.在此先感谢您的耐心等待!

Let me know if you need any further clarification.. I tried my best to explain it, but maybe I didn't do that very well.. Thank you in advance for your patience!

谢谢!:)

推荐答案

使用此样式表:

<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 不是节点集会报错.

Note: It would be an error if $node-set isn't a node set.

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

Edit: Added complete node type test in order to prove that this stylesheet works with any XPath expression wich eval to a node set.

Edit 2:添加了 template/@mode 以免错过 root.

Edit 2: Added template/@mode in order to not miss root.

这篇关于使用 xpath 和 xslt 选择所有匹配的节点(没有额外的模板或 for-each)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆