2011-05-13 54 views
1

我想獲取最短文本的節點的項目和類型列表。使用xslt/xpath。從節點列表中獲取最短文本列表

我有以下示例XML:

<a> 
    <b> 
    <item>short</item> 
    <item>longest</item> 
    <item type="x">longest text</item> 
    <item type="x">short text</item> 
    <item type="y">text</item> 
    </b> 
</a> 

這是我迄今爲止

<xsl:template match="ns:item"> 
    <xsl:variable name="type"> 
    <xsl:choose> 
     <xsl:when test="@type"> 
     <xsl:value-of select="@type" /> 
     </xsl:when> 
     <xsl:otherwise>default</xsl:otherwise> 
    </xsl:choose> 
    </xsl:variable> 
    <xsl:if test="position() = 1">{</xsl:if> 
    "<xsl:value-of select='$type' />" : "<xsl:value-of select='.' />" 
    <xsl:if test="position() != last()">,</xsl:if> 
    <xsl:if test="position() = last()">}</xsl:if> 
</xsl:template> 

如何過濾所有,但最短的文字出來的結果嗎?

輸出應該是這個樣子:

{ "default": "short", 
"x" : "short text", 
"y" : "text" } 

由於我使用XSLT/XPath的只是偶爾,只有非常簡單的事情,我希望有人能幫助我。

+0

它甚至取決於您正在使用的XSLT處理器。例如,Xalan和Saxon都會爲position()函數返回不正確的值。解決方案可以使用然後剝離第一個節點。 – 2011-05-13 11:39:03

+0

好問題,+1。查看我的答案,獲取完整而簡短的XSLT 2.0解決方案。 – 2011-05-13 13:05:09

回答

0

我將組(Muenchian分組的http://www.jenitennison.com/xslt/grouping/index.xml),然後取最短項各組(簡單地通過在長度排序,並採取的第一項):

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

    <xsl:output method="text"/> 

    <xsl:key name="k1" match="item" use="string(@type)"/> 

    <xsl:template match="/"> 
    <xsl:text>{ </xsl:text> 
    <xsl:apply-templates 
     select="a/b/item[generate-id() = generate-id(key('k1', string(@type))[1])]"/> 
    <xsl:text> }</xsl:text> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:if test="position() &gt; 1"><xsl:text>,&#10;</xsl:text></xsl:if> 
    <xsl:for-each select="key('k1', string(@type))"> 
     <xsl:sort select="string-length(.)" data-type="number"/> 
     <xsl:if test="position() = 1"> 
     <xsl:variable name="type"> 
      <xsl:choose> 
      <xsl:when test="@type"> 
       <xsl:value-of select="@type"/> 
      </xsl:when> 
      <xsl:otherwise>default</xsl:otherwise> 
      </xsl:choose> 
     </xsl:variable> 
     <xsl:text>"</xsl:text> 
     <xsl:value-of select="$type"/> 
     <xsl:text>" : "</xsl:text> 
     <xsl:value-of select="."/> 
     <xsl:text>"</xsl:text> 
     </xsl:if> 
    </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

隨着輸入是

<a> 
    <b> 
    <item>short</item> 
    <item>longest</item> 
    <item type="x">longest text</item> 
    <item type="x">short text</item> 
    <item type="y">text</item> 
    </b> 
</a> 

結果是

{ "default" : "short", 
"x" : "short text", 
"y" : "text" } 
+0

您的解決方案就像我希望的那樣工作。分組鏈接似乎也很有用。謝謝! – Tjeerd 2011-05-14 21:36:33

0

XSLT 2.0溶液

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:variable name="vQ">"</xsl:variable> 
<xsl:template match="https://stackoverflow.com/a/b"> 
    <xsl:text>{ </xsl:text> 
    <xsl:for-each-group select="item" group-by="string(@type)"> 
     <xsl:variable name="vShortest" select= 
     "current-group()[string-length(.) eq min(current-group()/string-length(.))] 
     " /> 
     <xsl:variable name="vNotLast" select="not(position() eq last())"/> 
     <xsl:variable name="vType" select= 
     "'default'[not($vShortest/@type)],$vShortest/@type"/> 
     <xsl:value-of select= 
     "concat($vQ,$vType,$vQ,':', $vQ,$vShortest,$vQ, ',&#xA;'[$vNotLast])"/> 
    </xsl:for-each-group> 
     <xsl:text> }</xsl:text> 
</xsl:template> 
</xsl:stylesheet> 

當所提供的XML文檔施加:

<a> 
    <b> 
     <item>short</item> 
     <item>longest</item> 
     <item type="x">longest text</item> 
     <item type="x">short text</item> 
     <item type="y">text</item> 
    </b> 
</a> 

有用結果產生:

{ "default":"short", 
"x":"short text", 
"y":"text" }