0

I have an XML that needs it's elements rearranging. Is there a way to do this using LINQ?

as in the below example, elements 3 and 2 have been mixed up, and need rearranging so the elements are 1,2 and 3. likely the next time data comes in, it will be in an even different order, but will need putting back to 1,2 and 3.

<a>
  <1></1>
  <3></3>
  <2></2>
</a>
TheBoyan
  • 6,802
  • 3
  • 45
  • 61
Andy
  • 2,248
  • 7
  • 34
  • 57
  • 1
    Of course you can, by simply rewriting the XML, putting its sub-`XElement`s in the correct order. How do you know what the correct order is? By loading your XSD to the `XmlSchema` and using the `XmlSchemaSequence` class. See my question (and my own answer) http://stackoverflow.com/questions/7311880/xmlschema-inferred-from-an-xml-file-how-to-iterate-through-all-the-elements-in for more info. – Konrad Morawski Dec 20 '11 at 09:29
  • @Morawski So what your code does is run through each and every element and attribute in the project. It seems easy enough for my 1,2,3 example, but then if there was a possibility for an element to occur multiple times, would you have to count how many times an element occurs and loop that number? – Andy Dec 20 '11 at 10:03

1 Answers1

3

The hardest part is getting the correct order from the XSD. You can load the XSD as an XDocument and query it directly with XML.

Consider the following schema based on your example (I added the underscores since 1, 2, & 3 are not valid XML names by themselves)

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="XMLSchema1"
    targetNamespace="http://tempuri.org/XMLSchema1.xsd"
    elementFormDefault="qualified"
    xmlns="http://tempuri.org/XMLSchema1.xsd"
    xmlns:mstns="http://tempuri.org/XMLSchema1.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>

  <xs:complexType name="a">
    <xs:sequence>
      <xs:element name="_1" type="xs:string" minOccurs="1" maxOccurs="1" />
      <xs:element name="_2" type="xs:string" minOccurs="1" maxOccurs="1" />
      <xs:element name="_3" type="xs:string" minOccurs="1" maxOccurs="1" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>    `

If you load this into an object (XDocument or XElement are best), you can do a LINQ query on the schema (the query is not tested, I am doing this from memory from the last time i did this, but if i am missing something, it should point you in the right direction)

var schema = XDocument.Load(@"C:\somepath\XMLSchema1.xsd");
var xs = XNamespace.Get(@"http://www.w3.org/2001/XMLSchema");

var order = (from x in schema.Elements(xs + "schema").Elements(xs + "complexType") 
             where x.Attributes("name").FirstOrDefault().Value == "a" 
             select x.Element(xs + "sequence").Elements())
            .First()
            .Select(x => x.Attribute("name").Value);

If you have a more complex XSD, with pre-defined types and/or custom name spaces, it will make the query to get the order of the elements more complex, but hopefully you get the idea. If you have an extremely complex XSD, see some of the links i have at the end of this answer for help understanding the XmlSchemaInfo object model and you might be abler to write your own query to get the order far more easily.

Once you have the correct order, I don't recommend using LINQ to actually change the order of the nodes as LINQ was not designed to modify objects, but rather using it to find the nodes and the parent node, then rearranging them in the order you want.

XElement xelem = // get parent element of the elements you need to rearrange

foreach (var element in order)
{
    var node = xelem.Element(element);
    node.Remove();
    xelem.Add(node);                
}

if you are going to be working with accessing XSD directly in code frequently, I recommend reading the following questions and answers for help as the XmlSchemaInfo object model is not well documented, and will take some time & effort to get a workable method to extract what you need. It will be easier finding and extracting the information you need from the schema.

XmlSchema inferred from an XML file - how to iterate through all the elements in the XSD? (Morawski's question he reference in his comment)

Capture Schema Information when validating XDocument (my own question & answer)

In C#, how to determine the XSD-defined MaxLength for an element

http://geekswithblogs.net/.NETonMyMind/archive/2006/05/02/76957.aspx (Great blog posting from where I got most of the info for my SchemaInfo question and answer)

Community
  • 1
  • 1
psubsee2003
  • 8,563
  • 8
  • 61
  • 79
  • still looking into this, thanks for the reply, it is harder then expected. the LINQ query did have some minor things that needed changing, if you want to update it in your question for correctness , i had to change it to --> var order = (from x in schema.Elements(xs + "schema").Elements(xs + "complexType") where x.Attributes("name").FirstOrDefault().Value == "a" select x.Element(xs + "sequence").Elements()) .First() .Select(x => x.Attribute("name").Value); – Andy Dec 20 '11 at 11:21