I am receiving data from a Web Service. The XML coming in is something like:
<data>
<item>
<code>a</code>
<price>2.89</price>
</item>
<item>
<code>a</code>
<price>2.89</price>
<colour>blue</colour>
</item>
</data>
So, we see that one item has an additional property of Colour.
Okay, this gets converted into a List<item> which is the point at which I get hold of it.
I need to convert this list into an XDocument.
Using:
var xml = new XDocument(
new XDeclaration("1.0", "utf-16", "yes"),
new XElement("data",
from i in myList
select new XElement("item",
new XElement("price", i.price),
new XElement("code", i.code),
new XElement("colour", i.colour))));
(I've typed this from memory, so excuse spellings)
Here, it errors because i.colour is null.
How do I cope with this?
Thanks in advance
Griff
You'll want to check whether i.colour is null before trying to access it.
You can do this neatly using the null-coalescing operator like:
new XElement("colour", i.colour ?? ""))));
Assuming that you want an empty string as the value if i.colour is null.
UPDATE
Based on your comment below, if you don't want the element added if i.colour is null then create it independantly of the XDocument instantiation and add it as required.
var xml = new XDocument(...);
if(i.colour != null)
{
xml.Add(new XElement(...));
}
}
To avoid adding a new XElement when colour is null you can use the ternary operator and return null or the new XElement as appropriate:
var xml = new XDocument(
new XDeclaration("1.0", "utf-16", "yes"),
new XElement("data",
from i in myList
select new XElement("item",
new XElement("price", i.price),
new XElement("code", i.code),
i.colour == null ?
null : new XElement("colour", i.colour)
)));
Related
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.
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)))));
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);
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";
i have an big issue, and just lost like 5 hours on it.
I have to create an XML file, which will be populated by a database reg.
i have variable structure, which in some cases will use specific sub structure.
the logic is simple.
I have to get all agencys,
then in every agency i have to iterate a foreach cycle,
and get all houses that they whant to sell/rent.
But its not only houses, there´s apartaments, garages, and so on.
Each of this scenes have their own structure with different data.
This is not all, there must have an condition. Only writes xml childs only if they are supposed to.
piece of xml example
<Clients>
<Client>
<aggregator/>
<code/>
<reference/>
<contact>
<secondhandListing>
<property>
<code/>
<reference/>
<scope/>
<address>
<features/>
<operation> // variable structure
1example <price/>
<communityCosts/>
2example <price/>
<communityCosts/>
<depositType/>
</operation>
</property>
</secondhandListing>
Can some one show me an example of how this could be done.
what I archive until now was:
var agenciasConectores = //query of Agencys
foreach (var agenciaConector in agenciasConectores)
{
var imoveisAgencia = // query of homes in each Agency
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Clients",
from agencia in agenciasConectores
select new XElement("Client", new XAttribute("ID", agencia.AgencyId),
new XElement("aggregator", agencia.ConnectorLicense),
new XElement("code", agencia.Name),
new XElement("Reference", agencia.Phone),
new XElement("contact", agencia.Phone),
new XElement("secondhandListing"),
new XElement("newbuildListing")
)));
foreach (var imovel in imoveisAgencia)
{
if (imoveisAgencia.Count() > 1)
{
doc.Document.Add(new XElement("property",
new XElement("code", "codigo"),
new XElement("reference", "reference"),
new XElement("scope", "scope"),
new XElement("address", "address"),
new XElement("contact", "contact"),
new XElement("features", "features"),
new XElement("operation", "operation"),
new XElement("description", "description")));
}
}
}
When I try to run this in Visual Studio, the following line throws an exception
doc.Document.Add(new XElement("property",
...
are you trying to do something more like this?
doc.Root.Add(new XElement("property",
...
or, perhaps, something closer to this
doc.Descendants("Client")
.Single(c => c.code == "something")
.Add(new XElement("property",
...
Already find a solution.
its simple.
XElement root = new XElement("root");
XElement child = new XElement("Child");
XElement child2 = new XElement(Child2);
then I populate the elements.
Child.SetValue(a);
child2.Setvalue(b);
and at final, i just add elements to parent Element.
root.add(Child,Child2);
But like that i also can make some validations(in my case in cycle)
If(a>b)
root.add(child);
else
root.add(child2);
thx for the try. I learn it by the example hehehhe
I am trying to replicate:
<gcf>
<cbxDecOnly Type="Boolean">False</cbxDecOnly>
<cbxFormName Type="String" />
<txtCustomerCellPhonePart2 Type="String">5236</txtCustomerCellPhonePart2>
<txtCustomerCellPhonePart1 Type="String">533</txtCustomerCellPhonePart1>
....
</gcf>
so far I have:
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("gcf",
new XElement("cbxDecOnly", new XAttribute("Type", "Boolean")),
new XElement("cbxFormName", oGSFE.TextBoxClientName),
new XElement("txtCustomerCellPhonePart2", oGSFE.TextBoxDealSearch),
new XElement("txtCustomerCellPhonePart1 ", oGSFE.DropDownListFIManager)
)
);
what I don't know is how to add a XAttribute and a value at the same time to the XML element <cbxDecOnly Type="Boolean">False</cbxDecOnly>
In the same way you provide the value for your txtCustomerCellPhonePart2 etc nodes - by including the string value as one of the element's params content[]:
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("gcf",
new XElement("cbxDecOnly", "False", new XAttribute("Type", "Boolean")),
new XElement("cbxFormName", oGSFE.TextBoxClientName),
new XElement("txtCustomerCellPhonePart2", oGSFE.TextBoxDealSearch),
new XElement("txtCustomerCellPhonePart1", oGSFE.DropDownListFIManager)
)
);
Any values of type string provided in content[] will be merged into the element's value, any values of type XAttribute will create attributes and any values of type XElement will become the children.
I am trying to create an XML document using Linq and need to reference the index within a list of each object. At the moment all I can find is the IndexOf(s) method which just returns the first occurrence of s, rather the position of any s given. This creates a problem when the List contains multiple copies of the same value.
var commands = listProcedure.Items.Cast<string>().ToList();
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("commands",
commands.Select(s => new XElement("command", s, new XAttribute("id", commands.IndexOf(s)))
)));
Try this one
var commands = listProcedure.Items.Cast<string>().ToList();
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("commands",
commands.Select( (s, idx) =>
new XElement("command", s, new XAttribute("id", idx))
)));
For LINQ look at SELECTMANY - sorry can't be more help with detail but hopefully a pointer in the right direction.
I want to make xml element like this:
<ElementName Type="FirstAttribute" Name="SecondAttribute">Value</Atrybut>
Now I'm doing this in this way:
XmlNode xmlAtrybutNode = xmlDoc.CreateElement("ElementName ");
_xmlAttr = xmlDoc.CreateAttribute("Type");
_xmlAttr.Value = "FirstAttribute";
xmlAtrybutNode.Attributes.Append(_xmlAttr);
_xmlAttr = xmlDoc.CreateAttribute("Name");
_xmlAttr.Value = "SecondAttribute";
xmlAtrybutNode.Attributes.Append(_xmlAttr);
xmlAtrybutNode.InnerText = !string.IsNullOrEmpty(Value)
? SetTextLength(Name, ValueLength)
: string.Empty;
Value is input variable in method.
Is there possibility to make this in another way?
More efficiently?
Can I use xmlWriter? Now i'm using xmlDocument.
You can use Linq to XML.
Basically
XDocument doc = new XDocument();
doc.Add(
new XElement("ElementName", "Value",
new XAttribute("Type", "FirstAttribute"),
new XAttribute("Name", "SecondAttribute")));
will give this xml document
<ElementName Type="FirstAttribute" Name="SecondAttribute">Value</ElementName>
How about tweaking your existing code:
XmlElement el = xmlDoc.CreateElement("ElementName");
el.SetAttribute("Type", "FirstAttribute");
el.SetAttribute("Name", "SecondAttribute");
el.InnerText = ...;
Additional thoughts:
XElement
XmlSerializer (from a class instance)
If you’re on .NET 3.5 (or later), you could use LINQ to XML. Make sure that the System.Xml.Linq assembly is referenced, and that you have a using directive for its eponymous namespace.
XDocument document = new XDocument(
new XElement("ElementName",
new XAttribute("Type", "FirstAttribute"),
new XAttribute("Name", "SecondAttribute"),
value));
If you subsequently want to write the XDocument to a target, you can use its Save method. For debugging, it’s useful to call its ToString method, which returns its XML representation as a string.
Edit: Replying to comment:
If you need to convert the XDocument created above into an XmlDocument instance, you may use code similar to the following:
XmlDocument xmlDocument = new XmlDocument();
using (XmlReader xmlReader = document.CreateReader())
xmlDocument.Load(xmlReader);
What about using LINQ to XML as in this article. That can be very elegant - it can all be done on one line.
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("element",
new XAttribute("attribute1", "val1"),
new XAttribute("attribute2", "val2"),
)
);