1

我对 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>

所需的 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 知识不是很好。

4

2 回答 2

2

我不是 100% 确定您希望 XSLT 如何从该输入中确定顶部 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>

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

于 2013-02-09T21:28:38.597 回答
0

啊,看了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 的解决方案,只是他添加了使用键的优化。

于 2013-02-10T00:06:21.093 回答