【问题标题】:Wrapping multiple identically named elements into a new element using XSLT使用 XSLT 将多个同名元素包装成一个新元素
【发布时间】:2014-02-06 15:14:39
【问题描述】:

我正在尝试使用 XSLT 重新格式化一些 XML。我输入的 sn-p 如下所示:

<toggles>
  <toggle toggleDisplayName="Charges">
    <anotherElement attribute="value" />
    <gridColumn sourceField.name="FIELD1" />
    <gridColumn sourceField.name="FIELD2" />
    <gridColumn sourceField.name="FIELD3" />
  </toggle>
</toggles>

我想将所有“gridColumn”元素包装成一个“网格”元素,如下所示:

<toggles>
  <toggle toggleDisplayName="Charges">
    <anotherElement attribute="value" />
    <grid>
      <gridColumn sourceField.name="FIELD1" />
      <gridColumn sourceField.name="FIELD2" />
      <gridColumn sourceField.name="FIELD3" />
    </grid>
  </toggle>
</toggles>

我当前的 XSLT 是:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:msxsl="urn:schemas-microsoft-com:xslt"
     exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>

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

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

现在这种工作,但我得到每个 'gridColumn' 元素在它自己的 'grid' 元素。是否有任何简单的方法可以修改它,以便我可以获得上述结果?

注意:已编辑以阐明输入 XML。

提前感谢您的帮助!

【问题讨论】:

  • &lt;toggle&gt; 创建一个模板,将&lt;grid&gt; 包裹在其子项周围。
  • 对不起,我的 XML 很长,所以可能我删掉了太多。 “toggle”下还有其他不是“gridColumns”的元素。您提出的方法会将“切换”的所有子元素包装到“网格”元素中,这不是我想要做的。
  • &lt;toggle&gt; 创建一个模板,将&lt;grid&gt; 包裹在其&lt;gridColumn&gt; 子代周围,然后在包含的&lt;xsl:apply-templates&gt; 中指定后者。或者澄清要求,如果我仍然误解你。
  • "toggle 下还有其他不是gridColumns 的元素" - 所有gridColumn 元素都相邻吗?如果不是,您是要将它们全部聚集到一个组中还是只将相邻的一组(这样您最终在输出中会得到多个grid)?

标签: xml xslt


【解决方案1】:

我能想到的最简单的变体,如果所有 gridColumn 元素在原始输入 XML 中都是相邻的(形成一个没有其他干预元素的连续块),则该变体有效:

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

  <xsl:template match="toggle">
    <xsl:copy>
      <!-- apply templates to everything except the second and subsequent
           gridColumn child elements -->
      <xsl:apply-templates select="@* | node()[not(self::gridColumn)]
                                      | gridColumn[1]" />
    </xsl:copy>
  </xsl:template>

  <!-- this template will be called for just the first gridColumn within
       a toggle... -->
  <xsl:template match="gridColumn">
    <grid>
      <!-- ... and will gather all its sibling gridColumn elements under the
           new grid element -->
      <xsl:copy-of select="../gridColumn" />
    </grid>
  </xsl:template>

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

如果gridColumn 元素不是全部相邻,您会发现它们都已在第一个 gridColumn 出现在输入 XML。

【讨论】:

  • 太棒了!我稍微调整了一下,因为我已经手动完成了一些,所以基本上我必须添加一个规则来复制现有的“网格”标签和子标签。否则你的工作完美。感谢大家的帮助!
【解决方案2】:

我想出了这个解决方案。请检查它是否满足您的所有要求。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes" />

  <!-- Process toggle separately, because its childredn cannot simply be copied -->
  <xsl:template match="toggle">
    <xsl:copy>
      <xsl:apply-templates select="./@*" /> <!-- For some unknown reason I needed this -->
      <xsl:apply-templates />
      <grid>
        <xsl:for-each select="gridColumn">
          <xsl:copy-of select="." />
        </xsl:for-each>
      </grid>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="gridColumn">
    <!-- Do nothing, because it is processed by for-each -->
  </xsl:template>

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

【讨论】:

  • 谢谢!我也调整了你的工作,我会支持它,但我的声誉还不够高。感谢您的回复!
猜你喜欢
  • 1970-01-01
  • 2017-03-23
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 2014-06-16
  • 1970-01-01
  • 2012-06-09
  • 2017-03-23
相关资源
最近更新 更多