2

I'm using C#. I have the following XML file:

<MyItems count="2">
<MyItem itemId="1234">
   <MyItem itemId="12344">
        <!--Same fields like any another MyItem, can be more then one element like that--->
   </MyItem>
<Field id="1">1234</Field>
<Field id="2">My Item 1 Text</Field>
<Field id="3">
  <ListValues>
    <ListValue itemDisplayName="Item P1">Item P1</ListValue>
  </ListValues>
</Field>
<Field id="4"/>
<Field id="5">
  <ItemRef id="xyz">Test Reference</ItemRef>
  <ItemRef id="xyzw">Test Reference2</ItemRef>
</Field>
</MyItem>
<MyItem itemId="1235">
    <MyItem itemId="12355">
        <!--Same fields like any another MyItem, can be more then one element like that--->
    </MyItem>
<Field id="1">1235</Field>
<Field id="2">My Item 2 Text  </Field>
<Field id="3">
  <ListValues>
    <ListValue itemDisplayName="Item P2">Item P2</ListValue>
  </ListValues>
</Field>
<Field id="4"/>
<Field id="5">
  <ItemRef id="xyz">Test Reference</ItemRef>
  <ItemRef id="xyzw">Test Reference2</ItemRef>
</Field>
</MyItem>
<Metadata>
 <MyItemFieldDef>
    <ItemFieldDef id="1" aliasName="Item_ID" />
    <ItemFieldDef id="2" aliasName="Item_Data0" />
    <ItemFieldDef id="3" aliasName="Item_Data1" />
    <ItemFieldDef id="4" aliasName="Item_Data2" />
    <ItemFieldDef id="5" aliasName="Item_Data3" />
    <!--ItemFieldDef 6 etc... -->
  </MyItemFieldDef>
</Metadata>
</MyItems>

The xml file scheme: Items, and then for each item i have the fields (each field with field id) and the field defnition in the <Metdadata>.
I want to convert the XML to format of "Key-Value" like the following example:

 <ex:MyItems xmlns:ex="http://bla.com">
 <ex:MyItem>
      <ex:MyItem>
             <ex:Item_ID>12344</ex:Item_ID>
      </ex:MyItem>
   <ex:Item_ID>1234</ex:Item_ID>
   <ex:Item_Data0>My Item 1 Text</ex:Item_Text>
   <ex:Item_Data1>
     <ex:Item>Item P1</ex:Item>
   </ex:Item_Data1>
   <ex:Item_Data2 />
   <ex:Item_Data3>
     <ex:Item>Test Reference</ex:Item>
     <ex:Item>Test Reference2</ex:Item>
   </ex:Item_Data3>
   <!-- Item_Data4.... -->
   </ex:MyItem>
<ex:MyItem>
  <ex:MyItem>
        <ex:Item_ID>12355</ex:Item_ID>
  </ex:MyItem>
  <ex:Item_ID>1235</ex:Item_ID>
  <ex:Item_Data0>My Item 2 Text </ex:Item_Text>
  <ex:Item_Data1>
    <ex:Item>Item P2</ex:Item>
  </ex:Item_Data1>
  <ex:Item_Data2 />
  <ex:Item_Data3>
     <ex:Item>Test Reference</ex:Item>
     <ex:Item>Test Reference2</ex:Item>
   </ex:Item_Data3>
  <!-- Item_Data4.... -->
  </ex:MyItem>
</ex:MyItems>

I'm looking for the best/easy way to make the convert from the first xml file format to the second xml file format.
The reason: the second xml file format is "readable".
I'm have been tried with XmlDocument but its take a long time.
There is another way to do that? maybe with Serallize/Deserallize ? Thanks a lot!!

*<ListValue> can to be with more then one value

Edit:
1. Add ItemRef Element.
2. Add MyItem element inside MyItem Element

CSharpBeginner
  • 601
  • 2
  • 7
  • 22

2 Answers2

1

You are on the right track with XmlDocument. Easiest way to do this is to deserialize the incoming XML file into a C# class and map it to another C# object that you can serialize back into XML.

Microsoft actually provides a tool that has the capability of generating a class from XML called xsd.exe. You can use it as follows:

xsd.exe /c filename

There are more options if you want to specify the class name, namespace, etc.

Once you've got the classes generated for the XML, you can deserialize the class using XMLSerializer.Deserialize. Same thing in reverse for the output class. Also, you can write your own logic for mapping from first object to the next, or use a tool like AutoMapper.

Editing to add link to another SO post with additional info

Here is another popular SO post about deserializing XML. If you don't want to use the xsd.exe tool, you can create the classes yourself and tell the serializer how to work with it using attributes. Also, there is an online tool where you can paste in some XML and generate the corresponding C# object.

Community
  • 1
  • 1
Larry
  • 511
  • 4
  • 10
1

Try this code with Linq to Xml:

var inputXml = XElement.Load("input.xml");

var dict = inputXml.Element("Metadata")
    .Element("MyItemFieldDef")
    .Elements("ItemFieldDef")
    .ToDictionary(elem => elem.Attribute("id").Value,
        elem => elem.Attribute("aliasName").Value);

XNamespace ns = "http://bla.com";

var outputXml = new XElement(ns + "MyItems",
    new XAttribute(XNamespace.Xmlns + "ex", ns),
    inputXml.Elements("MyItem")
        .Select(item => new XElement(ns + "MyItem",
            item.Elements("MyItem")
                .Select(myItem =>
                    new XElement(ns + "MyItem",
                        new XElement(ns + "Item_ID", myItem.FirstAttribute.Value))
                ),
            item.Elements("Field")
                .Select(field =>
                {
                    if (field.HasElements)
                        return new XElement(ns + dict[field.Attribute("id").Value],
                            field.Descendants().Where(desc => !desc.HasElements)
                                .Select(desc => new XElement(ns + "Item", desc.Value)));
                    else
                        return new XElement(ns + dict[field.Attribute("id").Value],
                            field.Value);
                }))));

outputXml.Save("output.xml");

You mentioned a long time. Probably xml size is large. So I used a Dictionary, which provides a quick search.

Alexander Petrov
  • 13,457
  • 2
  • 20
  • 49