2012-09-14 47 views
2

我對XSLT相當陌生,並且已經瀏覽了關於該主題的多篇文章,但似乎無法得到我需要做的最後一件事。我試圖從我已有的節點數據中出現的已知數據串中刪除條目。我已經將一個適用於單節點值但不是多值的解決方案拼湊在一起。如何根據多個節點值的搜索刪除多個數字?

,這裏是我的xml

<root> 
<item>2</item> 
<item>9</item> 
<item>5</item> 
</root> 

這裏是我的代碼,對於一個節點值的工作原理:

<xsl:template match="item"> 
<xsl:copy> 
<xsl:call-template name="replaceChars"> 
<xsl:with-param name="original" select="string('1 2 3 4 5 6 7 8 9 10')"/> 
</xsl:call-template> 
</xsl:copy> 
</xsl:template> 
<xsl:template name="replaceChars"> 
<xsl:param name="original"/> 
<xsl:choose> 
<xsl:when test="contains($original, current())"> 
<xsl:value-of select="substring-before($original, current())"/> 
<xsl:variable name="after" select="substring-after($original, current())"/> 
<xsl:variable name="char" select="substring-before($after, current())"/> 
<xsl:value-of select="concat($char, $after)"/> 
<xsl:call-template name="replaceChars"> 
<xsl:with-param name="original" select="substring-after($after, current())"/> 
</xsl:call-template> 
</xsl:when> 
<xsl:otherwise> 
<xsl:value-of select="$original"/> 
</xsl:otherwise> 
</xsl:choose> 
</xsl:template> 

我最新的測試我試圖用這個:

<xsl:template match="item"> 
<xsl:copy> 
<xsl:call-template name="replaceChars"> 
<xsl:with-param name="original" select="string('1 2 3 4 5 6 7 8 9 10')"/> 
</xsl:call-template> 
</xsl:copy> 
</xsl:template> 
<xsl:template name="replaceChars"> 
<xsl:param name="original"/> 
<xsl:choose> 
<xsl:when test="contains($original, current())"> 
<xsl:variable name="before" select="substring-before($original, current())"/> 
<xsl:variable name="after" select="substring-after($original, current())"/> 
<xsl:variable name="char" select="substring-before($after, current())"/> 
<xsl:variable name="new" select="concat($before, $after)"/> 
<xsl:call-template name="replaceChars"> 
<xsl:with-param name="original" select="$new"/> 
</xsl:call-template> 
</xsl:when> 
<xsl:otherwise> 
<xsl:value-of select="$original"/> 
</xsl:otherwise> 
</xsl:choose> 
</xsl:template> 

我連續得到在響應中迭代了幾次的值。我想我的輸出爲以下:

我已經搜索在此廣泛,你可以看到我的例子是基於改變的搜索場景。任何幫助,將不勝感激。

回答

0

你很近。

如果你想產生一次字符串「1 3 4 6 7 8 10」,那麼你可能不希望你顯示的代碼每個item元素被評估一次,但是每個root元素一次。

如果您希望遞歸模板replaceChars敲除一組同級item元素中的每個item的值,那麼當前結構將不會執行此操作。爲什麼?因爲它敲掉current()的值,然後遞歸地調用自己而不做任何改變current()的值。

一種替代方法是說「我想構建一個由數字1組成的字符串(除非它出現在輸入中),後面是數字2(除非它出現在輸入中),後面是.. 」和寫(NB未測試):

<xsl:template match="root"> 
    <survivors> 
    <xsl:if test="not(./item = '1')">1 </xsl:if> 
    <xsl:if test="not(./item = '2')">2 </xsl:if> 
    <xsl:if test="not(./item = '3')">3 </xsl:if> 
    <xsl:if test="not(./item = '4')">4 </xsl:if> 
    <xsl:if test="not(./item = '5')">5 </xsl:if> 
    <xsl:if test="not(./item = '6')">6 </xsl:if> 
    <xsl:if test="not(./item = '7')">7 </xsl:if> 
    <xsl:if test="not(./item = '8')">8 </xsl:if> 
    <xsl:if test="not(./item = '9')">9 </xsl:if> 
    </survivors> 
</xsl:template> 

或者,如果你真的想要做的子字符串匹配的事情,你需要確保你在replaceChars實際上在item元素迭代遞推:

<xsl:template match="root"> 
    <survivors> 
    <xsl:call-template name="replaceChars2"> 
     <xsl:with-param name="s" select="'1 2 3 4 5 6 7 8 9'"/> 
     <xsl:with-param name="item" select="./item[1]"/> 
    </xsl:call-template> 
    </survivors> 
</xsl:template> 

<xsl:template name="replaceChars2"> 
    <xsl:param name="s"/> 
    <xsl:param name="item"/> 
    <xsl:variable name="s2" select="string($item)"/> 
    <xsl:choose> 
    <xsl:when test="$item"> 
     <xsl:call-template name="replaceChars2"> 
     <xsl:with-param name="s" 
      select="concat(
      substring-before($s,$s2, 
      ' ', 
      substring-after($s,$s2, 
      )"/> 
     <xsl:with-param name="item" 
      select="./following-sibling::item[1]"/> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="$s"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

像顯示的代碼通過OP,假設沒有item元素將意外地匹配不應該被刪除的字符串的任何部分(例如,如果任何項目的值爲'1',原始字符串將永遠不會具有像'11'的值)。

對兄弟姐妹進行迭代並傳遞參數以跟蹤早期兄弟姐妹發生的事情的模式是學習的一個重要習慣用法,用於像這樣的變換。

+0

感謝您的詳細信息和教學我會檢討這 – user1672039

0

這種轉變

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

<my:sent/> 
<xsl:variable name="vSent" select="document('')/*/my:sent"/> 

<xsl:param name="pGiven" select="'1 2 3 4 5 6 7 8 9 10'"/> 

<xsl:template match="/*"> 
    <xsl:apply-templates select="item[1]"/> 
</xsl:template> 

<xsl:template match="item"> 
    <xsl:param name="pText" select="$pGiven"/> 

    <xsl:apply-templates select= 
    "following-sibling::item[1]|$vSent[not(current()/following-sibling::item)]"> 
    <xsl:with-param name="pText" select= 
    "concat(substring-before(concat($pText, .), .), 
      substring-after($pText,.) 
      ) 
    "/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="my:sent"> 
    <xsl:param name="pText"/> 
    <xsl:value-of select="$pText"/> 
</xsl:template> 
</xsl:stylesheet> 

時所提供的XML文檔應用:

<root> 
    <item>2</item> 
    <item>9</item> 
    <item>5</item> 
</root> 

產生想要的,正確的結果:

1 3 4 6 7 8 10 

請注意

  1. 有一個在整個轉型沒有XSLT條件指令 - 沒有xsl:choose,沒有xsl:when,沒有xsl:otherwise沒有xsl:if

  2. 沒有命名模板,也沒有顯式遞歸(儘管xsl:apply-templates隱式遞歸)。

  3. Sentinel以兩種不同的方式使用編程來顯着簡化代碼並使其更高效。

+0

感謝您的信息,我正在審查這一點。 – user1672039

+0

@ user1672039,請告訴我,如果您有任何問題,或者您已成功使用此解決方案。 –