将XML节点组合在一起,并在一行中显示两个元素

时间:2014-01-10 04:27:57

标签: xml xslt xslt-1.0 modulo

我想根据一个值将特定的XML节点组合在一起,并在一行中最多显示两个元素。

我已经尝试了很多,但找不到合理的工作原理。

首先,这是一个示例XML:

<apples>
    <gala>
        <pattern></pattern>
        <mutated>self</mutated>
        <marketed>Gala</marketed>
    </gala>
    <gala>
        <pattern>stripe</pattern>
        <mutated>Gala</mutated>
        <marketed>Royal Gala</marketed>
    </gala>
    <gala>
        <pattern>stripe</pattern>
        <mutated>Tenroy</mutated>
        <marketed>Obrogala</marketed>
    </gala>
    <gala>
        <pattern>stripe</pattern>
        <mutated>Tenroy</mutated>
        <marketed>Waliser Gala</marketed>
    </gala>
    <gala>
        <pattern>stripe</pattern>
        <mutated>Tenroy</mutated>
        <marketed>Caitlin</marketed>
    </gala>
    <gala>
        <pattern>stripe</pattern>
        <mutated>Imperial</mutated>
        <marketed>Banning Gala</marketed>
    </gala>
    <gala>
        <pattern>stripe</pattern>
        <mutated>Tenroy</mutated>
        <marketed>Smith gala</marketed>
    </gala>         
</apples>

我想通过突变对苹果进行分组,但前提是它们有一个模式。输出应如下:

Mutated from: Gala
Marketed as Royal Gala

Mutated from Tenroy
Marketed as Obrogala :: Marketed as Waliser Gala
Marketed as Caitlin :: Marketed as Smith Gala

Mutated from Imperial
Marketed as Banning Gala

此外,更简单的解决方案可能不是将“Marketed as Smith Gala”添加到“Tenroy”组中,而是在“Imperial”组下面创建一个新组“Tenroy”。

这是我到目前为止所尝试的内容:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="apples">
    <html>
        <body>
            <h2>Gala Apples</h2>

            <xsl:for-each select="gala[normalize-space(pattern)][position() mod 2=1]">

                <!-- Add a headline for each mutation -->
                <xsl:if test="preceding-sibling::gala[normalize-space(pattern)][1]/mutated != mutated or position() = 1">
                    <table border="1">
                        <tr bgcolor="#9acd32">
                            <th>
                                Mutated from: <xsl:value-of select="mutated" />
                            </th>
                        </tr>           
                    </table>
                </xsl:if>

                <!-- Build a 2 column Layout for each Gala Apple -->
                <table border="1">
                    <tr>
                        <td width="50%">
                            Marketd as: <xsl:value-of select="marketed" />
                        </td>
                        <td width="50%">
                            <xsl:for-each select="following-sibling::gala[normalize-space(pattern)][1]">
                                Marketd as: <xsl:value-of select="marketed" />
                            </xsl:for-each>
                        </td>                           
                    </tr>

                </table>

          </xsl:for-each>
        </body>
    </html>
</xsl:template>
</xsl:stylesheet>

我的代码问题是,我在检查突变时只通过第一个节点(mod 2 = 1)进行迭代。如果每个组中都有偶数个苹果,这将正常工作。如果没有,它将最终陷入混乱。

我还试图计算先前兄弟突变的数量,但它也没有按预期工作。

非常感谢帮助!

1 个答案:

答案 0 :(得分:1)

如果您的处理器支持它,您可以使用EXSLT set:distinct()函数通过变异对记录进行分组,例如:

<xsl:variable name="groups" select="set:distinct(/apples/gala/mutated)[.!='self']" />

而不是使用(更复杂的)Muenchian方法。然后,您可以使用来获取每个组中的苹果并进行处理。恕我直言,该组应作为列表输出,并由CSS处理两列显示 - 但如果您更喜欢通过表格单元格来处理它,请尝试类似:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:set="http://exslt.org/sets">

<xsl:variable name="groups" select="set:distinct(/apples/gala/mutated)[.!='self']" />
<xsl:key name="samegGroup" match="gala" use="mutated" />

<xsl:template match="/">
<html>
<body>
<h2>Gala Apples</h2>
<table border="1" >
<xsl:for-each select="$groups">
    <tr><th colspan="2"><xsl:value-of select="." /></th></tr>
    <xsl:call-template name="proc">
        <xsl:with-param name="group" select="key('samegGroup', .)"/>
    </xsl:call-template>
</xsl:for-each>
</table>          
</body>
</html>
</xsl:template>

<xsl:template name="proc">
<xsl:param name="group" />
<xsl:param name="i" select="1"/>
<xsl:choose>
    <xsl:when test="$i > count($group)"/>
    <xsl:otherwise>
        <tr>
            <td>
                <xsl:text>Marketed as: </xsl:text>
                <xsl:value-of select="$group[$i]/marketed" />
            </td>
            <td>            
                <xsl:if test="$i &lt; count($group)">
                    <xsl:text>Marketed as: </xsl:text>
                    <xsl:value-of select="$group[$i+1]/marketed" />
                </xsl:if>
            </td>
        </tr>   
        <xsl:call-template name="proc">
            <xsl:with-param name="group" select="$group"/>
            <xsl:with-param name="i" select="$i+2"/>
        </xsl:call-template>
    </xsl:otherwise>
</xsl:choose>
</xsl:template>

</xsl:stylesheet>