XSLT将一系列元素转换为单个列表?

时间:2009-06-03 11:03:26

标签: xslt

给出像这样的源文档:

<A>
  <B>
    <C>item1</C>
  </B>
  <B>
    <C>item2</C>
  </B>
  <B>
    <C>item3</C>
  </B>
</A>

我可以使用什么XSLT来产生这样的东西:

<A>
  <B>
    <C>item1</C>
    <C>item2</C>
    <C>item3</C>
  </B>
</A>

我试过一张表......

  <xsl:template match="B">
    <xsl:choose>
      <xsl:when test="count(preceding-sibling::B)=0">
        <B>
          <xsl:apply-templates select="./C"/>
          <xsl:apply-templates select="following-sibling::B"/>
        </B>
      </xsl:when>

      <xsl:otherwise>
          <xsl:apply-templates select="./C"/>
      </xsl:otherwise>

    </xsl:choose>
  </xsl:template>

但我得到......

<A>
  <B>
    <C>item1</C>
    <C>item2</C>
    <C>item3</C>
  </B>
  <C>item2</C>
  <C>item3</C>
</A>

第二个问题:我很难调试XSLT。提示?

4 个答案:

答案 0 :(得分:3)

最简单的方法:

<xsl:template match="/A">
  <A>
    <B>
      <xsl:copy-of select=".//C" />
    </B>
  </A>
</xsl:template>

回答这个问题,为什么你会看到你用XSLT看到的输出:

我猜你有一个

<xsl:apply-templates select="B" />

到位。这意味着:

  • <xsl:template match="B">被调用三次,每次<B>一次。
  • 对于第一个<B>,它会执行您想要的操作,有时会将其分支到<xsl:otherwise>,通过您可能拥有的<C>复制<xsl:template match="C"> 。这是您的额外<C>来自的地方。
  • 要修复它(不是我认可你的方法),你应该改变它......

...这样的:

<xsl:apply-templates select="B[1]" />

答案 1 :(得分:2)

您可以使用Altova XmlSpy或Visual Studio进行调试。以下xslt将给出所需的o / p。

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="A">
        <A>
            <B>
                <xsl:apply-templates/>
            </B>
        </A>
    </xsl:template>
    <xsl:template match="B">
        <xsl:copy-of select="C"/>
    </xsl:template>
</xsl:stylesheet>

如果上面的soln对你不起作用(我怀疑你正在处理一个更复杂的xml),你可能想在你的xml上发布更多的信息。

此外,如果需要,拥有B和C模板可以进一步扩展模板o / p。

答案 2 :(得分:1)

要回答你的第二个问题,我使用VS 2008 debugger,它就像一个魅力。

答案 3 :(得分:1)

此样式表合并了同级<B>元素,无论样式表中的位置或其他元素名称是什么。

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- By default, copy all nodes unchanged -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template> 

  <!-- Only copy the first B element -->
  <xsl:template match="B[1]">
    <xsl:copy>
      <!-- Merge the attributes and content of all sibling B elements -->
      <xsl:apply-templates select="../B/@* |
                                   ../B/node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- Don't copy the rest of the B elements -->
  <xsl:template match="B"/>

</xsl:stylesheet>

更新:

如果您希望结果打印得漂亮,并且输入文档中只有空格的文本节点无关紧要,那么您可以将其添加到样式表的顶部(作为<xsl:stylesheet>的子项):

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