使用XSL和多层次结构排序(嵌套)XML

时间:2014-09-15 10:19:58

标签: c# xml sorting xslt treeview

我确实有一个我想用xsl排序的treeview xml,但似乎我错过了一些东西:

我的xml的结构是这样的:

<treeview>
  <treenode>
    <caption>Directory Z</caption>
    <nodes>
      <treenode>
        <caption>File B</caption>
      </treenode>
      <treenode>
        <caption>File Z</caption>
      </treenode>
      <treenode>
        <caption>File A</caption>
      </treenode>
    </nodes>
  </treenode>
  <treenode>
    <caption>Directory G</caption>
    <nodes>
      <treenode>
        <caption>File F</caption>
      </treenode>
      <treenode>
        <caption>File O</caption>
      </treenode>
      <treenode>
        <caption>File B</caption>
      </treenode>
    </nodes>
  </treenode>
</treeview>

我尝试了以下xsl来执行排序:

<?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" indent="yes" />
  <xsl:template match="/*">
    <treeview>
      <xsl:apply-templates select="treenode">
        <xsl:sort select="caption" data-type="text" order="ascending"/>
        <xsl:sort/>
      </xsl:apply-templates>
    </treeview>
  </xsl:template>
  <xsl:template match="treenode">
    <xsl:copy-of select="."/>
    <xsl:apply-templates select="nodes/treenode">
      <xsl:sort select="caption" data-type="text" order="descending"/>
      <xsl:sort/>
    </xsl:apply-templates>
  </xsl:template>
</xsl:stylesheet>

我最终将文件添加到根节点,但我希望目录按升序排序,每个目录中的文件都会降序。

感谢您的帮助:)

3 个答案:

答案 0 :(得分:1)

您的代码中有一些导致该行为的事情:

  • 您只有一个与所有<treenode>元素匹配的模板,使用mode属性将其拆分更容易
  • 您正在输出节点的副本

以下是修改后的版本:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
    <xsl:template match="/">
        <treeview>
            <xsl:apply-templates select="/treeview/treenode" mode="dir">
                <xsl:sort select="caption" data-type="text" order="ascending"/>
            </xsl:apply-templates>
        </treeview>
    </xsl:template>
    <xsl:template match="treenode" mode="dir">
        <treenode>
            <caption><xsl:value-of select="caption"/></caption>
            <node>
                <xsl:apply-templates select="./nodes/treenode" mode="file">
                    <xsl:sort select="caption" data-type="text" order="descending"/>
                </xsl:apply-templates>
            </node>
        </treenode>
    </xsl:template>
    <xsl:template match="treenode" mode="file">
        <caption><xsl:value-of select="caption"/></caption>
    </xsl:template>
</xsl:stylesheet>

输出:

<?xml version="1.0" encoding="utf-8"?>
<treeview>
  <dir>
    <name>Directory G</name>
    <file>File O</file>
    <file>File F</file>
    <file>File B</file>
  </dir>
  <dir>
    <name>Directory Z</name>
    <file>File Z</file>
    <file>File B</file>
    <file>File A</file>
  </dir>
</treeview>

答案 1 :(得分:0)

试试这个:

<xsl:template match="/*">
    <treeview>
      <xsl:apply-templates select="treenode" mode="levelone">
        <xsl:sort select="caption" data-type="text" order="ascending"/>
      </xsl:apply-templates>
    </treeview>
  </xsl:template>
  <xsl:template match="treenode" mode="levelone">
    <treenode>
      <caption>
        <xsl:value-of select="caption" />
      </caption>
      <xsl:apply-templates select="nodes"/>
    </treenode>
  </xsl:template>
  <xsl:template match="nodes">
    <node>
      <xsl:apply-templates select="treenode" mode="leveltwo">
        <xsl:sort select="caption" order="descending"/>
      </xsl:apply-templates>
    </node>
  </xsl:template>
  <xsl:template match="treenode" mode="leveltwo">    
      <caption>
        <xsl:value-of select="caption" />
      </caption>
      <xsl:apply-templates select="nodes"/>    
  </xsl:template>

输出:

    <treeview>
  <treenode>
    <caption>Directory G</caption>
    <node>
      <caption>File O</caption>
      <caption>File F</caption>
      <caption>File B</caption>
    </node>
  </treenode>
  <treenode>
    <caption>Directory Z</caption>
    <node>
      <caption>File Z</caption>
      <caption>File B</caption>
      <caption>File A</caption>
    </node>
  </treenode>
</treeview>

答案 2 :(得分:0)

我现在的解决方案是创建一个递归函数,我在其中加载子节点和xsl转换每个“节点”:

public void main()
{
    // [...]
    ProcessXsltSort(MyXmlDocument.DocumentElement);
}

// untested since i'm not coding directly in c# dotnet
private static void ProcessXsltSort(XmlNode nodes)
{
    // "nodes" into XmlReader
    StringReader documentStringReader = new StringReader(nodes.OuterXml);
    XmlReader documentXmlReader = XmlReader.Create(documentStringReader);

    // xsl into XmlReader
    StringReader stylesheetStringReader = new StringReader(XsltSortingString());
    XmlReader stylesheetXmlReader = XmlReader.Create(stylesheetStringReader);

    // output
    StringBuilder outputBuilder = new StringBuilder();
    XmlWriter outputXmlWriter = XmlWriter.Create(outputBuilder);

    // transform
    XlsCompiledTransform transformer = new XslCompiledTransform();
    transformer.Load(stylesheetXmlReader);
    transformer.Transform(documentXmlReader,outputXmlWriter);

    // write output back
    XmlDocument transformedXmlDocument = new XmlDocument();
    transformedXmlDocument.LoadXml(outputBuilder.ToString());
    nodes.InnerXml = transformedXmlDocument.DocumentElement.InnerXml;

    // recursive loop
    foreach (XmlNode subnodes in nodes.SelectNodes("treenode/nodes"))
    {
        ProcessXsltSort(subnodes);
    }
}

和XsltSortingString()使用以下xsl:

<?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" indent="yes" />
  <xsl:template match="/">
    <nodes>
      <xsl:apply-templates select="/*/treenode">
        <xsl:sort select="caption" data-type="text" order="ascdending"/>
      </xsl:apply-templates>
    </nodes>
  </xsl:template>
  <xsl:template match="treenode">
    <xsl:copy-of select="."/>
  </xsl:template>
</xsl:stylesheet>