XSLT:将属性从一个节点移动到现有节点[更新于23/7/14]

时间:2014-07-21 11:13:23

标签: xml xslt

我已经有一段时间了 - 已经让XSLT工作了,删除了不需要的节点和属性,但是其中有一部分让我失望。

我的想法是我有3个元素,每个元素有1个属性,我想将属性从第二个和第三个元素移动到第一个元素(并删除第二个和第三个元素)。

[Snippet 1]来自:

<info>
    <id name="Tim"/>
    <address addr="1 Witchwood Close"/>
    <phone num="01234 567 891"/>
</info>

[Snippet 2] To:

<info>
    <id name="Tim" addr="1 Witchwood Close" num="01234 567 891"/>
</info>

xslt目前(并且已经输出了如上所述的xml片段):

<xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:strip-space elements="*"/>

<!-- Identity Transform -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

<!-- remove 'fullname' node to promote sub-nodes -->
  <xsl:template match="fullname">
    <xsl:apply-templates"/>
  </xsl:template>

<!-- Promote 'phone' node to 'info' (from 'address' sub-node) -->
  <xsl:template match="address[phone]">
    <xsl:copy>
      <xsl:apply-templates select="node()[not(self::phone)]|@*"/>
    </xsl:copy>
    <xsl:apply-templates select="phone"/>
  </xsl:template>


<!-- Drop unwanted elements & attributes -->
  <xsl:template match="addressline2|addressline3|postcode|@middlename"/>

</xsl:stylesheet>

任何指针?

非常感谢

修改

包括来自Eero的XSLT片段,它似乎没有做任何事情(即我获得与[Snippet 1]中相同的XML),但是玩弄它:

  <xsl:template match="id">
    <xsl:copy>
      <xsl:apply-templates select="@* | following-sibling::*/>
    </xsl:copy>
  </xsl:template>

制备:

<info>
  <id name="Tim">
    <address addr="1 Witchwood Close"/>
    <phone num="01234 567 891"/>
  </id>
  <address addr="1 Witchwood Close"/>
  <phone num="01234 567 891"/>
</info?

如果将兄弟姐妹改为

following-sibling::*|@*

我得到了相同的结果。那么为什么下面的兄弟语句包含'/'而不是'|'没有进行任何改造?很明显我错过了一些简单的东西。

编辑2(包含解决方案)

我想我已经对它进行了分类。意识到我需要在XPath上生成(现在可能非常明显!)我真的不知道wtf是怎么回事,我想出了这个片段:

<xsl:template match="id">
  <xsl:copy>
    <xsl:apply-templates select="@name | following-sibling::*//@addr"/>
    <xsl:apply-templates select="@name | @addr | following-sibling::*//@num"/>
  </xsl:copy>
</xsl:template>

产生:

<info>
  <id name="Tim" addr="1 Witchwood Close" num="01234 567 891"/>
</info>

这正是我追求的!我认为这可能不是最强烈的优雅做事方式,但它似乎完成了工作......只有一个小例外。 偶尔,输出将是(没有明显的原因,为什么那个而不是另一个):

<info>
  <id name="Tim" addr="1 Witchwood Close" num="01234 567 891"/>
  <address addr="1 Witchwood Close"/>
</info>

尽管在复制后删除了节点。这不是一个大问题,因为SQL XML导入设置为仅导入由'id'标识的行上的字段,因此忽略'address'行。

我已将Eero的答案标记为“已接受”,因为这是我最终解决问题的方向,但我的代码实际上是丑陋的。欢迎评论如何减少对它的影响!

谢谢!

1 个答案:

答案 0 :(得分:1)

像这样的简单样式表可以解决这个问题:

样式表

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

  <xsl:strip-space elements="*"/>

  <xsl:template match="id">
    <xsl:copy>
      <!--
      Apply the attributes of the current node and the attributes of all
      following siblings (in this case, <address> and <phone>)
      -->
      <xsl:apply-templates select="@* | following-sibling::*/@*"/>
    </xsl:copy>
  </xsl:template>

  <!-- Drop the <address> and <phone> elements -->
  <xsl:template match="address | phone"/>

  <!--
  Identity transform: copy attributes and elements from input document to output
  document as is
  -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>