XSLT元素名称为字符串

时间:2010-07-12 20:45:29

标签: xml 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深)
  • 我不知道数字或位置 或数组元素,但孩子 节点(元素)与这些组的名称相同。
  • 可能/确实存在多个阵列,并且可以 在任何树深处。
  • 带文字的元素没有子元素 节点

2 个答案:

答案 0 :(得分: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"

但我认为你应该改进你的目标。

答案 1 :(得分: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,以致node1下有两个myroot元素,则您将看不到任何“arraystart”东西。如果可能发生这种情况,则需要进行一些重新设计,但希望这里有足够的有用示例来帮助。

编辑:忘了两个小点:

我正在使用&#10;作为换行符;如果需要,请用&#13;&#10;代替。

此外,substring(something,2)位是因为它每次下降一级时附加一个句点后跟节点名称,这意味着它每次都有一个权限。 substring(something,2)只需要从第二个角色开始,换句话说,切断那段时间。