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

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

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

How do I put a foreach loop inside of a XDocument in creation?

I have a small problem with an XDocument that I am creating. I am trying to use a foreach loop inside of the document creation, but I have no idea how to pull it off.
Code:
Some of the code:
XDocument doc = null;
doc = new XDocument(
new XDeclaration("1.0", "ISO-8859-1", "no"),
new XElement("data",
new XElement("meta",
new XElement("val",
new XAttribute("n", "printer"), DropDownPrinters.SelectedItem.Text),
new XElement("val",
new XAttribute("n", "autoprint"), "YES"),
new XElement("val",
new XAttribute("n", "test"), 0)
), //after this I need to loop through datarows, something like this
foreach (DataTable dt in ds3.Tables)
{
foreach (DataRow dr in dt.Rows)
{
new XElement("something",
new XAttribute("something", dr.Field<string>("3")),
new XElement("val",
new XAttribute("n", "something"), dr.Field<string>("0") + " " + dr.Field<string>(4) + " " + dr.Field<string>(5)),
new XElement("val",
new XAttribute("n", "something"), dr.Field<string>("0")),
new XElement("val",
new XAttribute("n", "something"), dr.Field<string>("0")),
new XElement("val",
new XAttribute("n", "something"), dr.Field<string>("0")),
new XElement("val",
new XAttribute("n", "something"), "SE"),
new XElement("val",
new XAttribute("n", "something"), dr.Field<string>("0")),
new XElement("val",
new XAttribute("n", "something"))
);
}}
Use LINQ instead of foreach, something like this :
var something = from dt in ds.Tables.OfType<DataTable>()
from dr in t.AsEnumerable()
select
new XElement("something",
new XAttribute("something", dr.Field<string>("3")),
......
......
);
Then you can put the variable, something, in the place where your foreach supposed to be.

XDocument Error Nonwhitespace

I'm getting an error when trying to build an XDocument. The error is happening inside System.XML.Linq.Xdocument under the code
internal override void ValidateString(string s) {
if (!IsWhitespace(s)) throw new ArgumentException(Res.GetString(Res.Argument_AddNonWhitespace));
}
This code is generating a Null Reference Exception. Below is MY code for the XDocument, I'm lost as to where something I'm doing is causing this.
XDocument folderviewContents = new XDocument(
new XDeclaration("1.0", "utf8", "yes"),
new XElement("LVNPImport",
new XAttribute("xmlns" + "xsd", XNamespace.Get("http://www.w3.org/2001/XMLSchema")),
new XAttribute("xmlns" + "xsi", XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance"))),
new XElement("InterfaceIdentifier", "835"),
//Start of FolderPaths
new XElement("FolderPaths",
new XElement("Folder",
new XAttribute("fromDate", "TEST"),
//attributes for Folder w/ lots of attributes
new XAttribute("toDate", "TEST"),
new XAttribute("contactName", "APerson"),
new XAttribute("email", "AnEmail"),
//value for that long Folder w/ lots of attributes
"Remittance Advice"),
//Facility
new XElement("Folder", "TEST"),
//PayorID
new XElement("Folder", "TEST"),
//RemitDate Year
new XElement("Folder","TEST"),
//RemitDate Month/Year
new XElement("Folder","TEST")),
new XElement("DocumentType", "RA"),
new XElement("DocumentDescription","TEST"),
new XElement("TotalFiles", "1"));
//Create a writer to write XML to the console.
XmlTextWriter writer = null;
writer = new XmlTextWriter(Console.Out);
//Use indentation for readability.
writer.Formatting = Formatting.Indented;
writer.Indentation = 4;
folderviewContents.WriteTo(writer);
writer.WriteEndDocument();
writer.Close();
Console.ReadLine();
Edit
Updated code
You were creating more than one element at root level. Assuming LVNPImport is your root node, just moving one closing bracket fixes this:
XDocument folderviewContents = new XDocument(
new XDeclaration("1.0", "utf8", "yes"),
new XElement("LVNPImport",
new XAttribute("xmlns" + "xsd", XNamespace.Get("http://www.w3.org/2001/XMLSchema")),
new XAttribute("xmlns" + "xsi", XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance")),
new XElement("InterfaceIdentifier", "835"),
//Start of FolderPaths
new XElement("FolderPaths",
new XElement("Folder",
new XAttribute("fromDate", "TEST"),
//attributes for Folder w/ lots of attributes
new XAttribute("toDate", "TEST"),
new XAttribute("contactName", "APerson"),
new XAttribute("email", "AnEmail"),
//value for that long Folder w/ lots of attributes
"Remittance Advice"),
//Facility
new XElement("Folder", "TEST"),
//PayorID
new XElement("Folder", "TEST"),
//RemitDate Year
new XElement("Folder", "TEST"),
//RemitDate Month/Year
new XElement("Folder", "TEST")),
new XElement("DocumentType", "RA"),
new XElement("DocumentDescription", "TEST"),
new XElement("TotalFiles", "1")));
I have tested this locally, and the XDocument is created without errors.

How to add XElements dynamically in a loop?

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

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

Categories

Resources