【问题标题】:Retrieving XML value in C# from arbitary key path从任意键路径检索 C# 中的 XML 值
【发布时间】:2018-08-29 01:19:17
【问题描述】:

我有一个项目,我目前正在实现对通过文档键中的任意/用户定义路径从 XML 文件读取值的支持。

例如,如果文档如下所示:

<information>
    <machine>
        <foo></foo>
        <name>
            test machine
        </name>
        <bar>spam</bar>
    </machine>
</information>

那么用户可能想要从information/machine 中的name 键中检索值。

有没有一种方法可以使用XDocument/XPath 来查找用户想要的值,而无需知道/在文档架构中进行编码?

我最初的想法是通过使用XElement 项目的递归函数形式来处理文档,但我觉得应该有一个更简单/更清洁的解决方案,不需要我滚动自己的查找代码。

我也尝试过类似的方法

var doc = XDocument.Load("C:\Path\to\XML\file.xml");

// Split the parent keys string
XElement elem = doc.Root.XPathSelectElement("path/to/key");
if (elem != null && elem.Attribute("wantedKeyName") != null)
    replace = elem.Attribute("wantedKeyName").Value;

elem 始终为空。我假设我定义路径或使用 XPathSelectElement 的方式存在问题,但我还没有解决。

【问题讨论】:

  • XDocument doc = XDocument.Load("YOURXML.xml"); var q = from elements in doc.Elements("information").Elements("machine") 选择元素; foreach (var item in q) { string str = item.Element("name").Value;}
  • @ershoaib 如果我事先知道 XML 文件的架构,我会这样做,但程序必须能够处理任何 XML 文件和其中的任何路径,而不知道内容.
  • 如果您不知道文件的内容,如何使用 XPathSelectElement("path/to/key") ?在这种情况下,您不知道路径
  • @RPiAwesomeness 可能您的实际 XML 包含默认命名空间(名为 xmlns 的“属性”,如 xmlns="some-namespace-uri-here")。如果是这种情况,请参阅:Use XPath with XML namespace
  • 使用后代:List elements = doc.Descendants("name").ToList();

标签: c# xml xpath linq-to-xml


【解决方案1】:
static XmlNode SearchNode(XmlNodeList nodeList, string nodeName)
{
    for (int i = 0; i < nodeList.Count; i++)
    {
        if (nodeList[i].Name == nodeName)
        {
            return nodeList[i];
        }

        if (nodeList[i].HasChildNodes)
        {
            XmlNode node = SearchNode(nodeList[i].ChildNodes, nodeName);
            if (node != null)
            {
                return node;
            }
        }
    }

    return null;
}

static XmlNodeList SearchNodeByPath(XmlNodeList nodeList, string xPath)
{
    for (int i = 0; i < nodeList.Count; i++)
    {
        var nodes = nodeList[i].SelectNodes(xPath);
        if (nodes != null && nodes.Count > 0)
        {
            return nodes;
        }

        if (nodeList[i].HasChildNodes)
        {
            XmlNodeList innerNodes = SearchNodeByPath(nodeList[i].ChildNodes, xPath);
            if (innerNodes != null && innerNodes.Count > 0)
            {
                return innerNodes;
            }
        }
    }

    return null;
}

这是使用方法:

    var node = SearchNode(doc.ChildNodes, "compiler");
    var node1 = SearchNodeByPath(doc.ChildNodes, "compilers/compiler");

【讨论】:

    【解决方案2】:

    我发现使用XPathSelectElement 的解决方案是正确的方法,我只需要在path/to/key 字符串前面加上//

    我最终使用的以下代码会执行此操作,并去除值外部的所有空格(以防值与开始标记位于不同的行。

    // xml is a struct with the path to the parent node (path/to/key)
    // and the key name to look up
    // Split the parent keys string
    XElement elem = doc.Root.XPathSelectElement("//" + xml.KeyPath);
    if (elem != null && elem.Element(xml.Key) != null)
        replace = elem.Element(xml.Key).Value.Trim();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-19
      • 1970-01-01
      • 1970-01-01
      • 2017-08-31
      • 1970-01-01
      • 1970-01-01
      • 2013-08-15
      • 2018-02-15
      相关资源
      最近更新 更多