使用xslt将xml转换为xml:递归匹配&;创建类层次树

使用xslt将xml转换为xml:递归匹配&;创建类层次树,xslt,xslt-1.0,Xslt,Xslt 1.0,我对xslt一无所知。请帮我写样式表。我有这样的xml输入 输入XML: <elements> <e1> <pid>1</pid> <cid>2</cid> </e1> <e1> <pid>1</pid> <cid>3</cid> </e1>

我对xslt一无所知。请帮我写样式表。我有这样的xml输入

输入XML:

    <elements>
     <e1>
       <pid>1</pid>
       <cid>2</cid>
     </e1>

     <e1>
      <pid>1</pid>
      <cid>3</cid>
     </e1>

     <e1>
      <pid>2</pid>
      <cid>4</cid>
    </e1>
    </elements>

1.
2.
1.
3.
2.
4.
所需的XML:

    <tree>
      <unit id="1">
        <unit id="2">
           <unit id="4">
             <data></data>
           </unit>
           <data></data>
        </unit>

        <unit id="3">
           <data></data>
        </unit>

        <data></data>

      </unit>
    </tree>


我觉得这应该很容易,但我正在努力寻找如何做到这一点的信息。我的XSLT知识不是很好。

我不能100%确定您希望XSLT如何从该输入确定top id为1(是因为它是唯一的
pid
值,没有相应的
cid
值,还是始终为1?)。尽管如此,这项工作还是应该做到:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="kItemsByC" match="e1" use="cid" />
  <xsl:key name="kItemsByP" match="e1" use="pid" />

  <xsl:template match="/">
    <tree>
      <xsl:call-template name="Unit">
        <!-- This will be the value of the <pid> that has no <cid> references to
             it (assuming there is only one top-level <pid>) -->
        <xsl:with-param name="id" 
                        select="string(/elements/e1/pid[not(key('kItemsByC', .))])" />
      </xsl:call-template>
    </tree>
  </xsl:template>

  <xsl:template match="e1" name="Unit">
    <xsl:param name="id" select="cid" />

    <unit id="{$id}">
      <xsl:apply-templates select="key('kItemsByP', $id)" />
      <data />
    </unit>
  </xsl:template>
</xsl:stylesheet>

当对示例输入运行此操作时,将生成:

<tree>
  <unit id="1">
    <unit id="2">
      <unit id="4">
        <data />
      </unit>
      <data />
    </unit>
    <unit id="3">
      <data />
    </unit>
    <data />
  </unit>
</tree>

注意:上述XSLT具有尝试动态定位顶级ID的逻辑。如果可以假设顶级单元始终具有ID 1,则可以消除一个键和上述XSLT(有些)复杂的公式:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="kItemsByP" match="e1" use="pid" />

  <xsl:template match="/">
    <tree>
      <xsl:call-template name="Unit">
        <xsl:with-param name="id" select="1" />
      </xsl:call-template>
    </tree>
  </xsl:template>

  <xsl:template match="e1" name="Unit">
    <xsl:param name="id" select="cid" />

    <unit id="{$id}">
      <xsl:apply-templates select="key('kItemsByP', $id)" />
      <data />
    </unit>
  </xsl:template>
</xsl:stylesheet>


当在示例输入上运行时,这也会生成所请求的输出。

啊,在阅读JLRishe之后,我想我明白了:“pid”表示“父ID”,“cid”表示“子ID”,e1表示父子关系。出色的侦探工作,我永远不会为自己解决这个问题

基本模型是,当您定位在父元素上时,会将模板应用于其子元素。如果父/子关系由主键/外键表示,就像它们使用XML层次结构表示一样,这同样适用。因此,其实质是:

<xsl:template match="e1">
  <unit id="{pid}">
    <xsl:apply-templates select="//e1[pid=current()/cid]"/>
    <data/>
  </unit>
</xsl:template>

这本质上是JLRishe的解决方案,除了他添加了一个使用密钥的优化