简体   繁体   中英

Traversing an XML file using Linq to XML not working as expected

Sorry for the somewhat basic question, but what can I say. I can't figure it out. The problem is that there's a foreach loop that's supposed to iterate through the rows (sections) and while it works for the first section, the second time through the loop it doesn't seem to read the second section. The same data is stored in version . BTW, the way the method is called I would be passing in ProductName as a parameter (There will be multiple products represented here and also a version number (eg v2.0.0) that I'll need to filter the results for too.

So I have an XML file that looks like this:

<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>

There will only be 10 or so versions (eg v2.xx) so there's not a lot of data here. So I created a multidimensional (nested) class/struct to hold the data and when I try my code to read the data it's not working.

Here are the classes/stucts (I've tried both and neither works) that I'm trying to populate:

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; }
    }

So here's my code. Please just ignore the Stream - that's so I can embed this XML file in the .exe and not have it be a separate file:

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;
    }

I know there are many ways to read XML and my choice doesn't work so I'm looking for another simple solution.

The following works :

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; }
    }

}

I figured it out (many thanks to jdweng!!). Here's the final solution based on the revised XML at the top:

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; }
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM