2013-01-31 53 views
0

我想如何做一個字符串查找和如何解析逗號分隔字符串分別。不過,我想知道是否有一種有效的方法來滿足這兩個要求。下面是我的源XML:XSLT如何用逗號分隔的字符串查找值?

<?xml version="1.0" ?> 
    <MATRIX> 
    <DATA_RECORD> 
     <COMPONENT1>1, 2</COMPONENT1> 
     <COMPONENT2>6, 7, 8, 9</COMPONENT2> 
    </DATA_RECORD> 
    </MATRIX> 

我希望通過解析逗號分隔字符串,並使用每個令牌做一個查找生成以下XML:

<?xml version="1.0" encoding="UTF-8"?> 
    <MATRIX> 
    <DATA_RECORD> 
     <COMPONENT1>A, B</COMPONENT1> 
     <COMPONENT2>F, G, H, I</COMPONENT2> 
    </DATA_RECORD> 
    </MATRIX> 

這裏是我的查找XML( COMPONENT_LOOKUPLIST.xml):

<?xml version="1.0" ?> 
    <MAIN> 
     <DATA_RECORD> 
     <COMPONENT_ID>1</COMPONENT_ID> 
     <COMPONENT_NAME>A</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>2</COMPONENT_ID> 
     <COMPONENT_NAME>B</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>3</COMPONENT_ID> 
     <COMPONENT_NAME>C</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>4</COMPONENT_ID> 
     <COMPONENT_NAME>D</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>5</COMPONENT_ID> 
     <COMPONENT_NAME>E</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>6</COMPONENT_ID> 
     <COMPONENT_NAME>F</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>7</COMPONENT_ID> 
     <COMPONENT_NAME>G</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>8</COMPONENT_ID> 
     <COMPONENT_NAME>H</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>9</COMPONENT_ID> 
     <COMPONENT_NAME>I</COMPONENT_NAME>  
     </DATA_RECORD> 
    </MAIN> 

我是XSLT的初學者。一些XSLT專家可以分享一些想法或提供示例代碼嗎?我接到了傑尼網站的令牌代碼:

<xsl:template name="tokenize"> 
      <xsl:param name="string" /> 
      <xsl:param name="delimiter" select="','" /> 
      <xsl:choose> 
      <xsl:when test="$delimiter and contains($string, $delimiter)"> 
       <token> 
       <xsl:value-of select="substring-before($string, $delimiter)" /> 
       </token> 

       <xsl:call-template name="tokenize"> 
       <xsl:with-param name="string" 
           select="substring-after($string, $delimiter)" /> 
       <xsl:with-param name="delimiter" select="$delimiter" /> 
       </xsl:call-template> 
      </xsl:when> 

      <xsl:otherwise> 
       <token><xsl:value-of select="$string" /></token> 

      </xsl:otherwise> 
      </xsl:choose> 
     </xsl:template> 

    <xsl:call-template name="tokenize">  
      <xsl:with-param name="string" select="/MATRIX/DATA_RECORD/COMPONENT1"></xsl:with-param> 
      </xsl:call-template> 

      <xsl:call-template name="tokenize">  
      <xsl:with-param name="string" select="/MATRIX/DATA_RECORD/COMPONENT2"></xsl:with-param> 
      </xsl:call-template> 

,並寫了一個查詢:

<xsl:variable name="lookup" select="document('COMPONENT_LOOKUPLIST.xml')/MAIN/DATA_RECORD"/> 
       <xsl:for-each select="//DATA_RECORD"> 

<token> 
    <xsl:for-each select="*">  
    <xsl:value-of select="$lookup[COMPONENT_ID = current()]/COMPONENT_NAME"/>   
      </xsl:for-each> 
      </token> 
     </xsl:for-each> 

但似乎具有挑戰性的這兩個結合在一起。

謝謝。

+0

您希望我們爲您做好工作嗎? – BenjiWiebe

+0

您使用的是什麼版本的XSLT,以及什麼處理器? – JLRishe

回答

0

您是否考慮過使用像Saxon 9或AltovaXML或XmlPrime這樣的XSLT 2.0處理器?在這種情況下,你可以很容易地做到

<xsl:key name="by-id" match="DATA_RECORD" use="COMPONENT_ID"/> 

<xsl:param name="lk-doc-url" select="'COMPONENT_LOOKUPLIST.xml'"/> 
<xsl:variable name="lk-doc" select="document($lk-doc-url)"/> 

<xsl:template match="*[starts-with(local-name(), 'COMPONENT')]"> 
    <xsl:copy> 
    <xsl:value-of select="for $id in tokenize(., ', ') return key('by-id', $id, $lk-doc)/COMPONENT_NAME" 
     separator=", "/> 
    </xsl:copy> 
</xsl:template> 

[編輯] 下面是一個完整和測試樣品:

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



<xsl:key name="by-id" match="DATA_RECORD" use="COMPONENT_ID"/> 

<xsl:param name="lk-doc-url" select="'test2013013103.xml'"/> 
<xsl:variable name="lk-doc" select="document($lk-doc-url)"/> 

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

<xsl:template match="*[starts-with(local-name(), 'COMPONENT')]"> 
    <xsl:copy> 
    <xsl:value-of select="for $id in tokenize(., ', ') return key('by-id', $id, $lk-doc)/COMPONENT_NAME" 
     separator=", "/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

當我申請與撒克遜9.4到輸入

