How to add XElements dynamically in a loop? - c#

I get an HybridDictionary with all the child XElements.
I don't know ahead how many items I have there.
So instead of doing this:
xmlDoc.Element("Parent").Add(
new XElement("Child", new XAttribute("Name", "Child1"),
new XElement("Id", "796"),
new XElement("Name", "gdsa")
etc..
));
I'm trying to do something like that:
Strung [] allKeys = new String[ChildElements.Count];
TheHybridDictionary.Keys.CopyTo(allKeys, 0);
xmlDoc.Element("Parent").Add(
new XElement("Child", new XAttribute("Name", "Child1"),
for (int i = 0; i < TheHybridDictionary.Count; i++)
new XElement(allKeys[i], TheHybridDictionary[allKeys[i]])
But how to connect whatever is inside the for loop to be part of the XML document construction?

Problem is, your HybridDictionary class does not implement IEnumerable, so you can't use LINQ on it directly.
But you can use allKeys string array instead:
string [] allKeys = new String[ChildElements.Count];
TheHybridDictionary.Keys.CopyTo(allKeys, 0);
xmlDoc.Element("Parent").Add(
new XElement("Child", new XAttribute("Name", "Child1"),
allKeys.Select(x => new XElement(x, TheHybridDictionary[x])))

You can use .Add() method as in Stefan's comment, or use LINQ:
xmlDoc.Element("Parent").Add(
new XElement("Child", new XAttribute("Name", "Child1"),
TheHybridDictionary.Select(kvp => new XElement(kvp.Key, kvp.Value)));

Related

How to execute a LINQ query while constructing an XDocument?

I want to create a table that list the count of each file type. I've created a query to get that data. When I create the XDocument, how do I execute the query and create rows in the table with data from query?
var query = listFiles.GroupBy(f => Path.GetExtension(f).ToLower())
.Select(g => new
{
Extension = g.Key,
Count = g.Count(),
});
var doc = new XDocument(
new XElement("html",
new XElement("body",
new XElement("table", new XAttribute("border", 2),
foreach (var f in query)
{
new XElement("tr",
new XElement("td", f.Extension),
new XElement("td", f.Count));
}))));
Try following :
var doc = new XDocument(
new XElement("html",
new XElement("body",
new XElement("table", new object[] {
new XAttribute("border", 2),
query.Select(f =>
new XElement("tr",
new XElement("td", f.Extension),
new XElement("td", f.Count)))
}))));

Create XML via loop from SQL query data (static and looping XML)

I'll try explain what i'm trying to achieve as best I can...
I'm generating order XML document in C# using XDocument based on data from a SQL Query. Some of the XML Elements & Attributes need only appear once but the Order Line information needs to be looped a number of times; for example if an order contains 3 items I need to generate three instances of the Order Line information, if an order contains 5 items I need to generate five instances of the Order Line information etc.
My XML structure will look like below:
Delivery information - no loop required
Invoice information - no loop required
Order Line information - loop required as per above
More delivery information (shipping type) - no loop required
To get the static information, i'm using a SQLDataReader and passing the information into a variable:
var example = reader["column_name"];
This works fine for when I don't need to loop. However i'm now at the stage where I want to create the loop for Order Line information.
Each Order Line will come as a seperate row in my SQL query, the row will contain all the static information (Delivery information, invoice information etc) as well as the individual Order Line information (SKU, Product Description etc).
Essentially what I think I need to do is a foreach loop for each row in the SQLDataReader, and populate variables to drop into the XML OrderLine section, however I'm not sure how to do this, nor is this the best approach.
I can create a static version of the OrderLine section easily enough, but how would I go about looping through the SQL rows to pass variables into it? My static OrderLine code is as below
new XElement("OrderLine", new XAttribute("TypeDescription", "Goods & Services"), new XAttribute("Action", "Add"), new XAttribute("TypeCode", "GDS"),
new XElement("LineNumber", new XAttribute("Preserve", "true"), "item_number then increment by 1"),
new XElement("Product",
new XElement("SuppliersProductCode", "VALUE"),
new XElement("Description", "VALUE")),
new XElement("Quantity", new XAttribute("UOMDescription", "VALUE"), new XAttribute("UOMCode", "VALUE"),
new XElement("Amount", "Value")),
new XElement("Quantity", new XAttribute("UOMDescription", "VALUE"), new XAttribute("UOMCode", "VALUE"),
new XElement("UnitPrice", "Value"))),
My full XML generate code looks like this:
new XElement("Order",
new XElement("OrderHead",
new XElement("Schema",
new XElement("Value", "3.05")),
new XElement("Parameters",
new XElement("Language", "en-GB"),
new XElement("DecimalSeperator", "."),
new XElement("Precision", "12.3")),
new XElement("OrderType", new XAttribute("Code", "PUO"), "Purchase Order"),
new XElement("OrderCurrency",
new XElement("Currency", new XAttribute("Code", "GBP"), "GB Pounds Sterling"))),
new XElement("OrderReferences",
new XElement("BuyersOrderNumber", new XAttribute("Preserve", "true"), incrementid_var)),
new XElement("Buyer",
new XElement("BuyerReferences",
new XElement("SupplierscodeForBuyer", "****VALUE****")),
new XElement("Contact",
new XElement("Name"))),
new XElement("Delivery",
new XElement("DeliverTo",
new XElement("Party", firstname_var + " " + lastname_var),
new XElement("Contact",
new XElement("Name", firstname_var + " " + lastname_var),
new XElement("Email", "****EMAIL ADDRESS****")),
new XElement("Address",
new XElement("AddressLine", street_var),
new XElement("AddressLine", city_var),
new XElement("AddressLine", region_var),
new XElement("PostCode", postcode_var),
new XElement("Country", new XAttribute("Code", countryid_var)))),
new XElement("DeliverFrom",
new XElement("Party", firstname_var + " " + lastname_var))),
new XElement("InvoiceTo",
new XElement("Party", firstname_var + " " + lastname_var),
new XElement("Address",
new XElement("AddressLine", street_var),
new XElement("AddressLine", city_var),
new XElement("AddressLine", region_var),
new XElement("PostCode", postcode_var),
new XElement("Country", new XAttribute("Code", countryid_var)))),
//Start Loop
new XElement("OrderLine", new XAttribute("TypeDescription", "Goods & Services"), new XAttribute("Action", "Add"), new XAttribute("TypeCode", "GDS"),
new XElement("LineNumber", new XAttribute("Preserve", "true"), "item_number then increment by 1"),
new XElement("Product",
new XElement("SuppliersProductCode", "VALUE"),
new XElement("Description", "VALUE")),
new XElement("Quantity", new XAttribute("UOMDescription", "VALUE"), new XAttribute("UOMCode", "VALUE"),
new XElement("Amount", "Value")),
new XElement("Quantity", new XAttribute("UOMDescription", "VALUE"), new XAttribute("UOMCode", "VALUE"),
new XElement("UnitPrice", "Value"))),
// End Loop
//Start Delivery Information
new XElement("OrderLine", new XAttribute("TypeDescription", "VALUE"), new XAttribute("Action", "VALUE"), new XAttribute("TypeCode", "VALUE"),
new XElement("LineNumber", new XAttribute("Preserve", "true"), "item_number + 1"),
new XElement("Product",
new XElement("SuppliersProductCode", "**** DELIVERY CODE ****"),
new XElement("Description", "**** DELIVERY DESCRIPTION****")),
new XElement("Quantity", new XAttribute("UOMDescription", "Piece"), new XAttribute("UOMCode", "PCE"),
new XElement("Amount", "1")),
new XElement("Quantity", new XAttribute("UOMDescription", "Pack"), new XAttribute("UOMCode", "PCK"),
new XElement("UnitPrice", "0"))),
new XElement("AdditionalOrderReferences",
new XElement("OrderReference", incrementid_var)),
new XElement("DeliveryInformation", "TELEPHONE NUMBER")));
Everything outside of the Start Loop, End Loop comments only needs to be generated once. If the order has 5 items I need to generate the code within those comments 5 times.
Any help is much appreciated as i'm going round in circles reading articles and still not sure how to implement this.
Thanks
Iain

How can I add XElement iterating elements?

This is my code:
var xml = new XElement("test", new[] {
new XElement("group", new[] {
new XElement("date", dateNow.ToString("dd/MM/yyyy HH:mm:ss"))
}),
new XElement("users", new[] {
foreach(var item in in PlaceHolderCustom.Controls)
{
new XElement("nome", ((TextBox)item.FindControl("myTextBox")).Text)
}
})
});
I'd like to set in the xml some fixed fields (within the element "group") and some that would iterate across a placeholder. But the syntax seems to be wrong when I try to add a new "iterating" list.
Where am I wrong?
Use linq .Select to perform the foreach. Also when you create the array the new [] {} syntax is valid only for new string[]. In your case use:
new XElement[] {}
Or because the method gets a params object[] you can just give each new XElement independently without wrapping with an array
So showing both ways of passing the collection of XElements:
var xml = new XElement("test",
new XElement("group", new XElement[] {
new XElement("date", dateNow.ToString("dd/MM/yyyy HH:mm:ss"))
}),
new XElement("users", PlaceHolderCustom.Control.Select(item =>
new XElement("nome", ((TextBox)item.FindControl("myTextBox")).Text)).ToArray())
);

Linq to XML - From table to XDocument

I would like to generate an XDocument from my table (the structure is different) but I keep getting the following error :
LINQ to Entities does not recognize the method 'System.String ToString()' method.
I know this is caused by the Birthdate and I would need to use SqlFunctions.StringConvert but I'm working with Framework 4.0
Any ideas on how to solve that?
// Newsletter subscriptions
var news = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement("USER",
from n in _dc.Newsletter_Datas
where n.Timestamp >= startDate
select
new XElement("ROW",
new XElement("UTI", n.ID),
new XElement("FIRSTNAME", n.FirstName),
new XElement("FAMILYNAME", n.LastName),
new XElement("GENDER", n.Gender),
new XElement("BIRTHDATE", n.BirthDate != null ? n.BirthDate.Value.ToString("yyyy-MM-dd") : "2003-01-01"),
new XElement("LANGUAGE", n.Language),
new XElement("EMAIL", n.Email),
new XElement("STREETNAME", n.StreetName),
new XElement("HOUSENR", n.HouseNr),
new XElement("BOXNR", n.BoxNr),
new XElement("ZIPCODE", n.Zipcode),
new XElement("CITY", n.City),
new XElement("COUNTRY", n.Country),
new XElement("TS", n.Timestamp.ToString("yyyy-MM-dd hh:mm:ss")),
new XElement("MESSAGE_ID", "SCNEWS02"),
new XElement("OPT_INS",
new XElement("OPT_IN",
new XElement("OPT_IN_CBP", "01000000000"),
new XElement("OPT_IN_INSERT_TS", n.Timestamp.ToString("yyyy-MM-dd hh:mm:ss")),
new XElement("OPT_IN_METHOD", "1"),
new XElement("OPT_IN_TYPE", n.OptIn),
new XElement("OPT_IN_CHANNEL", "2"))))));
Thank you very much
Break your query into separate parts, the first part is the query itself. That will be handled by the entity framework. Then cast that query to an IEnumerable<NewsletterData> to finish it off using LINQ to objects. Entity Framework can't do more than a simple projection (which you are clearly not doing).
var query =
from n in _dc.Newsletter_Datas
where n.Timestamp >= startDate
select n;
var news = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement("USER",
from n in query.AsEnumerable() // LINQ to objects
select new XElement("ROW",
new XElement("UTI", n.ID),
new XElement("FIRSTNAME", n.FirstName),
new XElement("FAMILYNAME", n.LastName),
new XElement("GENDER", n.Gender),
new XElement("BIRTHDATE", n.BirthDate != null ? n.BirthDate.Value.ToString("yyyy-MM-dd") : "2003-01-01"),
new XElement("LANGUAGE", n.Language),
new XElement("EMAIL", n.Email),
new XElement("STREETNAME", n.StreetName),
new XElement("HOUSENR", n.HouseNr),
new XElement("BOXNR", n.BoxNr),
new XElement("ZIPCODE", n.Zipcode),
new XElement("CITY", n.City),
new XElement("COUNTRY", n.Country),
new XElement("TS", n.Timestamp.ToString("yyyy-MM-dd hh:mm:ss")),
new XElement("MESSAGE_ID", "SCNEWS02"),
new XElement("OPT_INS",
new XElement("OPT_IN",
new XElement("OPT_IN_CBP", "01000000000"),
new XElement("OPT_IN_INSERT_TS", n.Timestamp.ToString("yyyy-MM-dd hh:mm:ss")),
new XElement("OPT_IN_METHOD", "1"),
new XElement("OPT_IN_TYPE", n.OptIn),
new XElement("OPT_IN_CHANNEL", "2")
)
)
)
)
);

How to build an XDocument with a foreach and LINQ?

I can use XDocument to build the following file which works fine:
XDocument xdoc = new XDocument
(
new XDeclaration("1.0", "utf-8", null),
new XElement(_pluralCamelNotation,
new XElement(_singularCamelNotation,
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
),
new XElement(_singularCamelNotation,
new XElement("id", "2"),
new XElement("whenCreated", "2008-12-31")
)
)
);
However, I need to build the XML file by iterating through a collection like this:
XDocument xdoc = new XDocument
(
new XDeclaration("1.0", "utf-8", null));
foreach (DataType dataType in _dataTypes)
{
XElement xelement = new XElement(_pluralCamelNotation,
new XElement(_singularCamelNotation,
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
));
xdoc.AddInterally(xelement); //PSEUDO-CODE
}
There is Add, AddFirst, AddAfterSelf, AddBeforeSelf, but I could get none of them to work in this context.
Is an iteration with LINQ like this possible?
Answer:
I took Jimmy's code suggestion with the root tag, changed it up a bit and it was exactly what I was looking for:
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement(_pluralCamelNotation,
_dataTypes.Select(datatype => new XElement(_singularCamelNotation,
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
))
)
);
Marc Gravell posted a better answer to this on this StackOverflow question.
You need a root element.
var xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("Root",
_dataTypes.Select(datatype => new XElement(datatype._pluralCamelNotation,
new XElement(datatype._singlarCamelNotation),
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
))
)
);
If I'm not mistaken, you should be able to use XDocument.Add():
XDocument xdoc = new XDocument
(
new XDeclaration("1.0", "utf-8", null));
foreach (DataType dataType in _dataTypes)
{
XElement xelement = new XElement(_pluralCamelNotation,
new XElement(_singularCamelNotation,
new XElement("id", "1"),
new XElement("whenCreated", "2008-12-31")
));
xdoc.Add(xelement);
}
I know it's very very old post but I stumbled across this today trying to solve the same problem. You have to add the element to the Root of the document:
xdoc.Root.Add(xelement);
What's wrong with the simple Add method?

Categories

Resources