2010-07-12 89 views
-2

我想類似下面的使用XSLT輸出的東西XSLT元素名稱作爲字符串

XML:

<myroot> 
    <node1> 
    <subnode1>somestuff</subnode1> 
    <subnode2>otherstuff</subnode2> 
    </node1> 
    <node2> 
    <subnode2></subnode2> 
    <subnode3>stuff here</subnode3> 
    </node2> 
    <node3> 
    <subnode>stuff</subnode> 
    <subnode>stuff</subnode> 
    <subnode>other</subnode> 
    </node3> 
</myroot> 

在哪裏,我不知道一個給定的實例節點名稱。

我希望我的輸出看起來像這樣:

myroot = new jsonObject(); 
myroot.node1 = new jsonObject(); 
myroot.node1.subnode1 = "holder"; 
myroot.node1.subnode2 = "holder"; 
myroot.node2 = new jsonObject(); 
myroot.node2.subnode2 = "holder"; 
myroot.node2.subnode3 = "holder"; 
myroot.node3 = new jsonObject(); 
myroot.node3.subnode = new array(); 
"arraystart" 
myroot.node3.subnode[aindex] = new jsonObject(); 
myroot.node3.subnode[aindex] = "holder"; 
"endarray" 

要點:

  • = 「持有人」;可以是任何東西獨一無二的,因爲我將稍後對此進行更改
  • 「arraystart」和「endarray」可以是任何 獨一無二的,因爲我會改變這 後來
  • 我不知道具體的節點名稱 超越了根。
  • 我不知道樹 (6-7一些深存在)
  • 我不知道號碼或位置 或數組元素的深度,但孩子 節點(元素)是同一名稱那些團體。
  • 可能存在多個陣列,並且 可能處於任何樹深度。
  • 元素文本沒有子 節點
+0

有一件事讓我深深的關注你的XML:你不知道根之外的特定節點名稱。這是非常糟糕的XML設計,儘管從它的聲音來看,這不是您的選擇。如果您可以更改/說服某人將其更改爲而不是(例如),它會使事情變得更容易。主要原因是您無法可靠地爲這些節點創建模板;它將不得不成爲一個全面的模板,而不是專門尋找'節點'元素。 – Flynn1179 2010-07-12 21:41:35

+0

實際上,真正的XML更大,沒有數字。其中有些是已知的,但爲此目的,我需要一個通用的解決方案,它是一個更大的應用程序的一部分,因此這種方法非常適合於手頭的目的。 – 2010-07-13 17:37:34

+0

注意自我:使用http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog進行測試時,硬性限制爲5023個字符的XML,如果失敗,則不會有任何警告(空輸出)。 – 2010-07-13 17:39:03

回答

1

這個樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:key name="name" match="*" use="name()"/> 
    <xsl:template match="text()"/> 
    <xsl:template match="*[*]"> 
     <xsl:param name="name"/> 
     <xsl:value-of select="concat($name, 
            name(), 
            ' = new jsonObject();&#xA;')"/> 
     <xsl:apply-templates> 
      <xsl:with-param name="name" select="concat($name,name(),'.')"/> 
     </xsl:apply-templates> 
    </xsl:template> 
    <xsl:template match="*[not(*)][count(../*|key('name',name()))!=count(key('name',name()))]"> 
     <xsl:param name="name"/> 
     <xsl:value-of select="concat($name, 
            name(), 
            ' = &quot;holder&quot;;&#xA;')"/> 
    </xsl:template> 
    <xsl:template match="*[not(*)][1][count(../*|key('name',name()))=count(key('name',name()))]" priority="1"> 
     <xsl:param name="name"/> 
     <xsl:value-of select="concat($name, 
            name(), 
            ' = new array();&#xA;', 
            '&quot;arraystart&quot;&#xA;')"/> 
     <xsl:apply-templates select="following-sibling::*" mode="array"> 
      <xsl:with-param name="name" select="concat($name,name(),'.')"/> 
     </xsl:apply-templates> 
     <xsl:text>"endarray"</xsl:text> 
    </xsl:template> 
    <xsl:template match="*" mode="array"> 
     <xsl:param name="name"/> 
     <xsl:value-of select="concat($name, 
            '[aindex] = ')"/> 
     <xsl:choose> 
      <xsl:when test="contains(.,'stuff')">new jsonObject();&#xA;</xsl:when> 
      <xsl:otherwise>"holder";&#xA;</xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

