Quantum_Kernel
Quantum_Kernel

Reputation: 333

C# Linq XDoc - add element with same name

I'm attempting to write a small XML file using c# Linq XDocument.

The final xml file should look like this:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Asset InternalID="SOMEID" LastSaveDate="2016-10-28" LastSaveTime="01:01:33:00" AssetType="New">
    <type_metadata>
      <FIELD name="filename">SOMEID.MOV</FIELD>
      <FIELD name="duration">00:00:00:10</FIELD>
    </type_metadata>
  </Asset>
</Root>

Here is my code:

XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", null));
doc.Add(new XElement("Root"));
doc.Element("Root").Add(new XElement("Asset"));
doc.Element("Root").Element("Asset").Add(new XAttribute("InternalID", a.InternalID));
doc.Element("Root").Element("Asset").Add(new XAttribute("LastSaveDate", a.lastSaveDate));
doc.Element("Root").Element("Asset").Add(new XAttribute("LastSaveTime", a.lastSaveTime));
doc.Element("Root").Element("Asset").Add(new XAttribute("AssetType", a.AssetType));
doc.Element("Root").Element("Asset").Add(new XElement("type_metadata"));

doc.Element("Root").Element("Asset").Element("type_metadata").Add(new XElement("FIELD"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Add(new XAttribute("name","filename"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Value = a.filename;

doc.Element("Root").Element("Asset").Element("type_metadata").Add(new XElement("FIELD"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Add(new XAttribute("name", "duration"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Value = a.duration;

Everything works fine until I try to put in the second "FIELD" element. What is the proper way to do this? I have done some research, but I cant find a simple answer that is directly relevant to what I'm trying to accomplish.

Upvotes: 0

Views: 580

Answers (3)

RK_Aus
RK_Aus

Reputation: 946

This can be achieved in different ways. I just followed your approach. Since you have multiple FIELD elements, slight modification required in your code. The following code will work as expected.

XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", null));
doc.Add(new XElement("Root"));
doc.Element("Root").Add(new XElement("Asset"));
doc.Element("Root").Element("Asset").Add(new XAttribute("InternalID", "intID"));
doc.Element("Root").Element("Asset").Add(new XAttribute("LastSaveDate", "28.10.2016"));
doc.Element("Root").Element("Asset").Add(new XAttribute("LastSaveTime", "1.48PM"));
doc.Element("Root").Element("Asset").Add(new XAttribute("AssetType", "Laptop"));
doc.Element("Root").Element("Asset").Add(new XElement("type_metadata"));

doc.Element("Root").Element("Asset").Element("type_metadata").Add(new XElement("FIELD"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Add(new XAttribute("name", "filename"));
doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD").Value = "a.txr";

doc.Element("Root").Element("Asset").Element("type_metadata").Add(new XElement("FIELD"));
doc.Element("Root").Element("Asset").Element("type_metadata").Elements().Last().Add(new XAttribute("name", "duration"));
doc.Element("Root").Element("Asset").Element("type_metadata").Elements().Last().Value = "00:12:98";

Upvotes: 0

MarcinJuraszek
MarcinJuraszek

Reputation: 125640

That's because when you're trying to add second element you're using:

doc.Element("Root").Element("Asset").Element("type_metadata").Element("FIELD")

It will return first element matching the name, which is this case is the previously added "FIELD" element, which already has "name" attribute.

I'd suggest you create the element itself before attaching it to the document. This way you won't have to search for the element over and over again:

XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", null));

var root = new XElement("Root");

var asset = new XElement("Asset");
asset.Add(new XAttribute("InternalID", a.InternalID));
asset.Add(new XAttribute("LastSaveDate", a.lastSaveDate));
asset.Add(new XAttribute("LastSaveTime", a.lastSaveTime));
asset.Add(new XAttribute("AssetType", a.AssetType));

var type_metadata = new XElement("type_metadata");

var field = new XElement("FIELD");
field.Add(new XAttribute("name","filename"));
field.Value = a.filename;

type_metadata.Add(field);

var field2 = new XElement("FIELD");
field2.Add(new XAttribute("name","duration"));
field2.Value = a.duration;

type_metadata.Add(field2);

asset.Add(type_metadata);

root.Add(asset);

doc.Add(root);

Also, you can create the entire document in a single statement:

XDocument doc = new XDocument(
    new XDeclaration("1.0", "UTF-8", null),
    new XElement("Root",
        new XElement("Asset",
            new XAttribute("InternalID", a.InternalID),
            new XAttribute("LastSaveDate", a.lastSaveDate),
            new XAttribute("LastSaveTime", a.lastSaveTime),
            new XAttribute("AssetType", a.AssetType),
            new Element("type_metadata",
                new XElement("FIELD",
                    new XAttribute("name", "filename"),
                    a.filename),
                new XElement("FIELD",
                    new XAttribute("name", "duration"),
                    a.duration)))));

Upvotes: 1

har07
har07

Reputation: 89305

It would be easier if you prepare new FIELD element before adding it to the parent element :

var filename = new XElement("FIELD",
                    new XAttribute("name","filename"),
                    a.filename
               );
var duration = new XElement("FIELD",
                    new XAttribute("name","duration"),
                    a.duration
               );
doc.Element("Root").Element("Asset").Element("type_metadata").Add(field);
doc.Element("Root").Element("Asset").Element("type_metadata").Add(duration);

Upvotes: 1

Related Questions