2009-02-13 67 views
3

我有一個屬性,其值可能是一個或多個文本字符串,所有文本字符串都用逗號分隔。 我希望使用XSL將屬性值轉換爲它們自己的元素;如何分解由a分隔的屬性,分解爲單獨的元素

e.g

<post title='Hello World" tags="Test,Hello,World /> 

在我想它轉化爲;

<post> 
<title>Hello World</title> 
<tag>Test</tag> 
<tag>Hello</tag> 
<tag>World</tag> 
</post> 

這可能嗎? TIA

+0

你錯配了「和 」並留下了「 未閉合。 – Sparr 2009-02-13 02:13:23

回答

5

有幾種方法可以做到這一點。

I.在XSLT 1.0 使用遞歸所謂命名模板這種轉化

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

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

    <xsl:template match="@*[not(name()='tags')]"> 
     <xsl:element name="{name()}"> 
     <xsl:value-of select="."/> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="@tags"> 
     <xsl:call-template name="tokenize"> 
     <xsl:with-param name="pText" 
     select="concat(., ',')"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="tokenize"> 
     <xsl:param name="pText"/> 

     <xsl:if test="string-length($pText)"> 
     <tag> 
      <xsl:value-of select= 
      "substring-before($pText, ',')"/> 
     </tag> 

     <xsl:call-template name="tokenize"> 
      <xsl:with-param name="pText" select= 
      "substring-after($pText, ',')"/> 
     </xsl:call-template> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

當在最初提供的XML文檔施加(校正爲良好的形成):

<post title="Hello World" 
     tags="Test,Hello,World" /> 

產生所需的結果

<post> 
    <title>Hello World</title> 
    <tag>Test</tag> 
    <tag>Hello</tag> 
    <tag>World</tag> 
</post> 

二,從FXSL 1.x的

這裏使用str-split-to-words模板/功能FXSL提供標記化功能

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

    <xsl:import href="strSplit-to-Words.xsl"/> 

    <xsl:output indent="yes" omit-xml-declaration="yes"/> 

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

    <xsl:template match="@*[not(name()='tags')]"> 
     <xsl:element name="{name()}"> 
     <xsl:value-of select="."/> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="@tags"> 
    <xsl:variable name="vwordNodes"> 
     <xsl:call-template name="str-split-to-words"> 
     <xsl:with-param name="pStr" select="."/> 
     <xsl:with-param name="pDelimiters" 
        select="','"/> 
     </xsl:call-template> 
    </xsl:variable> 

    <xsl:apply-templates select="ext:node-set($vwordNodes)/*"/> 
    </xsl:template> 

    <xsl:template match="word"> 
    <tag> 
     <xsl:value-of select="."/> 
    </tag> 
    </xsl:template> 

</xsl:stylesheet> 

當作爲前對相同的XML文檔應用中,相同的正確的輸出產生

三,使用來自XSLT 2.0轉換的XPath 2.0標準函數tokenize()

這是最簡單的方法 - 如果可以使用XSLT 2.0處理器。

下面的XSLT變換2.0

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

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

    <xsl:template match="@*[not(name()='tags')]"> 
     <xsl:element name="{name()}"> 
     <xsl:value-of select="."/> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="@tags"> 
    <xsl:for-each select="tokenize(.,',')"> 
     <tag><xsl:value-of select="."/></tag> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

當對相同的XML文檔施加再次產生希望的結果。

+0

Dimitre,謝謝你的詳細解決方案。已經運行他們與輕微的mods,它的作品一種享受。 XSL 1.0 tho。 謝謝 – 2009-02-13 23:52:50

0

你應該做的第一件事是找到使用屬性的人,他應該使用元素並讓他停下來。我們接受XML的冗長的原因是,它給了我們無需弄清楚如何解析數據的好處。如果你打算用必須解析的數據打包你的XML,爲什麼你首先使用XML?

+0

這不是100%正確的有所謂的*列表類型*在XML和XML Schema(如IDREFS),這應該是ID或名稱的空格分隔的列表。如果有人使用XPath 2.0/XSLT2.0,那麼這種類型的輸入並不那麼具有挑戰性。 – 2009-02-13 21:09:26

3

我真的很喜歡Dimitre的答案,但他的XSLT 1.0解決方案有一個小錯誤。當我有 「價值,價值,價值」時,它只會將前兩個分割並跳過最後一個。

編輯這是不是一個錯誤,我沒有注意到他被調用模板,CONCAT

這是我修改他的記號化XSLT 1個模板。

<xsl:template name="tokenize"> 
    <xsl:param name="pText"/> 
    <xsl:param name="pTag"/> 
    <xsl:if test="string-length($pText)"> 
    <xsl:element name="{$pTag}"> 
      <xsl:choose> 
        <xsl:when test="string-length(substring-before($pText, ','))"> 
         <xsl:value-of select="substring-before($pText, ',')"/> 
        </xsl:when> 
        <xsl:otherwise><xsl:value-of select="$pText" /></xsl:otherwise> 
       </xsl:choose> 
    </xsl:element> 

    <xsl:call-template name="tokenize"> 
     <xsl:with-param name="pText" select= 
     "substring-after($pText, ',')"/> 
     <xsl:with-param name="pTag"><xsl:value-of select="$pTag" /></xsl:with-param> 
    </xsl:call-template> 
    </xsl:if> 

用法示例

<xsl:call-template name="tokenize"> 
     <xsl:with-param name="pText">123,234,345</xsl:with> 
     <xsl:with-param name="pTag">tag</xsl:with-param > 
</xsl:call-template> 

輸出

<tag>123</tag> 
    <tag>234</tag> 
    <tag>345</tag> 
+0

它沒有錯誤,因爲他用``。 tokenizer遞歸模板有很多種形式。你的是一些多麼詳細... – 2011-04-07 17:19:30

相關問題