2017-04-20 25 views
2

我有下面的XML片段:如何計算XSLT中的不同子字符串?

<wrapper> 
     <item timestamp="19.10.2011 12:05"> 
     <comment>Used for orderID '011187' with item 'xyz1'</comment> 
     </item> 
     <item timestamp="01.06.2012 16:25"> 
     <comment>Used for orderID '011379' with item 'xyz2'</comment> 
     </item> 
     <item timestamp="06.06.2012 14:32"> 
     <comment>Used for orderID '011382' with item 'xyz2'</comment> 
     </item> 
    </wrapper> 

我想知道有多少的每個項目出現。 在這種情況下:
- 1個XYZ1
- 2×XYZ2

所以,在某種程度上,你必須遍歷所有<item>,提取其中的文本with item...後引號(')之間的字符串,然後怎麼算很多時候這個字符串總是出現在包裝元素中。

在XSLT中你會如何解決這個問題?

+2

1.0或2.0?兩者之間的字符串處理差異很大。 – Paulb

+1

「*提取引號(')*」之間的字符串哪一個?給定示例中的所有實例中都有兩個。您需要提供更具體的規則。 –

+0

@ michael.hor257k:我的意思是「有物品......」之後的第二個引號,我在我的問題中添加了信息。 – basZero

回答

2

對於XSLT 2,你會做最好的去與fafl的答案。如果你堅持用XSLT 1,以下將工作:

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

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

    <xsl:template match="comment"> 
     <xsl:variable name="item" select='substring-before(substring-after(., "item &apos;"), "&apos;")' /> 
     <xsl:variable name="quotedItem" select='concat("item &apos;", $item, "&apos;")' /> 
     <xsl:if test='generate-id(.) = generate-id(//comment[contains(text(), $quotedItem)])'> 
      <xsl:value-of select='count(//comment[contains(text(), $quotedItem)])' /> 
      <xsl:text> x </xsl:text> 
      <xsl:value-of select="$item" /> 
      <xsl:text>&#13;&#10;</xsl:text> 
     </xsl:if> 
    </xsl:template> 

</xsl:transform> 

讓我們把它分解一下。第一個模板很簡單,遞歸地應用模板。第二個模板匹配所有<comment>元素。

首先,項目名稱是取子item '後,然後在結果取子'之前提取。這假設項目名稱始終以item 'name'的形式出現。如果沒有,你需要調整它。結果分配給變量item。請注意,使用單引號會使這有點棘手,因爲雙引號和單引號是XML標記。因此select屬性值放置在單引號之間而不是標準雙引號之間,而實際用作文本的單引號則通過&apos;進行引用。

然後分配一個名爲quotedItem的變量,該變量基本上是字符串item 'name'(名稱是實際的項目值),以便稍後使事情變得更容易。它避免了在引號之外匹配項目名稱或者部分匹配(例如,如果一個註釋包含item 'xy'和另一個item 'xyz')。再一次,這會對輸入進行假設。

然後在if元件檢查測試如果當前<comment>的生成的ID是相同的,其中包含quotedItem子串的最後<comment>的生成的ID,使得僅針對每個項目的最後出現的動作是拍攝。在這種情況下,此操作將對包含quotedItem子字符串的所有<comment>元素進行計數,並將其輸出爲count x item,後跟回車和換行符。

核心部分是變數和generated-id技巧。其餘的將取決於你對結果的意義。

的XslTransform鏈接:http://xsltransform.net/a9Giwm

2

在XSLT 2.0這個作品:

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

    <xsl:template match="wrapper"> 
     <xsl:for-each-group select="item/comment" 
      group-by="replace(tokenize(., ' ')[last()], '[^a-zA-Z0-9]', '')"> 
     <xsl:sort select="current-grouping-key()"/> 
     <xsl:value-of select="concat('- ', count(current-group()), ' x ', current-grouping-key(), '&#xa;')"/> 
     </xsl:for-each-group> 
    </xsl:template> 

</xsl:stylesheet> 

小提琴:http://xsltransform.net/pNmBxZD

2

下面是使用Muenchian分組的(xsl:key),另一個XSLT 1.0選項...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:strip-space elements= "*"/> 

    <xsl:key name="items" match="comment" 
    use="substring-after(normalize-space(),'with item ')"/> 

    <xsl:template match="/wrapper"> 
    <xsl:for-each select="item/comment[count(.|key('items', 
     substring-after(normalize-space(),'with item '))[1])=1]"> 
     <xsl:variable name="items" select="key('items', 
     substring-after(normalize-space(),'with item '))"/> 
     <xsl:value-of select='concat("- ",count($items)," x ", 
     translate(substring-after(normalize-space(),"with item "),"&apos;",""), 
     "&#xA;")'/> 
    </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

實施例(因爲其他人都在做;-):http://xsltransform.net/93dEHFs