Alex Meyer
Alex Meyer

Reputation: 851

How to use LINQ to XML when XML parent and child nodes have the same name

I am trying to extract some SQL data to XML from a Microsoft Dynamics environment, I am currently using LINQ To XML in C# to read and write to my XML files. One piece of data I need is from a view called SECURITYSUBROLE. Looking at the structure of this view shows that there is a column also named SECURITYSUBROLE. My normal method of extraction has given me this XML.

<SECURITYSUBROLE>
  <SECURITYROLE>886301</SECURITYROLE>
  <SECURITYSUBROLE>886317</SECURITYSUBROLE>
  <VALIDFROM>1900-01-01T00:00:00-06:00</VALIDFROM>
  <VALIDFROMTZID>0</VALIDFROMTZID>
  <VALIDTO>1900-01-01T00:00:00-06:00</VALIDTO>
  <VALIDTOTZID>0</VALIDTOTZID>
  <RECVERSION>1</RECVERSION>
  <RECID>886317</RECID>
</SECURITYSUBROLE>

When I try to import this data later on, I am getting errors because the parent XML node has the same name as a child node. Here is a snippet of the import method:

XmlReaderSettings settings = new XmlReaderSettings();
settings.CheckCharacters = false;

XmlReader reader = XmlReader.Create(path, settings);

reader.MoveToContent();
int count = 1;
List<XElement> xmlSubset = new List<XElement>();
while (reader.ReadToFollowing(xmlTag))
 {
   if (count % 1000 == 0)
   {
    xmlSubset.Add(XElement.Load(reader.ReadSubtree()));
    XDocument xmlTemp = new XDocument(new XElement(xmlTag));
    foreach (XElement elem in xmlSubset)
    {
     xmlTemp.Root.Add(elem);
     }
     xmlSubset = new List<XElement>();
     ImportTableByName(connectionString, tableName, xmlTemp);
     count = 1;
     }
   else
   {
     xmlSubset.Add(XElement.Load(reader.ReadSubtree()));
     count++;
   }
  }
}

It's currently failing on the XmlReader.ReadToFollowing, where it doesn't know where to go next because of the name confusion. So my question has two parts:

1) Is there some better way to be extracting this data other than to XML?

2) Is there a way through LINQ To XML that I can somehow differentiate between the parent and child nodes named exactly the same?

Upvotes: 1

Views: 950

Answers (2)

Chuck Savage
Chuck Savage

Reputation: 11945

To get the elements (in your case) for SECURITYSUBROLE you can check to see if the element's have children:

XElement root = XElement.Load(path);
var subroles = root.Descendants("SECURITYSUBROLE") // all subroles
                   .Where(x => !x.HasElements); // only subroles without children

Upvotes: 2

MikeH
MikeH

Reputation: 4395

I'm going to suggest a different approach:

1) VS2013 (possibly earlier versions too) has a function to create a class from an XML source. So get one of your XML files and copy the content to your clipboard. Then in a new class file Edit --> Paste Special --> Paste XML as Classes

2) Look into XmlSerialization which will allow you to convert an XML file into an in memory object with a strongly typed class.

      XmlSerializer s = new XmlSerializer(yourNewClassTYPE);
      TextReader r = new StreamReader(XmlFileLocation);
      var dataFromYourXmlAsAStronglyTypedClass = (yourNewlyClassTYPE) s.Deserialize(r);
      r.Close();

Upvotes: 0

Related Questions