1

我有以下 XML:

<root>
  <nodeLevel1>
    <nodeType1>node type 1</nodeType1>
    <nodeType2><rank>3</rank></nodeType2>
    <nodeType2><rank>1</rank></nodeType2>
    <nodeType2><rank>4</rank></nodeType2>
    <nodeType2><rank>2</rank></nodeType2>
    <nodeType3>node type 3</nodeType3>
  </nodeLevel1>
</root>

我使用以下 XSLT 对该 XML 进行排序:

<?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="no" indent="yes" media-type="text/html"/>

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

      <xsl:template match="nodeLevel1">
          <xsl:copy>
            <xsl:apply-templates select="node()|@*">
              <xsl:sort select="rank" data-type="number" />
            </xsl:apply-templates>
          </xsl:copy>
      </xsl:template>

      </xsl:stylesheet>

结果是:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <nodeLevel1>
    <nodeType1>node type 1</nodeType1>
    <nodeType3>node type 3</nodeType3>
    <nodeType2>
        <rank>1</rank>
    </nodeType2>
    <nodeType2>
        <rank>2</rank>
    </nodeType2>
    <nodeType2>
        <rank>3</rank>
    </nodeType2>
    <nodeType2>
        <rank>4</rank>
    </nodeType2>
</nodeLevel1>
</root>

问题是所有“nodeType2”都不在我的 XML 中的正确位置。如何在“nodeType2”之前保留节点“nodeType1”,在“nodeType2”之后保留节点“nodeType3”。(解决方案不能使用元素名称“nodeType1”或“nodeType3”,因为它可以重命名为任何名称)

所以,结果应该是:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <nodeLevel1>
    <nodeType1>node type 1</nodeType1>
    <nodeType2>
        <rank>1</rank>
    </nodeType2>
    <nodeType2>
        <rank>2</rank>
    </nodeType2>
    <nodeType2>
        <rank>3</rank>
    </nodeType2>
    <nodeType2>
        <rank>4</rank>
    </nodeType2>
    <nodeType3>node type 3</nodeType3>
</nodeLevel1>
</root>

谢谢你的帮助。

4

2 回答 2

0

此转换适用于任何元素名称(没有名称是硬编码的)并且效率很高,因为它使用键来识别组

<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="kSameNamed" match="nodeLevel1/*" use=
  "generate-id(preceding-sibling::*[not(name()=name(current()))][1])"/>

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

 <xsl:template match="nodeLevel1">
  <nodeLevel1>
   <xsl:apply-templates select=
   "*[not(name() = name(preceding-sibling::*[1]))]"/>
  </nodeLevel1>
 </xsl:template>

 <xsl:template match="nodeLevel1/*">
  <xsl:for-each select="key('kSameNamed', generate-id(preceding-sibling::*[1]))">
   <xsl:sort select="rank" data-type="number"/>
   <xsl:copy-of select="."/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<root>
  <nodeLevel1>
    <nodeType1>node type 1</nodeType1>
    <nodeType2><rank>3</rank></nodeType2>
    <nodeType2><rank>1</rank></nodeType2>
    <nodeType2><rank>4</rank></nodeType2>
    <nodeType2><rank>2</rank></nodeType2>
    <nodeType3>node type 3</nodeType3>
  </nodeLevel1>
</root>

产生了想要的正确结果:

<root>
   <nodeLevel1>
      <nodeType1>node type 1</nodeType1>
      <nodeType2>
         <rank>1</rank>
      </nodeType2>
      <nodeType2>
         <rank>2</rank>
      </nodeType2>
      <nodeType2>
         <rank>3</rank>
      </nodeType2>
      <nodeType2>
         <rank>4</rank>
      </nodeType2>
      <nodeType3>node type 3</nodeType3>
   </nodeLevel1>
</root>

如果我们现在将相同的转换应用于完全不同的 XML 文档:

<r>
  <nodeLevel1>
    <X1>node type 1</X1>
    <Y2><rank>3</rank></Y2>
    <Y2><rank>1</rank></Y2>
    <Y2><rank>4</rank></Y2>
    <Y2><rank>2</rank></Y2>
    <Z3>node type 3</Z3>
    <A4><rank>8</rank></A4>
    <A4><rank>2</rank></A4>
    <A4><rank>9</rank></A4>
    <A4><rank>3</rank></A4>
    <B5><rank>8</rank></B5>
    <B5><rank>2</rank></B5>
    <B5><rank>9</rank></B5>
    <B5><rank>3</rank></B5>
    <C7>Node of Type C7</C7>
  </nodeLevel1>
</r>

我们再次得到正确的结果:

<r>
   <nodeLevel1>
      <X1>node type 1</X1>
      <Y2>
         <rank>1</rank>
      </Y2>
      <Y2>
         <rank>2</rank>
      </Y2>
      <Y2>
         <rank>3</rank>
      </Y2>
      <Y2>
         <rank>4</rank>
      </Y2>
      <Z3>node type 3</Z3>
      <A4>
         <rank>2</rank>
      </A4>
      <A4>
         <rank>3</rank>
      </A4>
      <A4>
         <rank>8</rank>
      </A4>
      <A4>
         <rank>9</rank>
      </A4>
      <B5>
         <rank>2</rank>
      </B5>
      <B5>
         <rank>3</rank>
      </B5>
      <B5>
         <rank>8</rank>
      </B5>
      <B5>
         <rank>9</rank>
      </B5>
      <C7>Node of Type C7</C7>
   </nodeLevel1>
</r>
于 2013-04-13T03:16:08.170 回答
0

一种方法是使用与第一个nodeType2元素匹配的模板

<xsl:template match="nodeType2[1]">

在此,您选择并排序所有 nodeType2 元素

<xsl:for-each select="self::*|following-sibling::nodeType2">
   <xsl:sort select="rank" data-type="number" />
    <!-- Copy element -->
    <xsl:call-template name="identity" />
 </xsl:for-each>

您唯一需要的另一件事是另一个模板来阻止其他nodeType2元素被输出两次

<xsl:template match="nodeType2" />

这是完整的 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="no" indent="yes" media-type="text/html"/>

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

      <xsl:template match="nodeType2[1]">
          <xsl:for-each select="self::*|following-sibling::nodeType2">
              <xsl:sort select="rank" data-type="number" />
              <xsl:call-template name="identity" />
            </xsl:for-each>
      </xsl:template>

       <xsl:template match="nodeType2" />
 </xsl:stylesheet>

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

<root>
   <nodeLevel1>
      <nodeType1>node type 1</nodeType1>
      <nodeType2>
         <rank>1</rank>
      </nodeType2>
      <nodeType2>
         <rank>2</rank>
      </nodeType2>
      <nodeType2>
         <rank>3</rank>
      </nodeType2>
      <nodeType2>
         <rank>4</rank>
      </nodeType2>
      <nodeType3>node type 3</nodeType3>
   </nodeLevel1>
</root>
于 2013-04-12T20:03:00.547 回答