我正在使用XSLT1.0(处理器无法处理2.0)并且在尝试对xml结构的输出进行分组时遇到问题:
<排>
<排序>
<文本>一些订单文本1
< /文本>
< /排序>
< /排>
<排>
<支付>
<文本>一些付款文本1
< /文本>
< /支付>
< /排>
<排>
<排序>
<文本>一些订单文本2
< /文本>
< /排序>
< /排>
<排>
<接触>
<文本>一些联系方式1
< /文本>
< /接触>
< /排>
<排>
<接触>
<文本>一些联系方式2
< /文本>
< /接触>
< /排>
今天我们选择所有行并为每个行调用apply模板(每个类型都有自己的模板写出它的主体),这样就创建了一个输出:
订单:一些订单text1
订单:一些订单text2
付款方式:一些付款文本1
联系方式:部分联系方式1
联系方式:部分联系方式2
但我想要的是(在XSLT 1.0中)将输出分组以便:
顺序
付款
联系
显然,此处涉及的订单,付款和联系等许多其他元素类型,因此选择显式元素名称不是解决方案。
修改
Ty,一些很好的答案,如果我有一个结构说明,Muenchian分组解决方案将如何改变<customers>
<person>
<row>....</row> (row is same as above)
<row>....</row>
</person>
<person>
<row>....</row>
<row>....</row>
<row>....</row>
</person>
然后是关键:
<xsl:key name="type" match="row/*" use="local-name()"/>
将选择所有人的所有行,这不是我想要的。感谢您的回复。
答案 0 :(得分:4)
在XSLT 1.0中执行此操作需要使用Muenchian grouping,但在XSLT 2.0中使用xsl:for-each-group
更容易(在我看来)。
以下XSLT 1.0样式表将按您的要求执行,关键是使用一个键(doh!),它允许您对节点本地名称进行分组。
<强>输入:强>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<row>
<order>
<text>some order text 1</text>
</order>
</row>
<row>
<payment>
<text>some payment text 1</text>
</payment>
</row>
<row>
<order>
<text>some order text 2</text>
</order>
</row>
<row>
<contact>
<text>some contact details 1</text>
</contact>
</row>
<row>
<contact>
<text>some contact details 2</text>
</contact>
</row>
</root>
<强> XSLT:强>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:key name="type" match="row/*" use="local-name()"/>
<xsl:template match="root">
<xsl:for-each select="row/*[
generate-id() = generate-id(key('type', local-name())[1])]">
<xsl:value-of select="local-name()"/>
<xsl:text>
</xsl:text>
<xsl:for-each select="key('type', local-name())">
<xsl:value-of select="concat(' ', position(), '. ')"/>
<xsl:apply-templates select="text"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<强>输出:强>
order
1. some order text 1
2. some order text 2
payment
1. some payment text 1
contact
1. some contact details 1
2. some contact details 2
答案 1 :(得分:1)
尝试:
<xsl:template match="(parent element-whatever contains the 'row' elements)">
<xsl:apply-templates>
<xsl:sort select="name(*)" />
</xsl:apply-templates>
</xsl:template>
这会按第一个子项的名称对行元素进行排序。
此模板添加标题:
<xsl:template match="row">
<xsl:copy>
<xsl:if test="not(preceding-sibling::*[name(*) = name(current()/*)])">
<!-- Output header here -->
<xsl:value-of select="name(*)" />
</xsl:if>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
测试基本上是说'如果之前没有同名的兄弟姐妹那就输出这个'。
答案 2 :(得分:1)
以@Flynn的回答为基础......
如果您有父模板(未在示例中显示):
<xsl:template match="row-parent">
<xsl:apply-templates select="row">
<xsl:sort select="name(*[1])" />
</xsl:apply-templates>
</xsl:template>
请注意,通过选择“row”而不是默认值(所有子节点,包括文本节点),我们避免选择包含空格的文本节点,这对于我们的输出是不合需要的。
然后,为了添加章节标题,处理子句的模板使用条件来查看这是否是其部分的第一行:
<xsl:template match="row">
<xsl:variable name="childName" select="name(*[1])"/>
<!-- if this is the first row with an element child of this name -->
<xsl:if test="not(preceding-sibling::row[name(*[1]) = $childName])">
<xsl:value-of select="concat(' ',
translate(substring($childName, 1, 1), $lower, $upper),
substring($childName, 2), ' ')"/>
</xsl:if>
然后输出该组每行的数据,并使用您想要的格式:
<xsl:number level="any" count="row[name(*[1]) = $childName]" format=" 1. "
from="row-parent"/>
<xsl:value-of select="normalize-space(*[1])"/>
<xsl:text> </xsl:text>
</xsl:template>
像往常一样,$ lower和$ upper在模板(或样式表)的顶部定义为
<xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
并使样式表使用'text'输出方法:
<xsl:output method="text"/>
输入上的上述样式表的输出(在<row-parent>
包装器中)是:
Contact
1. some contact details 1
2. some contact details 2
Order
1. some order text 1
2. some order text 2
Payment
1. some payment text 1
或者,更健壮,您可以使用Muenchian grouping:首先按子元素名称对行进行分组,然后(输出每个组的标题并处理)组中的所有行。
答案 3 :(得分:1)
除了分组方法的好答案,这个样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="vSort" select="'|order|payment|contact|'"/>
<xsl:template match="/">
<xsl:apply-templates select="*/row">
<xsl:sort select="string-length(
substring-before($vSort,
concat('|',
name(),
'|')))"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="row/*">
<xsl:variable name="vName" select="name()"/>
<xsl:variable name="vNumber">
<xsl:number level="any" count="*[name()=$vName]" from="/"/>
</xsl:variable>
<xsl:if test="$vNumber = 1">
<xsl:value-of select="concat(translate(substring(name(),1,1),
'opc',
'OPC'),
substring(name(),2),
'
')"/>
</xsl:if>
<xsl:value-of select="concat($vNumber,'. ',text,'
')"/>
</xsl:template>
</xsl:stylesheet>
输出(输入格式良好):
Order
1. some order text 1
Payment
1. some payment text 1
2. some order text 2
Contact
1. some contact details 1
2. some contact details 2