XSLT元素名称作为字符串

问题描述:

我想类似下面的使用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

这个样式表:

<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

不知道这是做的最有效的方式,但希望这应该给你一些指点,如果确实没有做的工作完全:

<?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