XSLT分组兄弟姐妹

时间:2009-06-03 08:56:12

标签: xml xslt

我正在尝试将兄弟数据分组到XML文件中。

鉴于:

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <competition>
        <timeline>10:00</timeline>
        <fixture>team a v team b</fixture>
        <fixture>team c v team d</fixture>
        <timeline>12:00</timeline>
        <fixture>team e v team f</fixture>
        <timeline>16:00</timeline>
        <fixture>team g v team h</fixture>
        <fixture>team i v team j</fixture>
        <fixture>team k v team l</fixture>
    </competition>
</data>

我正在尝试制作:

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <competition>
        <timeline time="10:00">
            <fixture>team a v team b</fixture>
            <fixture>team c v team d</fixture>
        </timeline>
        <timeline time="12:00">
            <fixture>team e v team f</fixture>
        </timeline>
        <timeline time="16:00">
            <fixture>team g v team h</fixture>
            <fixture>team i v team j</fixture>
            <fixture>team k v team l</fixture>
        </timeline>
    </competition>
</data>

我正在使用以下XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="competition" >

        <xsl:apply-templates select="timeline" />

    </xsl:template>

    <xsl:template match="timeline">
        <timeline>
            <xsl:attribute name="time" >
                <xsl:value-of select="." />
            </xsl:attribute>

            <xsl:apply-templates select="following-sibling::*" mode="copy"/>

        </timeline>
    </xsl:template>

    <xsl:template match="fixture" mode="copy">
        <fixture>
            <xsl:value-of select="." />
        </fixture>
    </xsl:template>

    <xsl:template match="timeline" mode="copy">
        <xsl:apply-templates select="following-sibling::*" mode="null" />
    </xsl:template>

    <xsl:template match="*" mode="null">
    </xsl:template>
</xsl:stylesheet>

我的问题是,当它到达下一个时间线时,它不会停止处理夹具节点

6 个答案:

答案 0 :(得分:10)

当以下情况属实时(我认为是这样),这很容易做到:

  • <timeline>内的所有<competition>都是唯一的
  • 仅在给定<fixture>之后的<timeline>属于它
  • 没有<fixture>之前没有<timeline>元素

此XSLT 1.0解决方案:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:key name="kFixture" 
           match="fixture" 
           use="generate-id(preceding-sibling::timeline[1])" 
  />

  <xsl:template match="data">
    <xsl:copy>
      <xsl:apply-templates select="competition" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="competition">
    <xsl:copy>
      <xsl:apply-templates select="timeline" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="timeline">
    <xsl:copy>
      <xsl:attribute name="time">
        <xsl:value-of select="." />
      </xsl:attribute>
      <xsl:copy-of select="key('kFixture', generate-id())" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

产生

<data>
  <competition>
    <timeline time="10:00">
      <fixture>team a v team b</fixture>
      <fixture>team c v team d</fixture>
    </timeline>
    <timeline time="12:00">
      <fixture>team e v team f</fixture>
    </timeline>
    <timeline time="16:00">
      <fixture>team g v team h</fixture>
      <fixture>team i v team j</fixture>
      <fixture>team k v team l</fixture>
    </timeline>
    </competition>
</data>

请注意,使用<xsl:key>来匹配给定<fixture>所属的<timeline>(“前面有”)。

稍微短但不太明显的解决方案是修改后的身份变换:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:key name="kFixture" 
           match="fixture" 
           use="generate-id(preceding-sibling::timeline[1])" 
  />

  <xsl:template match="* | @*">
    <xsl:copy>
      <xsl:apply-templates select="*[not(self::fixture)] | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="timeline">
    <xsl:copy>
      <xsl:attribute name="time">
        <xsl:value-of select="." />
      </xsl:attribute>
      <xsl:copy-of select="key('kFixture', generate-id())" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:3)

这是我的尝试。我所做的一个简化事情的假设是具有特定文本值的时间轴元素已经是唯一的。

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="UTF-8" />

  <xsl:template match="/data">
    <data>
      <xsl:apply-templates select="competition" />
    </data>
  </xsl:template>

  <xsl:template match="competition">
    <xsl:for-each select="timeline">
      <timeline time="{text()}">
        <xsl:copy-of
          select="./following-sibling::fixture[count(preceding-sibling::timeline[1] | current()) = 1]" />
      </timeline>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

