[英]XSL grouping xml by element
我正在使用XSLT1.0(處理器無法處理2.0),嘗試對xml結構的輸出進行分組時遇到問題:
<行>
<訂單>
<文本>一些命令文本1
</ text>
</ order>
</ row>
<行>
<付款>
<文本>一些付款文本1
</ text>
</ payment>
</ row>
<行>
<訂單>
<文本>一些命令文本2
</ text>
</ order>
</ row>
<行>
<聯系人>
<text>一些聯系方式1
</ text>
</ contact>
</ row>
<行>
<聯系人>
<text>一些聯系方式2
</ text>
</ contact>
</ row>
今天,我們選擇所有行並為每個行調用Apply模板(每種類型都有自己的模板,該模板寫出其主體),從而創建如下輸出:
訂單:一些訂單文字1
訂單:一些訂單文字2
付款方式:部分付款文字1
聯系人:一些聯系方式1
聯系人:一些聯系方式2
但是我想(在XSLT 1.0中)對輸出進行分組,以便:
訂購
付款
聯系
顯然,這里除了訂購,付款和聯系外還有許多其他元素類型,因此按顯式元素名稱進行選擇不是解決方案。
編輯
是的,一些很好的答案,如果我有一個說的結構,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()"/>
將跨所有人選擇所有行,這不是我想要的。 也感謝您的好評。
在XSLT 1.0中執行此操作,您需要使用Muenchian分組 ,但是(在我看來)使用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
嘗試:
<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>
測試基本上說:“如果以前沒有同名兄弟姐妹,則輸出此信息”。
以@Flynn的答案為基礎...
如果您有父級模板(樣本中未顯示):
<xsl:template match="row-parent">
<xsl:apply-templates select="row">
<xsl:sort select="name(*[1])" />
</xsl:apply-templates>
</xsl:template>
請注意,通過選擇“行”而不是默認值(所有子級,包括文本節點),我們避免選擇包含空格且對於我們的輸出不理想的文本節點。
然后,為了添加節標題,用於處理子項的模板使用一個條件來查看這是否是其節的第一行:
<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'"/>
並使樣式表使用“文本”輸出方法:
<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分組 :首先按子元素名稱對行進行分組 ,然后對(輸出每個組的標頭並)處理組中的所有行。
除了使用分組方法的良好答案外,此樣式表:
<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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.