Quantum_Kernel Quantum_Kernel - 1 month ago 9
C# Question

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.

Answer

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)))));
Comments