从每个节点的XML中选择不同的孙子

时间:2014-04-04 15:03:32

标签: xslt xslt-1.0

在尝试使用muenchian分组找到解决方案花了几天之后,我迫切需要一些帮助来找出用于转换我的XML的正确xslt代码,以便它将为所有节目生成一个独特的年份列表(是最终导入Solr)。基本上我需要对节点的独特孙子进行分组,但不知何故SO上的所有现有解决方案对我都不起作用。

这是我的源XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="http://localhost/default.xsl" ?>
<DIRECTORY>
    <SHOWS>
        <SHOW>
            <TITLE>Child's play</TITLE>
            <EVENTS>
                <EVENT>
                    <YEAR>2014</YEAR>
                    <TITLE>Gala day</TITLE>
                </EVENT>
                <EVENT>
                    <YEAR>2014</YEAR>
                    <TITLE>Gala night</TITLE>
                </EVENT>
                <EVENT>
                    <YEAR>2015</YEAR>
                    <TITLE>Gala night</TITLE>
                </EVENT>
            </EVENTS>
        </SHOW>
    </SHOWS>
</DIRECTORY>

这是所需的输出:

<?xml version="1.0"?>
<add>
  <doc>
    <field name="show_title">Child's play</field>
    <field name="show_year">2014</field>
    <field name="show_year">2015</field>
  </doc>
</add>

这是我的XSLT不起作用,并基于Stack Overflow的各种答案

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>

    <xsl:key name="show_key"
             match="TITLE"
             use="TITLE"/>

    <xsl:key name="show_years_key"
             match="TITLE"
             use="concat(TITLE, ' ',
                     EVENTS/EVENT/YEAR)"/>

    <xsl:template match="/">
        <add>
            <xsl:for-each select="/DIRECTORY/SHOWS/SHOW">
                <doc>
                    <xsl:call-template name="show_info"/>
                </doc>
            </xsl:for-each>
        </add>
    </xsl:template>

    <xsl:template name="show_info">
        <field name="show_title">
            <xsl:value-of select="TITLE"/>
        </field>
        <xsl:variable
                name="show_events"
                select="key('show_key', TITLE)"/>
        <xsl:for-each
                select="$show_events[generate-id() =
                             generate-id(
                               key('show_years_key',
                                   concat(TITLE,
                                          ' ',
                                          EVENTS/EVENT/YEAR))[1])]">
            <field name="show_years">
                <xsl:value-of select="EVENTS/EVENT/YEAR"/>
            </field>
        </xsl:for-each>

    </xsl:template>
</xsl:stylesheet>

虽然我非常感谢任何帮助以获得有效的解决方案,但我也可以使用一些指示来解释为什么我的解决方案无法正常工作。因为我怀疑我的xslt组织可能会使事情变得更复杂,所以我将最小的例子留下了更复杂的一点,但整体解决方案效果很好,即使有多个不同的模板也是如此。

1 个答案:

答案 0 :(得分:0)

分组键需要匹配您尝试分组的元素(即YEAR元素)。我跟你的call-template逻辑有点麻烦,我更接近这个:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>

    <xsl:key name="show_years_key"
             match="YEAR"
             use="concat(ancestor::SHOW[1]/TITLE, ' ', .)"/>

    <xsl:template match="/">
        <add>
            <xsl:apply-templates select="/DIRECTORY/SHOWS/SHOW" />
        </add>
    </xsl:template>

    <xsl:template match="SHOW">
        <doc>
            <field name="show_title">
                <xsl:value-of select="TITLE"/>
            </field>
            <!-- current() here is the SHOW element this template applies to -->
            <xsl:for-each select="EVENTS/EVENT/YEAR[generate-id() = generate-id(
                    key('show_years_key', concat(current()/TITLE, ' ', .))[1])]">
                <field name="show_years">
                    <xsl:value-of select="." />
                </field>
            </xsl:for-each>
        </doc>
    </xsl:template>
</xsl:stylesheet>

重要的一点是,您要将YEAR元素按其TITLE的{​​{1}}分组,而不是SHOW元素SHOW元素。它们包含。