使用 Linq to XML 遍历 XML 文件未按预期工作

Posted

技术标签:

【中文标题】使用 Linq to XML 遍历 XML 文件未按预期工作【英文标题】:Traversing an XML file using Linq to XML not working as expected 【发布时间】:2019-10-25 08:19:37 【问题描述】:

对不起,这个有点基本的问题,但我能说什么。我想不通。问题是有一个 foreach 循环应该遍历行(部分),虽然它适用于第一部分,但第二次通过循环它似乎没有读取第二部分。相同的数据存储在 version 中。顺便说一句,调用该方法的方式我将传入 ProductName 作为参数(这里将表示多个产品以及我需要过滤的版本号(例如 v2.0.0)结果也是。

所以我有一个如下所示的 XML 文件:

<Products>
  <ProductName1>
    <v2.0.0>
      <GUID>"B5ECEC43-5406-4E4D-96D9-456823100313"</GUID>
      <VersionNameToUninstall>"2.0.0 - 2.0.2"</VersionNameToUninstall>
      <UninstallResponseFile>"GVQC-Client-2.0.0-Uninst.iss"</UninstallResponseFile>
    </v2.0.0>
    <v2.0.3>
      <GUID>"1D6C02D7-8E87-43BE-8AB2-1FF0E5ACD410"</GUID>
      <VersionNameToUninstall>"2.0.3"</VersionNameToUninstall>
      <UninstallResponseFile>"GVQC-Client-2.0.3-Uninst.iss"</UninstallResponseFile>
    </v2.0.3>  
  </ProductName1>
  <ProductName2>
    <v3.0.0>
      <GUID>"ABCDEC43-5406-4E4D-96D9-456823101234"</GUID>
      <VersionNameToUninstall>"2.2.0 - 2.2.2"</VersionNameToUninstall>
      <UninstallResponseFile>"GVQC-Client-2.2.0-Uninst.iss"</UninstallResponseFile>
    </v3.0.0>
    <v4.0.0>
      <GUID>"5D6C02D7-8E87-43BE-8AB2-1FF0E5ACD589"</GUID>
      <VersionNameToUninstall>"4.0.0"</VersionNameToUninstall>
      <UninstallResponseFile>"GVQC-Client-4.0.0-Uninst.iss"</UninstallResponseFile>
    </v4.0.0>  
  </ProductName2>
</Products>

只有 10 个左右的版本(例如 v2.x.x),所以这里没有很多数据。所以我创建了一个多维(嵌套)类/结构来保存数据,当我尝试我的代码来读取数据时它不起作用。

这是我要填充的类/结构(我都尝试过,但都不起作用):

public class TopLevelObject
    
        public string Version  get; set; 
        public RowLevelObject Row get;set;
    
public struct RowLevelObject
    
        public string Guid  get; set; 
        public string VersionName  get; set; 
        public string UninstallFileName  get; set; 
    

这是我的代码。请忽略 Stream - 这样我就可以将这个 XML 文件嵌入到 .exe 中,而不是让它成为一个单独的文件:

public static List<TopLevelObject> GetGUIDSFromFile(string GUIDKey)

        List<InstallScriptMSIXMLTopLevelObject> installScriptMSIXMLTopLevelObjectList = new List<InstallScriptMSIXMLTopLevelObject>();

        Stream GUIDXmlFileStream = typeof(PGCommonCA).Assembly.GetManifestResourceStream("PGCommonCA.ProductGUIDs.xml");
        XElement xElement = XElement.Load(GUIDXmlFileStream);
        var versions = xElement.Elements(GUIDKey).Descendants();
        foreach (var version in versions)
        
            TopLevelObject topLevelObject = new TopLevelObject();
            RowLevelObject rowLevelObject = new RowLevelObject();
            TopLevelObject.Version = version.Name.LocalName;

            RowLevelObject.Guid = version.Element("GUID").Value;
            RowLevelObject.VersionName = version.Element("VersionNameToUninstall").Value;
            RowLevelObject.UninstallFileName = version.Element("UninstallResponseFile").Value;
            TopLevelObjectList.Add(topLevelObject);
        
        return TopLevelObjectList;
    

我知道读取 XML 的方法有很多,但我的选择不起作用,所以我正在寻找另一个简单解决方案。

【问题讨论】:

FWIW,您的 xml 无效&lt;/v2.0.&gt; 【参考方案1】:

以下作品:

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

namespace ConsoleApplication1

    class Program
    
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        
            XDocument doc = XDocument.Load(FILENAME);
            XElement productName = doc.Root;

            List<TopLevelObject> top = productName.Elements().Select(x => new TopLevelObject() 
                Version = x.Name.LocalName,
                Row = new RowLevelObject() 
                    Guid = (string)x.Element("GUID"),
                    VersionName = (string)x.Element("VersionNameToUninstall"),
                    UninstallFileName = (string)x.Element("UninstallResponseFile")
                
            ).ToList();

        
    
    public class TopLevelObject
    
        public string Version  get; set; 
        public RowLevelObject Row  get; set; 
    
    public struct RowLevelObject
    
        public string Guid  get; set; 
        public string VersionName  get; set; 
        public string UninstallFileName  get; set; 
    


【讨论】:

OK - 我刚刚意识到我在 XML 文件中遗漏了一个外层。我已经更新了上面的 XML 文件格式。 @jdweng - 如果您可以修改您的回复以使其适用于这个新结构,请告诉我。另请注意,我需要根据 的值进行过滤。所以可能有等。谢谢!! 没关系 - 我想通了(感谢@jdweng)!我只需要将 productName.Elements() 更改为 productName.Descendents(GUIDKey).Elements()。【参考方案2】:

我想通了(非常感谢 jdweng !!)。这是基于顶部修改后的 XML 的最终解决方案:

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

namespace ConsoleApplication1

class Program

    const string FILENAME = @"c:\temp\test.xml";
    static TopLevelObject GetInfo(string xmlKey)
    
        XDocument doc = XDocument.Load(FILENAME);
        XElement productName = doc.Root;

        List<TopLevelObject> top = productName.Descendants(xmlKey).Elements().Select(x => new TopLevelObject() 
            Version = x.Name.LocalName,
            Row = new RowLevelObject() 
                Guid = (string)x.Element("GUID"),
                VersionName = (string)x.Element("VersionNameToUninstall"),
                UninstallFileName = (string)x.Element("UninstallResponseFile")
            
        ).ToList();

    

public class TopLevelObject

    public string Version  get; set; 
    public RowLevelObject Row  get; set; 

public struct RowLevelObject

    public string Guid  get; set; 
    public string VersionName  get; set; 
    public string UninstallFileName  get; set; 

【讨论】:

以上是关于使用 Linq to XML 遍历 XML 文件未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Linq to XML 将 HTML 保存在 XML 文件中?

如何/我可以使用 linq to xml 以合理的内存消耗查询巨大的 xml 文件?

LINQ to XML简介

linq to xml 增删查改

LINQ to XML概述

LINQ to XML - 从文件加载 XML 片段