我是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>
我试着为每个小组读一读。但我不能使它工作......它是否必须是四个循环或什么,因为有四个属性?请帮帮我......
答案 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, '|')">