根据条件计算(嵌套)节点组

时间:2015-07-29 14:57:09

标签: xml xslt xml-parsing xslt-1.0

XML

<Action>
    <Step>
        <Obj>UC_A</Obj>
        <Step>
            <Obj>abc</Obj>
            <Step>
                <Obj>bcd</Obj>
            </Step>
        </Step>
    </Step>
    <Step>
        <Obj>cde</Obj>
    </Step>
    <Step>
        <Obj>UC_B</Obj>
    </Step>
    <Step>
        <Obj>def</Obj>
        <Step>
            <Obj>efg</Obj>
        </Step>
    </Step>
    <Step>
        <Obj>UC_C</Obj>
        <Step>
            <Obj>pqr</Obj>
        </Step>
        <Step>
            <Obj>xyz</Obj>
            <Step>
                <Obj>uvw</Obj>
            </Step>
        </Step>
    </Step>
</Action>

我的XSL

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" omit-xml-declaration="yes" version="5.0" doctype-system="about:legacy-compat" encoding="utf-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="group" match="Step[not(starts-with(Obj, 'UC_'))]" use="generate-id(ancestor::Step[starts-with(Obj, 'UC_')][1])"/>

    <xsl:template match="Action">
        <html>
            <head>
                <style type="text/css">
                    table { table-layout:auto; border-collapse:collapse; font-family:Arial; }
                    td { vertical-align:top; border:1px solid Silver; padding:0pt; font-size:9pt; padding-right:3px; padding-left:3px; }
                </style>
            </head>
            <body>
                <table>
                    <xsl:apply-templates select="Step[starts-with(Obj, 'UC_')]"/>  
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="Step[starts-with(Obj, 'UC_')]">
        <xsl:variable name="group" select="key('group', generate-id())"/>
        <tr>
            <td rowspan="{1 + count($group)}">
                <xsl:number count="Step[starts-with(Obj, 'UC_')]"/>
            </td>
            <td>
                <xsl:value-of select="Obj"/>
            </td>
        </tr>

        <xsl:apply-templates select="$group" />
    </xsl:template>

    <xsl:template match="Step[not(starts-with(Obj, 'UC_'))]">
        <tr>
            <td>
                <xsl:value-of select="Obj"/>
            </td>
        </tr>
    </xsl:template>

</xsl:stylesheet>

问题

预期的HTML

enter image description here

实际HTML

enter image description here

  1. 我当前的XSL并未考虑与UC_ *节点处于同一级别的节点(如cde)或处于第二级的节点。我想为一组UC_节点设置一个rowspan。

  2. 我不想使用分组,因为效率不高(我的实际xml很大)

1 个答案:

答案 0 :(得分:1)

目前您的密钥只是查看祖先节点,但Step个节点没有&#34; UC _&#34;作为祖先的价值。在这种情况下,您需要查找前面的元素,而不是祖先。

现在,您可以将密钥写为,以查找祖先不存在的前一个元素:

<xsl:key name="group" 
    match="Step[not(starts-with(Obj, 'UC_'))]" 
    use="generate-id(ancestor::Step[starts-with(Obj, 'UC_')][1] 
                   | self::*[not(ancestor::Step[starts-with(Obj, 'UC_')])]/preceding::Step[starts-with(Obj, 'UC_')][1])"/>

但这看起来并不特别好看。你可以通过为没有祖先

的单独键来略微简化一些事情
<xsl:key name="group2" 
        match="Step[not(ancestor::Step[starts-with(Obj, 'UC_')])][not(starts-with(Obj, 'UC_'))]" 
        use="generate-id(preceding::Step[starts-with(Obj, 'UC_')][1])"/>

然后,您只需更改group变量即可使用此密钥:

<xsl:variable name="group" select="key('group', generate-id())|key('group2', generate-id())"/>

作为最后的替代方案,您可能不需要一个密钥来键入&#34; UC _&#34;的后代节点。价值节点。相反,定义一个键以在同一级别上查找前面的兄弟姐妹....

<xsl:key name="group" 
        match="Step[not(starts-with(Obj, 'UC_'))]" 
        use="generate-id(preceding-sibling::Step[starts-with(Obj, 'UC_')][1])"/>

然后您的group变量定义如下:

<xsl:variable name="group" select="descendant::Step|key('group', generate-id())/descendant-or-self::Step"/>

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" omit-xml-declaration="yes" version="5.0" doctype-system="about:legacy-compat" encoding="utf-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="group" 
            match="Step[not(starts-with(Obj, 'UC_'))]" 
            use="generate-id(preceding-sibling::Step[starts-with(Obj, 'UC_')][1])"/>

    <xsl:template match="Action">
        <html>
            <body>
                <table border="1">
                    <xsl:apply-templates select="Step[starts-with(Obj, 'UC_')]"/>  
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="Step[starts-with(Obj, 'UC_')]">
        <xsl:variable name="group" select="descendant::Step|key('group', generate-id())/descendant-or-self::Step"/>
        <tr>
            <td rowspan="{1 + count($group)}">
                <xsl:number count="Step[starts-with(Obj, 'UC_')]"/>
            </td>
            <td>
                <xsl:value-of select="Obj"/>
            </td>
        </tr>

        <xsl:apply-templates select="$group" />
    </xsl:template>

    <xsl:template match="Step[not(starts-with(Obj, 'UC_'))]">
        <tr>
            <td>
                <xsl:value-of select="Obj"/>
            </td>
        </tr>
    </xsl:template>
</xsl:stylesheet>