myroot = new jsonObject(); 
myroot.node1 = new jsonObject(); 
myroot.node1.subnode1 = "holder"; 
myroot.node1.subnode2 = "holder"; 
myroot.node2 = new jsonObject(); 
myroot.node2.subnode2 = "holder"; 
myroot.node2.subnode3 = "holder"; 
myroot.node3 = new jsonObject(); 
myroot.node3.subnode = new array(); 
"arraystart" 
myroot.node3.subnode.[aindex] = new jsonObject(); 
myroot.node3.subnode.[aindex] = "holder"; 
"endarray" 

但我認爲你應該細化目標。

+0

+1給出了理想的結果(剔除了"),因爲它造成了不明原因的問題,並且不需要100% – 2010-07-13 17:32:52

0

不知道這是做的最有效的方式,但希望這應該給你一些指點,如果確實沒有做的工作完全:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text" /> 

    <xsl:template match="*[count(*)!=0]"> 
    <xsl:param name="prefix" /> 
    <xsl:value-of select="substring(concat($prefix,'.',name()),2)" /> 
    <xsl:text> = new jsonObject();&#10;</xsl:text> 
    <xsl:apply-templates select="*"> 
     <xsl:with-param name="prefix" select="concat($prefix,'.',name())" /> 
    </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="*[count(*)=0]"> 
    <xsl:param name="prefix" /> 
    <xsl:choose> 
     <xsl:when test="count(../*[name()=name(current())]) != 1"> 
     <xsl:if test="position()=1"> 
      <xsl:value-of select="substring(concat($prefix,'.',name()),2)" /> 
      <xsl:text> = new array();&#10;</xsl:text> 
      <xsl:text>"arraystart"&#10;</xsl:text> 
      <xsl:value-of select="substring(concat($prefix,'.',name()),2)" /> 
      <xsl:text>[aindex] = new jsonObject();&#10;</xsl:text> 
      <xsl:value-of select="substring(concat($prefix,'.',name()),2)" /> 
      <xsl:text>[aindex] = "holder";&#10;</xsl:text> 
      <xsl:text>"endarray"&#10;</xsl:text> 
     </xsl:if> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="substring(concat($prefix,'.',name()),2)" /> 
     <xsl:text> = "holder";&#10;</xsl:text> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

我本來第二模板匹配*[text()],但不幸的是你的<subnode></subnode>相當於<subnode />,其中有沒有任何文字,而不是0長度的文本。這意味着它假設任何沒有孩子的節點應該被視爲文本。

第二個模板中的'when'測試有點複雜,但它基本上檢查當前節點是否是具有該名稱的多個節點之一,並且如果它是第一個這樣的節點,它會輸出數組內容,否則什麼都不做。這裏最大的缺點是這樣的數組只能是文本節點;例如,如果您的示例x​​ml具有node1而不是node2,因此您在myroot下有兩個node1元素,則不會看到任何「arraystart」內容。如果發生這種情況,它需要一些重新設計,但希望有足夠的有用的例子來幫助。

編輯:忘記兩個小點:

我使用&#10;爲換行符;如果需要,用&#13;&#10;代替。

此外,substring(something,2)位是因爲它每追溯到一個級別後會追加一個節點名稱,這意味着它每次都會有一個右邊的開頭。 substring(something,2)只需要從第二個字符開始,換句話說,就是斬斷那段時間。

+0

+1給出了預期的結果 – 2010-07-13 17:33:33