2013-06-28 21 views
1

我對XSL完全陌生,正在嘗試學習一些東西。假設我有一個這樣的XML:在XSL中基於令牌大小提取節點

<?xml version="1.0" encoding="UTF-8"?> 
<Result> 
    <Node> 
     <node-id>1</node-id> 
     <node-path>2,3</node-path> 
    </Node> 
    <Node> 
     <node-id>2</node-id> 
     <node-path>2,3,4</node-path> 
    </Node> 
    <Node> 
     <node-id>3</node-id> 
     <node-path>123,34</node-path> 
    </Node> 
    <Node> 
     <node-id>4</node-id> 
     <node-path>2124,14,14</node-path> 
    </Node> 
    <Node> 
     <node-id>5</node-id> 
     <node-path>1,0</node-path> 
    </Node> 
</Result> 

,我想所有在該節點路徑字段只有兩個值,如節點:

<?xml version="1.0" encoding="UTF-8"?> 
    <Result> 
    <Node> 
     <node-id>1</node-id> 
     <node-path>2,3</node-path> 
    </Node> 
    <Node> 
     <node-id>3</node-id> 
     <node-path>123,34</node-path> 
    </Node> 
    <Node> 
     <node-id>5</node-id> 
     <node-path>1,0</node-path> 
    </Node> 
</Result> 

我怎麼會在XSL做到這一點?由於我需要複製節點,我發現我必須使用身份轉換作爲模板。我還看到我們應該使用遞歸來計算令牌。我想出了這個:

<?xml version="1.0" encoding="iso-8859-1"?> 
<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" /> 

    <xsl:template name="root-nodes"> 
     <xsl:for-each select="/Result/Node"> 
      <xsl:variable name="path" select="node-path" /> 
      <xsl:call-template name="tokenizer" mode="matcher"> 
       <xsl:with-param name="list" select="$path" /> 
       <xsl:with-param name="delimiter" select="','" /> 
      </xsl:call-template> 
     </xsl:for-each> 
    </xsl:template> 

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

    <!-- Could not figure out how to write this recursion --> 
    <xsl:template name="tokenizer" mode="matcher"> 
     <xsl:param name="list"/> 
     <xsl:param name="delimiter" /> 
     <xsl:value-of select="substring-before($list,$delimiter)" /> 
     <xsl:call-template name="tokenizer"> 
      <xsl:with-param name="list" select="substring-after($list,$delimiter)" /> 
      <xsl:with-param name="delimiter" select="','" /> 
     </xsl:call-template> 
    </xsl:template> 

</xsl:stylesheet> 

但我有問題遞歸片。如何計算令牌並確保僅在計數爲2時才進行身份轉換?我怎樣才能修復遞歸模板?我現有的「tokenizer」模板中有什麼問題(它甚至沒有給我這些令牌)?任何額外的資源/鏈接都會非常好。

+0

如果使用xslt 2.0,則使用replace()來提取值,寬度正則表達式。 http://www.xsltfunctions.com/xsl/fn_replace.html –

+0

你已經標記了「xslt-1.0」這個問題,但是你的樣式表說了「version =」2.0「' - 你真的想要哪個? –

+0

@伊·羅伯茨:對不起。那是個錯誤。更正它。我想要1.0 – Flash

回答

3

我覺得

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


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

    <xsl:template match="Node[string-length(translate(node-path, ',', '')) != (string-length(node-path) - 1)]"/> 


</xsl:stylesheet> 

就足夠了。

+0

看起來我們都有同樣的想法(如果表達方式稍有不同)。你贏了:-) –

1

自「是路徑中有兩個值節點」是一樣的「其路徑恰好包含一個逗號節點」,你可以使用一個小技巧是這樣

<?xml version="1.0" encoding="iso-8859-1"?> 
<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" /> 

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

    <!-- ignore Nodes whose node path does not contain one comma --> 
    <xsl:template match="Node[translate(node-path, translate(node-path, ',', ''), '') != ',']" /> 
</xsl:stylesheet> 

的雙翻譯技巧是一個很有用的知識,它提供了一個方法來去除字符串中的所有字符,除了在白名單中的。在這種情況下,我們將刪除路徑中的所有非逗號字符,然後檢查我們剩下的是否是單個逗號。

+0

是不是外部'translate'調用缺少一個參數(三個必需的參數)? –

+0

@MartinHonnen它做到了,我現在修好了。 –