<?xml version="1.0" ?> 
    <MATRIX> 
    <DATA_RECORD> 
     <COMPONENT1>1, 2</COMPONENT1> 
     <COMPONENT2>6, 7, 8, 9</COMPONENT2> 
    </DATA_RECORD> 
    </MATRIX> 

與查找文件test2013013103.xml

<?xml version="1.0" ?> 
    <MAIN> 
     <DATA_RECORD> 
     <COMPONENT_ID>1</COMPONENT_ID> 
     <COMPONENT_NAME>A</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>2</COMPONENT_ID> 
     <COMPONENT_NAME>B</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>3</COMPONENT_ID> 
     <COMPONENT_NAME>C</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>4</COMPONENT_ID> 
     <COMPONENT_NAME>D</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>5</COMPONENT_ID> 
     <COMPONENT_NAME>E</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>6</COMPONENT_ID> 
     <COMPONENT_NAME>F</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>7</COMPONENT_ID> 
     <COMPONENT_NAME>G</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>8</COMPONENT_ID> 
     <COMPONENT_NAME>H</COMPONENT_NAME>  
     </DATA_RECORD> 
     <DATA_RECORD> 
     <COMPONENT_ID>9</COMPONENT_ID> 
     <COMPONENT_NAME>I</COMPONENT_NAME>  
     </DATA_RECORD> 
    </MAIN> 

輸出

<?xml version="1.0" encoding="UTF-8"?><MATRIX> 
    <DATA_RECORD> 
     <COMPONENT1>A, B</COMPONENT1> 
     <COMPONENT2>F, G, H, I</COMPONENT2> 
    </DATA_RECORD> 
    </MATRIX> 

所以我的建議的工作,我不知道你的情況,你沒有得到任何內容有所不同。

+0

嗨馬丁。感謝您查看這個。我對2.0開放。但我只是解析XML並且只是空的XML 。這裏有什麼遺漏嗎? – user2029709

+0

我沒有發佈完整的樣式表,只是試圖給你一個想法。但是現在我已經編寫了一個完整的工作樣式表,其中上面的示例用作發佈,除了查找文件的URL。我將編輯答案並提供詳細信息。 –

+0

看起來這與我的XMLSpy處理器有關。您的解決方案與撒克遜完美配合。非常感謝你以這樣一種流暢的方式出現。祝你有美好的一天。 – user2029709

0

如果你被卡住XSLT1.0,一個解決辦法是修改記號化模板做查詢,而不是吐痰令牌元素(如果你不停地跟令牌元素,你將不得不做一個兩遍轉換來根據你的查找把它們轉換回字符串)。

所以,與其在記號化這樣模板

<token> 
    <xsl:value-of select="substring-before($string, $delimiter)" /> 
</token> 

做的,這不是

<xsl:value-of select="$lookup[COMPONENT_ID=normalize-space(substring-before($string, $delimiter))]/COMPONENT_NAME"/> 
<xsl:value-of select="$delimiter"/> 

以下是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" method="html"/> 

    <xsl:variable name="lookup" select="document('C:\COMPONENT_LOOKUPLIST.xml')/MAIN/DATA_RECORD"/> 

    <xsl:template match="DATA_RECORD/*"> 
     <xsl:copy> 
     <xsl:call-template name="tokenize"> 
      <xsl:with-param name="string" select="."/> 
     </xsl:call-template> 
     </xsl:copy> 
    </xsl:template> 

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

    <xsl:template name="tokenize"> 
     <xsl:param name="string"/> 
     <xsl:param name="delimiter" select="','"/> 
     <xsl:choose> 
     <xsl:when test="$delimiter and contains($string, $delimiter)"> 
      <xsl:value-of select="$lookup[COMPONENT_ID=normalize-space(substring-before($string, $delimiter))]/COMPONENT_NAME"/> 
      <xsl:value-of select="$delimiter"/> 
      <xsl:call-template name="tokenize"> 
       <xsl:with-param name="string" select="substring-after($string, $delimiter)"/> 
       <xsl:with-param name="delimiter" select="$delimiter"/> 
      </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$lookup[COMPONENT_ID=normalize-space($string)]/COMPONENT_NAME"/> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

當適用於您的XML,以下是輸出

<MATRIX> 
    <DATA_RECORD> 
     <COMPONENT1>A,B</COMPONENT1> 
     <COMPONENT2>F,G,H,I</COMPONENT2> 
    </DATA_RECORD> 
</MATRIX> 

注意,這並不刪除空格過,但希望這不是一個問題...

編輯:如果你想保留的空間,你做這樣的事情:

<xsl:variable name="current" select="substring-before($string, $delimiter)" /> 
<xsl:value-of select="substring-before($current, normalize-space($current))" /> 
<xsl:value-of select="$lookup[COMPONENT_ID=normalize-space($)]/COMPONENT_NAME"/> 
<xsl:value-of select="substring-after($current, normalize-space($current))" /> 
+0

非常感謝Tim。這很快,效果很好。我很關心這個空間,但後來我需要把它解析成一個HTML。有了空格,文字可以正確包裝。將看看我是否可以添加空間。我將XSLT 1.0與Altova XMLSpy一起用作處理器。我想知道2.0是否有更好的解決方案。 – user2029709

+0

我已經修改了我的答案以顯示如何添加空格,但如果您可以使用XSLT2.0,那麼Martin的解決方案絕對是您的選擇。 –