2

此平面 XML 表示使用级别字段的树结构。如何将树中较深的元素获取到给定节点但仅在同一分支中?

因此,鉴于公司名称是 A,我需要获得公司 B 和 C(不是位于不同分支机构的 E)。

<Companies>
      <Company>
        <Name>A</Name>
        <Level>0</Level>
      </Company>
      <Company>
        <Name>B</Name>
        <Level>1</Level>
      </Company>
      <Company>
        <Name>C</Name>
        <Level>1</Level>
      </Company>
      <Company>
        <Name>D</Name>
        <Level>0</Level>
      </Company>
      <Company>
        <Name>E</Name>
        <Level>1</Level>
      </Company>
    </Companies>

可以有不止一级。我也想退货。我正在使用 XLST 1.0。

4

4 回答 4

2

使用

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

 <xsl:key name="kDescendants" match="Company[Level > 0]"
  use="generate-id(preceding-sibling::Company[Level=0][1])"/>

 <xsl:template match="/">
     <xsl:copy-of select="key('kDescendants', generate-id(/*/*[Name='A']))"/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<Companies>
    <Company>
        <Name>A</Name>
        <Level>0</Level>
    </Company>
    <Company>
        <Name>B</Name>
        <Level>1</Level>
    </Company>
    <Company>
        <Name>C</Name>
        <Level>1</Level>
    </Company>
    <Company>
        <Name>D</Name>
        <Level>0</Level>
    </Company>
    <Company>
        <Name>E</Name>
        <Level>1</Level>
    </Company>
</Companies>

产生了想要的正确结果

<Company>
   <Name>B</Name>
   <Level>1</Level>
</Company>
<Company>
   <Name>C</Name>
   <Level>1</Level>
</Company>

说明

"kDescendants"定义树中的顶部节点与其后代之间的映射 - 给定generate-id($someTopNode),它会在以 为顶部的(逻辑)树中生成所有后代$someTopNode

于 2012-10-17T13:55:15.227 回答
1

在 XSLT1.0 中实现此目的的一种方法是定义一个键,该键按具有较低级别的最前面的兄弟元素对元素进行分组

<xsl:key 
   name="companies" 
   match="Company" 
   use="generate-id(preceding-sibling::Company[Level &lt; current()/Level][1])" />

然后,假设您定位在您想要较低级别的特定公司元素上,您可以这样做

这将首先获得下一个级别的元素。要获得后续级别,您需要一个模板来匹配公司元素,复制它们并递归应用模板

<xsl:template match="Company">
   <Company>
     <xsl:apply-templates select="@*|node()"/>
   </Company>
   <xsl:apply-templates select="key('companies', generate-id())" />
</xsl:template>

这是完整的 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="companies" match="Company" use="generate-id(preceding-sibling::Company[Level &lt; current()/Level][1])" />

   <xsl:template match="/Companies">
      <xsl:apply-templates select="Company[Name='A']" mode="parent" />
   </xsl:template>

   <xsl:template match="Company" mode="parent">
      <xsl:apply-templates select="key('companies', generate-id())" />
   </xsl:template>

   <xsl:template match="Company">
      <Company>
         <xsl:apply-templates select="@*|node()"/>
      </Company>
      <xsl:apply-templates select="key('companies', generate-id())" />
   </xsl:template>

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

应用于您的示例 XML 时,将输出以下内容

<Company>
   <Name>B</Name>
   <Level>1</Level>
</Company>
<Company>
   <Name>C</Name>
   <Level>1</Level>
</Company>
于 2012-10-17T12:49:32.367 回答
0

假设焦点节点 (current()) 是您计算的基础。

定义...

<xsl:variable name="set1" select="following-sibling::Company[ Level &gt; current()]" />
<xsl:variable name="set2" select="following-sibling::Company[ Level &lt; 
      preceding-sibling::Company[1]/Level][1]/preceding-sibling::Company" />

那么子公司就在这两组的交汇处,也就是……

$set1[. = $set2]
于 2012-10-17T12:48:07.343 回答
0

这是我的尝试 - 但我相信有更简单的方法......抱歉:它只是 XSLT 2.0。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/Companies">
        <xsl:param name="nodeName" select="'A'" />

        <xsl:variable name="level" select="Company[Name = $nodeName]/Level/text()" as="xs:int"/>
        <xsl:variable name="seq" as="node()*" select="Company[Name = $nodeName]/following-sibling::*" />
        <xsl:variable name="levels" as="xs:int*" select="$seq/Level/text()" />
        <xsl:copy-of select="subsequence($seq, 0, index-of($levels, $level)[1])" />
    </xsl:template>
</xsl:stylesheet>
于 2012-10-17T13:32:09.150 回答