如何使用 XSLT 创建一组元素的子集? [英] How to create subsets of a single set of elements with XSLT?

查看:27
本文介绍了如何使用 XSLT 创建一组元素的子集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 xml 格式:

I have an xml of the form:

<Set>
   <Element name="Superset1_Set1_Element1"/>
   <Element name="Superset1_Set1_Element2"/>
   <Element name="Superset1_Set2_Element1"/>
   <Element name="Superset2_Set1_Element1"/>
   <Element name="Superset2_Set2_Element1"/>
</Set>

我希望将其转换为以下形式的 xml:

I wish to transform it to an xml of the form:

<Superset name="Superset1">
   <Set name="Set1">
       <Element name="Element1"/>
       <Element name="Element2"/>
   </Set>
   <Set name="Set2">
       <Element name="Element1"/>
   </Set>
</Superset>
<Superset name="Superset2">
   <Set name="Set1">
       <Element name="Element1"/>
   </Set>
   <Set name="Set2">
       <Element name="Element1"/>
   </Set>
</Superset>

如何使用 XSLT 做到这一点?

How can this be done with XSLT?

非常感谢!

推荐答案

这可以通过以下 XSLT 1.0 转换来解决:

This can be solved with the following XSLT 1.0 transformation:

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

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

  <!-- this key selects elements by their "Superset" name -->
  <xsl:key name="kElementBySuperset" match="Element" use="
    substring-before(@name, '_')" 
  />

  <!-- this key selects elements by their "Superset_Set" name -->
  <xsl:key name="kElementBySet" match="Element" use="
    concat(
      substring-before(@name, '_'), 
      '_',
      substring-before(substring-after(@name, '_'), '_')
    )
  " />

  <!--- initalize output (note the template modes) -->
  <xsl:template match="Set">
    <xsl:apply-templates select="Element" mode="Superset">
      <xsl:sort select="@name" />
    </xsl:apply-templates>
  </xsl:template>

  <!-- output <Superset> elements, grouped by name -->
  <xsl:template match="Element" mode="Superset">
    <xsl:variable name="vSupersetName" select="
      substring-before(@name, '_')
    " />

    <xsl:if test="
      generate-id() 
      = 
      generate-id(key('kElementBySuperset', $vSupersetName)[1])
    ">
      <Superset name="{$vSupersetName}">
        <xsl:apply-templates 
          select="key('kElementBySuperset', $vSupersetName)" 
          mode="Set"
        >
          <xsl:sort select="@name" />
        </xsl:apply-templates>
      </Superset>
    </xsl:if>
  </xsl:template>

  <!-- output <Set> elements, grouped by name -->
  <xsl:template match="Element" mode="Set">
    <xsl:variable name="vSetName" select="
      concat(
        substring-before(@name, '_'), 
        '_',
        substring-before(substring-after(@name, '_'), '_')
      )"
    />

    <xsl:if test="
      generate-id() 
      = 
      generate-id(key('kElementBySet', $vSetName)[1])
    ">
      <Set name="{substring-after($vSetName, '_')}">
        <xsl:apply-templates 
          select="key('kElementBySet', $vSetName)" 
          mode="Element"
        >
          <xsl:sort select="@name" />
        </xsl:apply-templates>
      </Set>
    </xsl:if>
  </xsl:template>

  <!-- output <Element> elements -->
  <xsl:template match="Element" mode="Element">
    <xsl:variable name="vElementName" select="
      substring-after(
        substring-after(@name, '_'), 
        '_'
      )
    " />

    <Element name="{$vElementName}" />
  </xsl:template>

</xsl:stylesheet>

应用于您的输入文档时在我的系统上的输出:

Output on my system when applied to your input document:

<Superset name="Superset1">
  <Set name="Set1">
    <Element name="Element1" />
    <Element name="Element2" />
  </Set>
  <Set name="Set2">
    <Element name="Element1" />
  </Set>
</Superset>
<Superset name="Superset2">
  <Set name="Set1">
    <Element name="Element1" />
  </Set>
  <Set name="Set2">
    <Element name="Element1" />
  </Set>
</Superset>

值得注意的是,此解决方案区分大小写.我认为在您的情况下这是可取的(或至少无害).如果需要不区分大小写,那么就需要撒上一些(其中..."当然必须用缺失的字母替换):

It is worth noting that this solution is case-sensitive. I assume that is desirable (or at least not harmful) in your case. If case-insensitivity is required, then sprinkling a handful of these would become necessary (where "…" must of course be replaced by the missing letters):

translate($anyvalue, 'ABC…XYZ', 'abc…xyz')

我避免这样做,因为它非常重复并且使解决方案(甚至更多)变得晦涩难懂.

I avoided that because it is very repetitive and makes the solution (even more) obscure.

进一步阅读:我使用两个 <xsl:key> 进行类似的两步分组的解决方案之一在这里:

Further reading: One of my solutions that does a similar two-step grouping using two <xsl:key>s is here:

XSLT 3 级属性分组

它的内部结构有点冗长,其中包含对 的冗长解释,我想避免在此重复.;-)

It is a bit more verbose on the internals, and it contains a lengthy explanation of <xsl:key> that I'd like to avoid repeating here. ;-)

这篇关于如何使用 XSLT 创建一组元素的子集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