如何在封闭元素下组织(分组)节点 - XSLT

Posted

技术标签:

【中文标题】如何在封闭元素下组织(分组)节点 - XSLT【英文标题】:How to organize(group) nodes under a closed element - XSLT 【发布时间】:2013-05-14 21:11:02 【问题描述】:

我尝试过使用 XSLT 1.0 对 XML 进行简单的分组,并且成功了,但在这里我遇到了一些更复杂且实际上不同的情况。 所以XML结构基本上是这样的:

<Main>
 <TB>
    --> some elements and stuff - not relevant
   <City>
     <Area>
       <Position>5</Position>
       <House>

       --> some elements and stuff

       </House>
     </Area>
     <Area>
       <Position>5</Position>
       <Block>

       --> some elements and stuff

       </Block>
     </Area>
     <Area>
       <Position>6</Position>
       <House>

       --> some elements and stuff

       </House>
     </Area>
     <Area>
       <Position>6</Position>
       <Block>

       --> some elements and stuff

       </Block>
     </Area>
   </City>
   <City>

   --> same structure but with several repetitions of Position 7 and 8.

   </City>
 </TB>
</Main>

我需要将位于同一位置的Blocks 和Houses 分组,并删除重复的位置编号。例如它会变成这样:

   <City>
     <Area>
       <Position>5</Position>
       <House>

       --> some elements and stuff

       </House>
       <Block>

       --> some elements and stuff

       </Block>
     </Area>
     <Area>
       <Position>6</Position>
       <House>

       --> some elements and stuff

       </House>
       <Block>

       --> some elements and stuff

       </Block>
     </Area>
   </City>
   <City>

   --> same structure for Position 7 and 8.

   </City>

比较难,因为Position不是Area的一个属性,所以我基本上要确定Area的Position的值,然后抓取同一个Position下的House和Block,放在一起被包围相同的&lt;Area&gt; &lt;/Area&gt;

【问题讨论】:

【参考方案1】:

在我看来,这似乎是一个相当标准的 Muenchian 分组问题,将 Area 元素(不是直接 HouseBlock 元素)按 Position 分组。

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

  <xsl:key name="areaByPosition" match="Area" use="Position" />

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

  <!-- for the first Area in each Position -->
  <xsl:template match="Area[generate-id() =
                            generate-id(key('areaByPosition', Position)[1])]">
    <Area>
      <!-- copy in the Position element once only -->
      <xsl:apply-templates select="Position" />
      <!-- copy in all sub-elements except Position from all matching Areas -->
      <xsl:apply-templates select="
            key('areaByPosition', Position)/*[not(self::Position)]" />
    </Area>
  </xsl:template>

  <!-- ignore all other Area elements -->
  <xsl:template match="Area" />
</xsl:stylesheet>

这假设文档中的其他地方没有其他名为Area的元素,如果任何“一些元素和东西”可能被命名为Area,那么你需要更具体一点,例如限制分组到作为City 的直接子级的Area 元素:

<xsl:key name="areaByPosition" match="City/Area" use="Position" />

<xsl:template match="City/Area[generate-id() =
                               generate-id(key('areaByPosition', Position)[1])]"
              priority="2">
  ...
</xsl:template>

<xsl:template match="City/Area" priority="1" />

(有明确的优先级,因为没有它,两个模板将具有相同的default priority 0.5)

【讨论】:

这工作得很好,直到我真正找到了不允许的东西。例如我有&lt;City A&gt;&lt;Area&gt;&lt;Position&gt;5&lt;/Position&gt;... bla bla&lt;///&gt; 然后我在&lt;City B&gt; 有相同的位置5 它从B 市获取位置5 下的元素并将它们排列在A 市的位置5 的元素下。我希望它订购房屋和街区,但留在同一个城市。 @Syspect 如果您想通过 Position 和包含 City 的名称对 Area 元素进行分组,您需要在分组键定义中包含相关内容,例如 @987654337 @ 和分组谓词,如 key('areaByPosition', concat(../@name, '|', Position)[1]

以上是关于如何在封闭元素下组织(分组)节点 - XSLT的主要内容,如果未能解决你的问题,请参考以下文章

如何在 XSLT 中对值进行分组和求和

在 XSLT 中对每个父节点下的子节点进行分组

使用父元素在 XSLT 中拆分/分组

XSLT / Muenchian 分组:如何从组中选择具有某些子元素的元素?

XSLT muenchian 在子节点中按值分组

XSLT:将分组 html 元素移动到部分级别