如何在循环中动态定位源xml文件中的元素

时间:2018-07-02 11:35:16

标签: xslt xpath xslt-2.0

如果我们有以下xml输入:

<root xmlns:ns="http://www.blabla">
  <ns:element1 attribute="attr1">10</ns:element1>
  <ns:element1 attribute="attr2">20</ns:element1>

  <ns:element2 attribute="attr1">30</ns:element1>
  <ns:element2 attribute="attr2">40</ns:element1>
</root>

如何在xslt中的for-each中定位每个元素?

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="root">
        <html>
            <body>
                <h2>My Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th style="text-align:left">Column 1</th>
                        <th style="text-align:left">Column 2</th>
                    </tr>
                    <xsl:for-each select="1 to 10">
                        <xsl:variable name="name" select="concat('element', .)"/>
                        <tr>
                        <td>
                            <xsl:value-of select="???what should be here???[lower-case(@attribute)='attr0']"/>
                        </td>
                        <td>
                            <xsl:value-of select="???same question???[lower-case(@attribute)='attr1']"/>
                        </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>

请注意,我想遵循此过程(如果可能的话),因为输入是非常动态的,因此我们并不总是获得每一行中的所有元素。 我感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

您想要的表情是这个...

<xsl:value-of select="*[local-name() = $name][lower-case(@attribute)='attr1']"/>

...否则,由于代码是在原子值的Required item type of context item for the child axis is node(); supplied expression (.) has item type xs:integer上下文中执行的,因此会失败,并沿xsl:for-each的行出现错误。要解决此问题,您需要在xsl:for-each之前的变量中保存对子元素的引用。

尝试使用此XSLT

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="root">
        <html>
            <body>
                <h2>My Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th style="text-align:left">Title</th>
                    </tr>
                    <xsl:variable name="children" select="*" />
                    <xsl:for-each select="1 to 10">
                        <xsl:variable name="name" select="concat('element', .)"/>
                        <tr>
                        <td>
                            <xsl:value-of select="$children[local-name() = $name][lower-case(@attribute)='attr1']"/>
                        </td>
                        <td>
                            <xsl:value-of select="$children[local-name() = $name][lower-case(@attribute)='attr2']"/>
                        </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

或稍好一点,以减少代码重复...

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="root">
        <html>
            <body>
                <h2>My Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th style="text-align:left">Title</th>
                    </tr>
                    <xsl:variable name="children" select="*" />
                    <xsl:for-each select="1 to 10">
                        <xsl:variable name="name" select="concat('element', .)"/>
                        <xsl:variable name="element" select="$children[local-name() = $name]"/>
                        <tr>
                        <td>
                            <xsl:value-of select="$element[lower-case(@attribute)='attr1']"/>
                        </td>
                        <td>
                            <xsl:value-of select="$element[lower-case(@attribute)='attr2']"/>
                        </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

注意,如果您可以控制输入XML,我真的会考虑更改它。使用元素名称对元素编号会使操作更加困难。理想情况下,您应该这样做...

<ns:element num="1" attribute="attr1">10</ns:element>

答案 1 :(得分:1)

如果您没有控制权,请尝试对元素进行计数并按如下所示按计数运行循环:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:ns="http://www.blabla">
    <xsl:template match="root">
        <html>
            <body>
                <h2>My Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th style="text-align:left">Column 1</th>
                        <th style="text-align:left">Column 2</th>
                    </tr>
                    <xsl:variable name="all-element" select="count(//*:element)"/>
                    <xsl:for-each select="*[concat('ns:element', (1 to $all-element))]">
                        <xsl:message select="."/>
                        <tr>
                            <td>
                                <xsl:value-of select="@attribute"/>
                            </td>
                            <td>
                                <xsl:value-of select="."/>
                            </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>