【问题标题】:XPath Version SearchXPath 版本搜索
【发布时间】:2009-02-05 10:09:54
【问题描述】:

如何从以下文档中找到最高版本的节点:

<GateKeeperFiles>
  <File>
    <Name>GateKeeper.exe</Name>
    <Major>2</Major>
    <Minor>1</Minor>
    <Build>1</Build>
    <Revision>6</Revision>
  </File>
  <File>
    <Name>GateKeeper.exe</Name>
    <Major>1</Major>
    <Minor>1</Minor>
    <Build>1</Build>
    <Revision>9</Revision>
  </File>
</GateKeeperFiles>

理想情况下,这将通过单个 XPath 函数来实现。我目前有两个功能可以让我获得最大的主要价值,但我似乎无法从那里取得进展。

/GateKeeperFiles/File[not (Major <= preceding-sibling::File/Major) and not(Major <= following-sibling::File/Major)]

/GateKeeperFiles/File[not(/GateKeeperFiles/File/Major > Major)]

干杯, 史蒂夫

【问题讨论】:

  • 顺便说一句 - 您可能想检查您当前的方法是否正在执行数字(而不是字母)排序 - 即 v12

标签: c# .net xml xpath


【解决方案1】:

如果您使用的是 C#,它必须是 xpath 吗?例如(编辑以支持具有相同版本的多个文件 - 帖子提到复数):

        XDocument doc = XDocument.Parse(xml);
        var nodes =
            from file in doc.Document
                .Element("GateKeeperFiles")
                .Elements("File")
            select new {
                   Node = file,
                   Version = new Version(
                     (int) file.Element("Major"),
                     (int) file.Element("Minor"),
                     (int) file.Element("Build"),
                     (int) file.Element("Revision"))
                   } into tmp
                orderby tmp.Version descending
                select tmp;

        var mostRecentVersion = nodes.Select(x => x.Version).FirstOrDefault();
        var files = nodes.TakeWhile(x => x.Version == mostRecentVersion);

        foreach(var file in files) {
            Console.WriteLine("{0}: {1}",
                file.Version,
                (string)file.Node.Element("Name"));
        }

或使用 2.0(来自 OP 评论):

    static int GetVersion(XmlNode element, string xpath) {
        return int.Parse(element.SelectSingleNode(xpath).InnerText);
    }
    static void Main() {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xml);

        Version bestVersion = null;
        List<XmlElement> files = new List<XmlElement>();
        foreach (XmlElement file in doc.SelectNodes(
                 "/GateKeeperFiles/File")) {
            Version version = new Version(
                GetVersion(file, "Major"), GetVersion(file, "Minor"),
                GetVersion(file, "Build"), GetVersion(file, "Revision"));
            if (bestVersion == null || version > bestVersion) {
                bestVersion = version;
                files.Clear();
                files.Add(file);
            } else if (version == bestVersion) {
                files.Add(file);
            }
        }
        Console.WriteLine("Version: " + bestVersion);
        foreach (XmlElement file in files) {
            Console.WriteLine(file.SelectSingleNode("Name").InnerText);
        }
    }

【讨论】:

    【解决方案2】:

    我使用 xsl:sort 来实现类似的东西。不记得确切的语法,但试试这个

    在此之后选择第一个或最后一个元素。我忘记了升序或降序排序的默认行为是什么,但您可以使用 xsl:sort 覆盖它。

    【讨论】:

    • OP 没有提到 xslt,但这可能是一个选项。默认是升序,顺便说一句。
    【解决方案3】:

    代码应该能够在 .Net 2.0 上运行,因此 LINQ 解决方案虽然正确但不适合 scinario。

    我在代码中处理 XML 并且不执行转换,所以 XSLT 也不适合。

    干杯

    【讨论】:

    • 编辑为包含 2.0 版本
    • XSLT 也是“代码”——调整您的手表!您听说过标准的 .NET 类 XslCompiledTransform 吗?您是否知道 XSLT 是处理 XML 的最佳选择,因为 XSLT 语言是专门为处理 XML 和树状结构数据而设计的?睁大你的眼睛,不要做自虐狂
    【解决方案4】:

    我有一个与您的 .Net 2.0 类似的解决方案,我只是希望有一个干净整洁的 XPath 版本。看起来这是 XPath 无法解决的另一个领域(如位运算符)。

    干杯

    【讨论】:

    • 这可以在单个 XPath 表达式中完成,但如果 XPath 引擎没有以良好的方式优化,它看起来并不漂亮并且可能效率很低。
    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 2012-01-25
    • 2014-07-12
    • 2017-03-29
    • 1970-01-01
    相关资源
    最近更新 更多