2013-11-21 46 views
1

我不知道怎麼用記號化()函數正確是這種情況:XSLT 2記號化

輸入

<RQ> 
    <Node1> 
     <Node2> 
      <Node3>VA</Node3> 
      <Node4>some value</Node4> 
     </Node2> 
     <Node2> 
      <Node3>PE</Node3> 
      <Node4>some value</Node4> 
     </Node2> 
     <Node2> 
      <Node3>VA|PE</Node3> 
      <Node4>some value</Node4> 
     </Node2> 
    </Node1> 
</RQ> 

所需的輸出:

<RQ> 
    <Node1> 
     <Node2> 
      <Node3>VA</Node3> 
      <Node4>some value</Node4> 
     </Node2> 
     <Node2> 
      <Node3>VA</Node3> 
      <Node4>some value</Node4> 
     </Node2> 
    </Node1> 
</RQ> 

說明: 我想標記化Node3的值並且只將那些Node3值等於'VA'的節點2元素複製到輸出。在上面的例子中,標記值爲'PE'的節點3應該被忽略。

用下面的變換:

<xsl:template match="/RQ/Node1/Node2/Node3"> 
    <xsl:for-each select="tokenize(., '\|')"> 
     <xsl:if test="current()='VA'"> 
      <xsl:element name="Node3"> 
       <xsl:copy-of select="current()"/> 
      </xsl:element> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:template> 

我能得到這樣的輸出:

<RQ> 
    <Node1> 
    <Node2> 
     <Node3>VA</Node3> 
     <Node4>some value</Node4> 
    </Node2> 
    <Node2> 
     <Node4>some value</Node4> 
    </Node2> 
    <Node2> 
     <Node3>VA</Node3> 
     <Node4>some value</Node4> 
    </Node2> 
    </Node1> 
</RQ> 

的事情是我不希望的中間節點2千萬在所有如果它不包含節點3 。

回答

0

我有身份模板,複製一切從輸入到輸出不變除了其中一個更具體的模板覆蓋啓動:

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

現在我們添加一些更具體的模板,第一個完全無視任何Node2Node3價值包含VA

<!-- this works because tokenize gives you a sequence of strings, and an = 
    comparison between a sequence and a string is true if _any_ of the items 
    in the sequence match the value, thus not(seq = 'val') is true if _none_ 
    of them match --> 
<xsl:template match="Node2[not(tokenize(Node3, '\|') = 'VA')]" /> 

最後,因爲你現在知道只有有一個VA的Node2元素將要在所有的處理,它是安全的硬編碼的所有Node3元素:

<xsl:template match="Node3"> 
    <xsl:copy>VA</xsl:copy> 
</xsl:template> 

更一般地,如果你有你感興趣的代碼列表(在這裏我把它放在一個變量,但它可能是一個外部XML文件):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
    <!-- interesting codes given inline, you could instead say 
     <xsl:variable name="interestingCodes" select="doc('codes.xml')" /> 
    --> 
    <xsl:variable name="interestingCodes"> 
    <codes> 
     <code>VA</code> 
     <code>VB</code> 
    </codes> 
    </xsl:variable> 

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

    <!-- ignore Node2 elements that don't contain at least one of the codes 
     we are interested in --> 
    <xsl:template match="Node2[not(tokenize(Node3, '\|') = 
           $interestingCodes/codes/code)]" /> 

    <xsl:template match="Node3"> 
    <xsl:copy> 
     <!-- filter the codes in this Node3 to just the interesting ones --> 
     <xsl:value-of select="tokenize(., '\|')[. = $interestingCodes/codes/code]" 
        separator="|" /> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

鑑於以下輸入:

<RQ> 
    <Node1> 
     <Node2> 
      <Node3>VA</Node3> 
      <Node4>some value 1</Node4> 
     </Node2> 
     <Node2> 
      <Node3>VB|PE|VA</Node3> 
      <Node4>some value 2</Node4> 
     </Node2> 
     <Node2> 
      <Node3>VB|PE</Node3> 
      <Node4>some value 3</Node4> 
     </Node2> 
     <Node2> 
      <Node3>PE</Node3> 
      <Node4>some value 4</Node4> 
     </Node2> 
    </Node1> 
</RQ> 

這個樣式表產生:

<?xml version="1.0" encoding="UTF-8"?> 
<RQ> 
    <Node1> 
     <Node2> 
      <Node3>VA</Node3> 
      <Node4>some value 1</Node4> 
     </Node2> 
     <Node2> 
      <Node3>VB|VA</Node3> 
      <Node4>some value 2</Node4> 
     </Node2> 
     <Node2> 
      <Node3>VB</Node3> 
      <Node4>some value 3</Node4> 
     </Node2> 

    </Node1> 
</RQ> 
+0

很好的解決方案。如果我不僅要處理VA,還要處理VB,VC,所以不能在最後一個模板中對其進行硬編碼? – pempek

+0

@pempek我已經添加了一個如何處理「有趣」代碼列表的例子。 –

0

使用上述的輸入和輸出下面的XSLT應產生使用原始模板所需的結果:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.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="/RQ/Node1/Node2[Node3='PE']" /> 
    <xsl:template match="/RQ/Node1/Node2/Node3"> 
     <xsl:for-each select="tokenize(., '\|')"> 
      <xsl:if test="current()='VA'"> 
       <xsl:element name="Node3"> 
        <xsl:copy-of select="current()"/> 
       </xsl:element> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

第一模板(身份模板)複製所有內容到輸出。

第二模板移除Node2時的Node3值等於PE

第三模板使用的原代碼,其中基於標記化上|值,並創建的current()副本。

0

你不一定需要來標記。該解決方案使用contains來檢查Node3元素是否包含「VA」。

<?xml version="1.0" encoding="utf-8"?> 

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

<xsl:output method="xml" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:apply-templates/> 
</xsl:template> 

<xsl:template match="RQ|Node1"> 
    <xsl:copy> 
    <xsl:apply-templates/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="Node2"> 
    <xsl:choose> 
    <xsl:when test="contains(Node3,'VA')"> 
     <xsl:copy> 
      <xsl:apply-templates/> 
     </xsl:copy> 
    </xsl:when> 
    <xsl:otherwise/> 
    </xsl:choose> 
</xsl:template> 

<xsl:template match="Node3[contains(.,'VA')]"> 
    <xsl:copy> 
    <xsl:text>VA</xsl:text> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="Node4[contains(preceding-sibling::Node3,'VA')]"> 
    <xsl:copy> 
    <xsl:value-of select="."/> 
    </xsl:copy> 
</xsl:template>    

</xsl:stylesheet> 

這是輸出你不用它:

<?xml version="1.0" encoding="UTF-8"?> 
<RQ> 
<Node1> 
    <Node2> 
     <Node3>VA</Node3> 
     <Node4>some value</Node4> 
    </Node2> 

    <Node2> 
     <Node3>VA</Node3> 
     <Node4>some value</Node4> 
    </Node2> 
</Node1> 
</RQ>