2011-12-12 36 views
2

這是我正在嘗試實現的: 我有一個CSV文件,其數據類似1,4,5 ..等等(不是一個固定的系列),我有一個XML是有某些節點重複。現在從該XML中,我需要刪除所有那些位置在CSV文件中的節點。在XSLT中比較CSV

這就是我想要做到的: 我將CSV文件作爲參數傳遞給XSLT並調用遞歸模板來打印XML。 (感謝我看到了很長一段時間back..don't記住地址後)

問題:「這是行不通的」 :)

下面是我的示例XML和XSLT。任何幫助,將不勝感激。

XML:

<?xml version="1.0" encoding="UTF-8"?> 
<Items> 
    <Item IItemID=""> 
    </Item> 
    <Item ItemID="100-8754"> 
    </Item> 
    <Item ItemID="206-4141"> 
    </Item> 
    <Item ItemID=""> 
    </Item> 
</Items> 

這裏是XSLT:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes"> 
    <xsl:param name="ErrorPos" as="xs:string" select="'1,4'"/> 
    <xsl:template match="*|/"> 
       <xsl:call-template name="commaSplit"> 
      <xsl:with-param name="dataString" select="$ErrorPos"/> 
      <xsl:with-param name="position" select="1"/> 
     </xsl:call-template> 
    </xsl:template> 
    <xsl:template name="commaSplit"> 
     <xsl:param name="dataString"/> 
     <xsl:param name="position"/> 
      Vivek 
     <xsl:choose> 
      <xsl:when test="contains($dataString,',')"> 
       <!-- Select the first value to process --> 
       <xsl:call-template name="getItems"> 
        <xsl:with-param name="errorPosition" select="substring-before($dataString,',')"/> 
        <xsl:with-param name="position" select="$position"/> 
       </xsl:call-template> 
       <!-- Recurse with remainder of string --> 
       <xsl:call-template name="commaSplit"> 
        <xsl:with-param name="dataString" select="substring-after($dataString,',')"/> 
        <xsl:with-param name="position" select="$position + 1"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <!-- This is the last value no need to recurse --> 
       <xsl:call-template name="getItems"> 
        <xsl:with-param name="errorPosition" select="$dataString"/> 
        <xsl:with-param name="position" select="$position"/> 
       </xsl:call-template> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
    <!-- Process of individual value here --> 
    <xsl:template name="getItems" match="/"> 
     <xsl:param name="errorPosition"/> 
     <xsl:param name="position"/> 
     <Items> 
      <xsl:value-of select="$errorPosition"/> 
      <xsl:value-of select="concat(',',$position)"/><!--Just for testing...will be replaced by copy statement--> 
     </Items> 
    </xsl:template> 

</xsl:stylesheet> 
+0

XSLT的任何原因?正如你發現的那樣,XSLT不知道CSV,這使得CSV成爲絕對的平衡器。所以通過C#/ Java/{chioce語言}中的DOM操作來實現這一點會更容易。 –

+0

沒有克里斯......其實我們並沒有使用C#..但是我在JAVA中並沒有那麼高興,所以如果你能提供相同的指針,我會很樂意瀏覽。 – Kapil

+0

這就是爲什麼我在列表中添加了{語言的選擇},因爲幾乎每個環境都有一個XML DOM解析器,這就是爲什麼我問你爲什麼只限於XSLT。 –

回答

2

你的問題是,因爲你有2個模板,都匹配 「/」 XML文檔的根,以漏斗正確的數據你必須確保優先級設置在你想要執行的模板上!由於您使用的是命名模板,因此您可以簡單地從getItems模板中刪除match屬性!

有了這個小改變它的工作原理,除非你有不同的輸出所需?

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes"> 
    <xsl:param name="ErrorPos" as="xs:string" select="'1,4'"/> 
    <xsl:template match="*|/" priority="999"> 
       <xsl:call-template name="commaSplit"> 
      <xsl:with-param name="dataString" select="$ErrorPos"/> 
      <xsl:with-param name="position" select="1"/> 
     </xsl:call-template> 
    </xsl:template> 
    <xsl:template name="commaSplit"> 
     <xsl:param name="dataString"/> 
     <xsl:param name="position"/> 
      Vivek 
     <xsl:choose> 
      <xsl:when test="contains($dataString,',')"> 
       <!-- Select the first value to process --> 
       <xsl:call-template name="getItems"> 
        <xsl:with-param name="errorPosition" select="substring-before($dataString,',')"/> 
        <xsl:with-param name="position" select="$position"/> 
       </xsl:call-template> 
       <!-- Recurse with remainder of string --> 
       <xsl:call-template name="commaSplit"> 
        <xsl:with-param name="dataString" select="substring-after($dataString,',')"/> 
        <xsl:with-param name="position" select="$position + 1"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <!-- This is the last value no need to recurse --> 
       <xsl:call-template name="getItems"> 
        <xsl:with-param name="errorPosition" select="$dataString"/> 
        <xsl:with-param name="position" select="$position"/> 
       </xsl:call-template> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
    <!-- Process of individual value here --> 
    <xsl:template name="getItems" match="/"> 
     <xsl:param name="errorPosition"/> 
     <xsl:param name="position"/> 
     <Items> 
      <xsl:value-of select="$errorPosition"/> 
      <xsl:value-of select="concat(',',$position)"/><!--Just for testing...will be replaced by copy statement--> 
     </Items> 
    </xsl:template> 

</xsl:stylesheet> 

問候, 山姆

+0

感謝Sam ..它完美地工作。 – Kapil

+0

@Vivek,TreeMonkey:爲什麼不真的使用XSLT 2.0作爲它的目標語言?使用它作爲純XSLT 1.0是一個恥辱。 –

+0

@DimitreNovatchev我只知道xslt 1.0在.net環境中工作,所以很快就會發生這種改變的可能性很小,我從你的回答中看到,爲了我的目的,它可能非常方便! – Treemonkey

3

問得好,+1。

請注意,您正在使用XSLT 2.0,但完全沒有使用任何XSLT 2.0特定功能。

下面是一個簡短和簡單(單個模板,沒有遞歸,沒有xsl:call-template,沒有xsl:choosexsl:whenxsl:otherwiseXSLT 2.0溶液

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:param name="pErrorPos" as="xs:string" select="'1,4'"/> 

<xsl:variable name="vDeletePos" as="xs:integer*" select= 
" for $s in tokenize($pErrorPos, ',') 
    return xs:integer($s) 
"/> 

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

<xsl:template match="Item[position() = $vDeletePos]"/> 
</xsl:stylesheet> 

當施加上提供的XML文檔

<Items> 
    <Item IItemID=""/> 
    <Item ItemID="100-8754"/> 
    <Item ItemID="206-4141"/> 
    <Item ItemID=""/> 
</Items> 

的希望,正確的結果產生

<Items> 
    <Item ItemID="100-8754"/> 
    <Item ItemID="206-4141"/> 
</Items> 

說明

  1. 重寫Identity rule

  2. 使用標準的XPath函數tokenize()

+0

+1正確答案和xslt 2.0使用! – Treemonkey

+0

@Treemonkey:不客氣。 –