XML Find,然后从上一个元素返回一个值

XML Find then return a value from previous element

提问人:Cyberdrac 提问时间:12/2/2022 最后编辑:Cyberdrac 更新时间:12/2/2022 访问量:158

问:

我正在处理一个构造奇怪的 XMl 文档,缺少 ID 和模棱两可的名称等。希望我的示例XML文档能为您描绘出一幅合适的画面。真正的文档是巨大的,有时嵌套 10 层或更多层深,真正的眼睛酸痛。

我需要做的是在名为 Supplier/Name 的节点中找到特定值。但要找到这个,我需要先在 Var/Value 中找到一个值,然后再查找。在我的示例中,我需要找到 Var/Value CLR-111。

我不知道最好是在 LINQ 中还是使用 XML 文档来执行此操作??我发现的壁橱是使用上一个节点的 XMLNode。但我不确定如何先找到位置,然后跳上两个。

简单的部分是找到元素,但不知道如何查找两个元素。这就是我轰炸的地方。

我需要返回的是 ACME。

<?xml version="1.0" encoding="utf-8"?>
<Uni>
  <Job ID="Job1">
    <Manufacturing ID="MPG-1">
        <Factory>
            <SKUGroups ID="SKU-72">
                <Supplier>
                  <Name>ACME</Name>
                  <Details address="123 Bobs Road" Zip="90210" />
                </Supplier>
                <Type>Paint</Type>
                <Var>
                  <Name>ColorID</Name>
                  <Value>CLR-111</Value>
                </Var>
                <Supplier>
                  <Name>TomInc</Name>
                  <Details address="555 Jayne Lane" Zip="65986" />
                </Supplier>
                <Type>Tire</Type>
                <Var>
                  <Name>ColorID</Name>
                  <Value>CLR-2222</Value>
                </Var>
            </SKUGroups>
        </Factory>
    </Manufacturing>
  </Job>
</Uni>


XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(myPath);
XmlNode blaa = doc.SelectSingleNode("descendant::SKUGroups[Var/Value='CLR-111']/Var/Name");
C# XML 链接

评论


答:

0赞 AceGambit 12/2/2022 #1

您将需要搜索 CLR-111 节点(可能使用递归),一旦找到它,您就可以爬上树以返回该节点。node.ParentNode.ParentNodeVar

到达节点后,您可以使用它在 XmlDoc 中向后走动。Varnode.PreviousSibling

例如:

var clrXmlTextElement = ... // whatever the XmlText object element of the <Value>CLR-111</Value> node is when you find it.
var valueNode = clrNode.ParentNode; // <Value>CLR-111</Value>
var varNode = valueNode.ParentNode; // <Var>
var typeNode = varNode.PreviousSibling; // <Type>Paint</Type>
var supplierNode = typeNode.PreviousSibling; // <Supplier>
var supplierName = GetSupplierName(supplierNode); // ACME

string GetSupplierName(XmlNode supplierNode)
{
    foreach (XmlElement xmlElement in supplierNode.ChildNodes)
    {
        if (xmlElement.Name == "Name")
        {
            return xmlElement.InnerText;
        }
    }

    return "Error: no <Name> tag found in <Supplier> node.";
}
0赞 jdweng 12/2/2022 #2

我从不倒退。永远向前。我喜欢收集所有数据,然后使用字典查找值。

下面使用的是 Xml linq。我转换而不是使用值,所以如果项目为空,我不会得到异常

请参阅下面的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            List<Supplier> suppliers = new List<Supplier>();
            foreach(XElement job in doc.Descendants("Job"))
            {
                string jobId = (string)job.Attribute("ID");
                XElement manufacturing = job.Element("Manufacturing");
                string manufacturingId = manufacturing == null ? "" : (string)manufacturing.Attribute("ID");
                foreach(XElement skuGroup in job.Descendants("SKUGroups"))
                {
                    string skuGroupId = (string)skuGroup.Attribute("ID");
                    Supplier supplier = null;
                    foreach(XElement element in skuGroup.Elements())
                    {
                        switch(element.Name.LocalName)
                        {
                            case "Supplier":
                                supplier = new Supplier();
                                suppliers.Add(supplier);
                                supplier.jobId = jobId;
                                supplier.manufacturingId = manufacturingId;
                                supplier.skuGroupId = skuGroupId;
                                supplier.name = (string)element.Element("Name");
                                XElement details = element.Element("Details");
                                supplier.address = details == null ? "" : (string)details.Attribute("address");
                                supplier.zip = details == null ? "" : (string)details.Attribute("Zip");
                                break;
                            case "Type":
                                supplier.type = (string)element;
                                break;
                            case "Var":
                                supplier.varName = (string)element.Element("Name");
                                supplier.value = (string)element.Element("Value");
                                break;

                        }

                    }
                }

            }
            Dictionary<string, Supplier> dict = suppliers.GroupBy(x => x.value).ToDictionary(x => x.Key, y => y.FirstOrDefault());
            Supplier CLR_2222 = dict["CLR-2222"];
 
        }
 
    }
    public class Supplier
    {
        public string jobId { get; set; }
        public string manufacturingId { get; set; }
        public string skuGroupId { get; set; }
        public string name { get; set; }
        public string address { get; set; }
        public string zip { get; set; }
        public string type { get; set; }
        public string varName { get; set; }
        public string value { get; set; }
    }
}

评论

0赞 Cyberdrac 12/2/2022
非常感谢您抽出宝贵时间向我展示这个。我花了最后一个小时学习这个,它也给了我一些提示,我知道我会遇到其他问题。你是对的,最好从时间开始,然后慢慢来。
0赞 jdweng 12/2/2022
如果您有多个键,请将字典更改为以下内容:Dictionary<string, List<Supplier>> dict = suppliers。GroupBy(x => x.value)。ToDictionary(x => x.Key, y => y.ToList());还要看看我在哪里使用了 Descendants(不是子级,返回多个子级)和 Element(只返回一个直接子级)。