【问题标题】:not able to group element with same name无法对具有相同名称的元素进行分组
【发布时间】:2015-02-04 13:49:17
【问题描述】:

我是 xslt 的新手,请帮忙以便为以下 xml 模式编写 xsl。 我想将具有相同名称的元素分组在一个标签下。可以有多个具有相同名称的元素,例如 Shapes、Devices 等。

<?xml version="1.0"?>
<Screen>
  <Shapes>
    <Triangle id="tri1">
    <color>red</color>
    <size>large</size>
    </Triangle>
  </Shapes>
  <Shapes>
    <Rectangle id="rec1">
      <color>blue</color>
      <size>medium</size>
    </Rectangle>
  </Shapes>
  <Device>
    <Name>peg</Name>
    <type>X11</type>
  </Device>
  <Device>
    <Name>peg1222</Name>
    <type>X11111</type>
  </Device>
  <Utilities>
    <Software>QT</Software>
    <Platform>Linux</Platform>
  </Utilities>
</Screen>

上面的xml文件,我用的是下面的xsl文件

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

  <xsl:output method="xml" indent="yes"/>

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

  <xsl:template match="/*">
    <xsl:copy>
      <Shapes>
        <xsl:copy-of select="Shapes/*"/>
      </Shapes>
      <xsl:apply-templates select="*[name()!='Shapes']"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

输出为

<?xml version="1.0" encoding="UTF-8"?>
<Screen>
    <Shapes>
        <Triangle id="tri1">
    <color>red</color>
    <size>large</size>
    </Triangle>
        <Rectangle id="rec1">
      <color>blue</color>
      <size>medium</size>
    </Rectangle>
    </Shapes>
    <Device>
    <Name>peg</Name>
    <type>X11</type>
  </Device>
    <Device>
    <Name>peg1222</Name>
    <type>X11111</type>
  </Device>
    <Utilities>
    <Software>QT</Software>
    <Platform>Linux</Platform>
  </Utilities>
</Screen>

但它仅基于形状进行分组,我不知道有多少元素在 XML 中重复(我们可能会得到另一个重复的元素)。

请让我知道我们是否可以修改上面的 xsl 以适应具有相同名称的动态元素出现的 xml。

【问题讨论】:

    标签: xml xslt xslt-1.0


    【解决方案1】:

    你可以使用这样的东西,它使用一个键来匹配Screen的子元素,根据他们的名字并将他们的孩子分组在单亲下:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:key name="elements" match="/Screen/*" use="name()"/>
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/*">
        <xsl:copy>
            <xsl:for-each select="*[count(. | key('elements', name())[1]) = 1]">
                <xsl:copy>
                    <xsl:apply-templates select="key('elements', name())/*"/>
                </xsl:copy>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 使用密钥是一个好方法。不过,我不清楚Device 元素会发生什么。 @Ravi 应该澄清这一点。 (顺便说一句,我很高兴看到您的 XSLT 技能不断提高!)
    • @Lingamurthy,我和上面提到的 Mathias 有同样的疑问。
    • @RudramuniTP 明确地说,我并不是说 Lingamurthy 的代码有问题。我是说 OP 没有足够清楚地说明Device 元素应该发生什么。
    • @MathiasMüller 感谢您的夸奖。你是对的,我们需要更多地澄清预期。我假设这个解决方案是因为 Ravi 的以下声明 我想将具有相同名称的元素分组到一个标签下
    猜你喜欢
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 1970-01-01
    • 2017-04-03
    相关资源
    最近更新 更多