XSLT发现了不同的组合

时间:2014-01-22 00:30:35

标签: xslt xslt-2.0 xslt-grouping

我是xslt的初学者。我想找到年,月,日和小时的所有独特组合。

我有以下xml文件要转换:

<Plans>
    <Plan Name="Plan_1">
        <Book Name="Book_1">
            <Time Name="AAA">
                <Property Name="Year" Value="2001"/>
                <Property Name="Month" Value="01"/>
                <Property Name="Day" Value="10"/>
                <Property Name="Hour" Value="12"/>
            </Time>
            <Time Name="BBB">
                <Property Name="Year" Value="2001"/>
                <Property Name="Month" Value="01"/>
                <Property Name="Day" Value="10"/>
                <Property Name="Hour" Value="12"/>
            </Time>
            <Time Name="CCC">
                <Property Name="Year" Value="2004"/>
                <Property Name="Month" Value="02"/>
                <Property Name="Day" Value="11"/>
                <Property Name="Hour" Value="04"/>
            </Time>
            <Time Name="DDD">
                <Property Name="Year" Value="2004"/>
                <Property Name="Month" Value="03"/>
                <Property Name="Day" Value="20"/>
                <Property Name="Hour" Value="04"/>
            </Time>
        </Book>
        <Book Name="Book_22">
            <Time Name="CCC">
                <Property Name="Year" Value="2001"/>
                <Property Name="Month" Value="01"/>
                <Property Name="Day" Value="10"/>
                <Property Name="Hour" Value="12"/>
            </Time>
            <Time Name="DDD">
                <Property Name="Year" Value="2002"/>
                <Property Name="Month" Value="03"/>
                <Property Name="Day" Value="23"/>
                <Property Name="Hour" Value="03"/>
            </Time>
            <Time Name="EEE">
                <Property Name="Year" Value="2002"/>
                <Property Name="Month" Value="03"/>
                <Property Name="Day" Value="23"/>
                <Property Name="Hour" Value="03"/>
            </Time>
            <Time Name="FFF">
                <Property Name="Year" Value="2004"/>
                <Property Name="Month" Value="02"/>
                <Property Name="Day" Value="11"/>
                <Property Name="Hour" Value="04"/>
            </Time>
        </Book>
    </Plan>
</Plans>

输入xml总共有八个组合(每本书四个)。

我只是想知道不同的组合。因此输出应该有6种组合,因为有两种相同的组合。书的名称无关紧要。我只想看看有多少种组合。并且只是标记从1到数字......它不必是任何顺序,虽然它可以按时间排序...如果标记数字太难了,那么我只需要获得不同的组合..

<Times>
    <Time Value="1">
        <Property Name="Year" Value="2001"/>
        <Property Name="Month" Value="01"/>
        <Property Name="Day" Value="10"/>
        <Property Name="Hour" Value="12"/>
    </Time>
    <Time Value="2">
        <Property Name="Year" Value="2004"/>
        <Property Name="Month" Value="02"/>
        <Property Name="Day" Value="11"/>
        <Property Name="Hour" Value="04"/>
    </Time>
    <Time Value="3">
        <Property Name="Year" Value="2004"/>
        <Property Name="Month" Value="03"/>
        <Property Name="Day" Value="20"/>
        <Property Name="Hour" Value="04"/>
    </Time>
    <Time Value="4">
        <Property Name="Year" Value="2001"/>
        <Property Name="Month" Value="01"/>
        <Property Name="Day" Value="10"/>
        <Property Name="Hour" Value="12"/>
    </Time>
    <Time Value="5">
        <Property Name="Year" Value="2002"/>
        <Property Name="Month" Value="03"/>
        <Property Name="Day" Value="23"/>
        <Property Name="Hour" Value="03"/>
    </Time>
</Times>

我试着为每个小组读一读。但我不能使它工作......它是否必须是四个循环或什么,因为有四个属性?请帮帮我......

3 个答案:

答案 0 :(得分:1)

使用

distinct-values(/Times/Time/string-join(Property/@Value, '|'))

获取不同的值。然后,如有必要,使用tokenize()将它们分成组件字段。

答案 1 :(得分:1)

以下样式表建立在@Michael Kay给出的答案之上。这只是为了说明解决方案并证明它正在发挥作用。请接受他的答案!

编号输出元素并不难,最简单的方法是在属性值模板中使用position()

<?xml version="1.0" encoding="utf-8"?>

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

   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/Plans">
      <Times>
         <xsl:for-each select="distinct-values(//Time/string-join(Property/@Value, '|'))">
            <xsl:variable name="tokens" select="tokenize(.,'\|')"/>
            <Time Value="{position()}">
               <Property Name="Year" Value="{$tokens[1]}"/>
               <Property Name="Month" Value="{$tokens[2]}"/>
               <Property Name="Day" Value="{$tokens[3]}"/>
               <Property Name="Hour" Value="{$tokens[4]}"/>
            </Time>
         </xsl:for-each>
      </Times>
   </xsl:template>

</xsl:stylesheet>

<强>输出

正如@Tim C所提到的,你可能期待4个结果元素。

<?xml version="1.0" encoding="UTF-8"?>
<Times>
   <Time Value="1">
      <Property Name="Year" Value="2001"/>
      <Property Name="Month" Value="01"/>
      <Property Name="Day" Value="10"/>
      <Property Name="Hour" Value="12"/>
   </Time>
   <Time Value="2">
      <Property Name="Year" Value="2004"/>
      <Property Name="Month" Value="02"/>
      <Property Name="Day" Value="11"/>
      <Property Name="Hour" Value="04"/>
   </Time>
   <Time Value="3">
      <Property Name="Year" Value="2004"/>
      <Property Name="Month" Value="03"/>
      <Property Name="Day" Value="20"/>
      <Property Name="Hour" Value="04"/>
   </Time>
   <Time Value="4">
      <Property Name="Year" Value="2002"/>
      <Property Name="Month" Value="03"/>
      <Property Name="Day" Value="23"/>
      <Property Name="Hour" Value="03"/>
   </Time>
</Times>

答案 2 :(得分:1)

与其他答案类似,您也可以在此处使用 xsl:for-each-group

<xsl:for-each-group select=".//Time" group-by="string-join(Property/@Value, '|')">

如果您的XSLT使用了身份模板,那么您可以通过执行此操作在该组中输出不同的时间元素

 <Time Value="{position()}">
     <xsl:apply-templates />
 </Time>

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/*">
    <Times>
      <xsl:for-each-group select=".//Time" group-by="string-join(Property/@Value, '|')">
          <Time Value="{position()}">
              <xsl:apply-templates />
          </Time>
      </xsl:for-each-group>
    </Times>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

现在,您在评论中(但不在问题中)提及有多个计划元素,但您还没有说过是否要选择不同的时间元素所有计划元素,或为每个单独的计划设置不同的元素。

假设您确实希望为每个单独的计划显示不同的时间元素,那么只需进行一些小调整即可。您只需有效匹配计划元素,并在该

中进行分组
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="Plan">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select=".//Time" group-by="string-join(Property/@Value, '|')">
          <Time Value="{position()}">
              <xsl:apply-templates />
          </Time>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

请注意,假设 Property 元素的顺序始终相同(“Year”,“Month”,“Day”,“Hour”)。如果没有,您可以通过执行以下操作来解决此问题

<xsl:for-each-group select=".//Time" group-by="concat(
     Property[@Name='Year']/@Value, '|', 
     Property[@Name='Month']/@Value, '|',
     Property[@Name='Day']/@Value, '|',
     Property[@Name='Hour']/@Value, '|')">