根据Tomalak的建议,编辑上面的内容是使用current()而不是变量。

答案 2 :(得分:1)

G Andrieu的解决方案不起作用,因为不幸的是,没有像'next-sibling'这样的轴。

替代解决方案如下:

<xsl:template match="timeline">
<timeline>
  <xsl:attribute name="time" >
    <xsl:value-of select="." />
  </xsl:attribute>

  <xsl:apply-templates select="following-sibling::*[local-name()='fixture' and position()=1]" />

</timeline>
</xsl:template>

<xsl:template match="fixture">
  <fixture>
      <xsl:value-of select="." />
  </fixture>
  <xsl:apply-templates select="following-sibling::*[local-name()='fixture' and position()=1]" />
</xsl:template>

答案 3 :(得分:1)

即使相同的时间轴分散在多个位置,以下xslt也能正常工作。对于例如在foll xml中,时间轴10:00有2个条目

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <competition>
        <timeline>10:00</timeline>
        <fixture>team a v team b</fixture>
        <fixture>team c v team d</fixture>
        <timeline>12:00</timeline>
        <fixture>team e v team f</fixture>
        <timeline>16:00</timeline>
        <fixture>team g v team h</fixture>
        <fixture>team i v team j</fixture>
        <fixture>team k v team l</fixture>
        <timeline>10:00</timeline>
        <fixture>team a v team b new</fixture>
        <fixture>team c v team d new</fixture>
    </competition>
</data>

<强> XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:key name="TimelineDistint" match="timeline" use="."/>

    <xsl:template match="data">
        <xsl:apply-templates select="competition"/>
    </xsl:template>

    <xsl:template match="competition">
        <data>
            <competition>
                <xsl:for-each select="timeline[generate-id() = generate-id(key('TimelineDistint', .)[1])]">
                    <timeline>
                        <xsl:variable name="varTimeline" select="."/>
                        <xsl:attribute name="time"><xsl:value-of select="normalize-space(.)"/></xsl:attribute>
                        <xsl:for-each select="../fixture[preceding::timeline[1] = $varTimeline]">
                            <fixture>
                                <xsl:value-of select="normalize-space(.)"/>
                            </fixture>
                        </xsl:for-each>
                    </timeline>
                </xsl:for-each>
            </competition>
        </data>
    </xsl:template>
</xsl:stylesheet>

<强>输出

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <competition>
        <timeline time="10:00">
            <fixture>team a v team b</fixture>
            <fixture>team c v team d</fixture>
            <fixture>team a v team b new</fixture>
            <fixture>team c v team d new</fixture>
        </timeline>
        <timeline time="12:00">
            <fixture>team e v team f</fixture>
        </timeline>
        <timeline time="16:00">
            <fixture>team g v team h</fixture>
            <fixture>team i v team j</fixture>
            <fixture>team k v team l</fixture>
        </timeline>
    </competition>
</data>

答案 4 :(得分:0)

尝试类似的东西:

<xsl:template match="timeline">
    <timeline>
            <xsl:attribute name="time" >
                    <xsl:value-of select="." />
            </xsl:attribute>

            <xsl:apply-templates select="following-sibling::*[name()=fixture][1]" />

    </timeline>
</xsl:template>

<xsl:template match="fixture">
    <fixture>
            <xsl:value-of select="." />
    </fixture>
    <xsl:apply-templates select="following-sibling::*[name()=fixture][1]" />
</xsl:template>

答案 5 :(得分:0)

在g andrieu的帮助下,我不得不让它只获得下一个项目而不是下面的列表:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="competition" >

        <xsl:apply-templates select="timeline" />

    </xsl:template>

    <xsl:template match="timeline">
        <timeline>
            <xsl:attribute name="time" >
                <xsl:value-of select="." />
            </xsl:attribute>

            <xsl:apply-templates select="following-sibling::*[1]" mode="copy"/>

        </timeline>
    </xsl:template>

    <xsl:template match="fixture" mode="copy">
        <fixture>
            <xsl:value-of select="." />
        </fixture>
        <xsl:apply-templates select="following-sibling::*[1]" mode="copy"/>
    </xsl:template>

    <xsl:template match="timeline" mode="copy" />

</xsl:stylesheet>