I'm trying to build an XML file that reads the content to put inside from a list:
List<Snack> trashFoods
When I create the XML file, it would be something like this:
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment(""),
new XElement("Snacks",
trashFoods.Select(snack =>
new XElement("Type", snack.Type),
new XElement("Name", snack.Name)
),
)
What I want to, and I am unable to do is something like putting conditionals inside the construction of the XML file. Similar to this:
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment(""),
new XElement("Snacks",
trashFoods.Select(snack =>
new XElement("Type", snack.Type),
if(snack.Type == "Doritos")
{
new XElement("GotSauce", snack.Sauce),
}
new XElement("Name", snack.Name)
),
)
Is this such a thing even possible with LINQ to XML even if the syntax is not the same?
LINQ to XML objects are not immutable, so you can rewrite your declarative code into imperative one using Add():
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment("")
);
XElement snacks = new XElement("Snacks");
foreach (var snack in trashFoods)
{
snacks.Add(new XElement("Type", snack.Type));
if(snack.Type == "Doritos")
snacks.Add(new XElement("GotSauce", snack.Sauce));
snacks.Add(new XElement("Name", snack.Name));
}
doc.Add(snacks);
It's not very pretty, but it work. Another approach would be to extract the conditional code into a method using yield return:
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment(""),
new XElement("Snacks",
trashFoods.Select(snack => GetSnackChildren(snack))));
…
IEnumerable<XElement> GetSnackChildren(Snack snack)
{
yield return new XElement("Type", snack.Type);
if(snack.Type == "Doritos")
{
yield return new XElement("GotSauce", snack.Sauce);
}
yield return new XElement("Name", snack.Name);
}
This looks better, but it splits code that probably should be together.
You could try this (which will always have a GotSauce element):
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment(""),
new XElement("Snacks",
trashFoods.Select(snack =>
new XElement("Snack",
new XElement("Type", snack.Type),
new XElement("Name", snack.Name),
new XElement("GotSauce", snack.Type=="Doritos" ? snack.Sauce : "")
)
)
));
or this (which won't)
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment(""),
new XElement("Snacks",
trashFoods.Select(snack =>
snack.Type=="Doritos" ?
new XElement("Snack",
new XElement("Type", snack.Type),
new XElement("Name", snack.Name),
new XElement("GotSauce", snack.Sauce)) :
new XElement("Snack",
new XElement("Type", snack.Type),
new XElement("Name", snack.Name))
)
)
);
or this (which doesn't either)
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment(""),
new XElement("Snacks",
trashFoods.Select(snack =>
new XElement("Snack",
new XElement("Type", snack.Type),
new XElement("Name", snack.Name),
snack.Type=="Doritos" ? new XElement("GotSauce", snack.Sauce) : null
)
)
));
Related
I am generating a XML file with hundreds of thousands of elements and the runtime of my code is currently over 3 minutes! I have tried both XDocument and XmlDocument to see if either would decrease the runtime; XDocument was better, but only by a small margin. Is there anything else I can try?
Code
string path = Server.MapPath("~/Temp/employee.xml");
XDocument d = new XDocument(new XElement("Employees"));
d.Declaration = new XDeclaration("1.0", "utf-8", "true");
while (reader.Read())
{
d.Root.Add(new XElement("Employee",
new XElement("LastName", reader["lastname"].ToString()),
new XElement("FirstName", reader["firstname"].ToString()),
new XElement("MiddleInitial", reader["middleini"].ToString()),
new XElement("ID", reader["id"].ToString()),
new XElement("Title", reader["title"].ToString()),
new XElement("DOB", reader["title"].ToString()),
new XElement("Category", reader["category"].ToString()),
new XElement("Supervisor", reader["supervisor"].ToString()),
new XElement("CurrentAddress", reader["address1"].ToString()),
new XElement("Address", reader["address2"].ToString()),
new XElement("City", reader["city"].ToString()),
new XElement("State", reader["state"].ToString()),
new XElement("ZipCode", reader["zip"].ToString()),
new XElement("OfficePhone", reader["office_phone"].ToString()),
new XElement("HomePhone", reader["home_phone"].ToString()),
new XElement("Email", reader["email_address"].ToString()),
new XElement("DateHired", reader["chem_employment_date"].ToString()),
new XElement("DateTerminated", reader["emp_terminate_date"].ToString()),
new XElement("StatusCode", reader["status_code"].ToString()),
new XElement("Room", reader["room"].ToString()),
new XElement("IsPrivate", reader["isprivate"].ToString()),
new XElement("Floor", reader["floor"].ToString()),
new XElement("Wing", reader["wing"].ToString()),
new XElement("InRoster", reader["isroster"].ToString()),
new XElement("RosterCategory", reader["roster_category"].ToString()),
new XElement("LastModified", reader["lastmodified"].ToString()),
new XElement("ShowReport", reader["isbudget"].ToString()),
new XElement("ModifiedBy", reader["lastmodifiedby"].ToString())
));
d.Save(path);
}
Try using the xmlwriter class
https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmlwriter?view=net-5.0
C# export of large datatbase to XML
XmlWriter uses less memory than XmlDocument, but you will have to write the entire document from scratch each time.
I'm using [Produces("application/xml")] data annotation to return my response in XML but unfortunately it do not return any thing. When I remove [Produces] data annotation it returns me data in JSON format. I've also added AddXmlSerializerFormatters() formatter.
Here is my controller action
[HttpGet("Generate")]
[Produces("application/xml")]
public XDocument Get()
{
XDocument sitemap = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
new XElement("urlset", XNamespace.Get("http://www.sitemaps.org/schemas/sitemap/0.9"),
from item in business
select CreateItemElement(item)
)
);
return Ok(sitemap.ToString());
}
Here is my ConfigureService method in startup class
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddXmlSerializerFormatters()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<ListingDbContext>
(options => options.UseSqlServer(Configuration.GetConnectionString("App4Rental_Website_DB")));
services.AddTransient<IRentalRepository, RentalRepository>();
services.AddTransient<IScrapingRepository, ScrapingRepository>();
}
Its working fine JSON result but not working for XML. I'm unable to understand problem.
For XDocument, it should not be serialized to xml format.
In general, we return Object like Product with xml formatter. You could try return Product to test [Produces("application/xml")].
If you want to return XDocument, you may consider return string directly like
public string Get()
{
XDocument srcTree = new XDocument(
new XComment("This is a comment"),
new XElement("Root",
new XElement("Child1", "data1"),
new XElement("Child2", "data2"),
new XElement("Child3", "data3"),
new XElement("Child2", "data4"),
new XElement("Info5", "info5"),
new XElement("Info6", "info6"),
new XElement("Info7", "info7"),
new XElement("Info8", "info8")
)
);
XDocument doc = new XDocument(
new XComment("This is a comment"),
new XElement("Root",
from el in srcTree.Element("Root").Elements()
where ((string)el).StartsWith("data")
select el
)
);
return doc.ToString();
}
Update:
The expected result is caused by the wrong XDocument creation. Try something like below:
XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
XDocument sitemap = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
new XElement(ns + "urlset",
new XElement(ns + "url",
new XElement(ns + "loc", "http://app4rental.com/business/100/r.s.-enterprises"),
new XElement(ns + "lastmod", "2019-08-01"),
new XElement(ns + "changefreq", "weekly"),
new XElement(ns + "priority", "0.8")
)));
return sitemap.ToString();
I have a dictionary with key value pair. I want to write it to XML using LINQ.
I am able to create the XML document using LINQ but not sure how to read the values from dictionary & write into the XML.
Following is the example with hardcode values to generate XML, I want to ready the dictionary instead of hardcode values
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "true"),
new XElement("countrylist",
new XElement("country",
new XAttribute("id", "EMP001"),
new XAttribute("name", "EMP001")
),
new XElement("country",
new XAttribute("id", "EMP001"),
new XAttribute("name", "EMP001")
)
)
);
If the id attribute is stored as dictionary key and the name as value, you can use the following
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "true"),
new XElement("countrylist",
dict.Select(d => new XElement("country",
new XAttribute("id", d.Key),
new XAttribute("name", d.Value))))
);
Assuming you have a Country class with an Id and a Name and the countries are stored as values in your dictionary countries, with the id beeing the key:
XDocument xDoc = new XDocument(new XDeclaration("1.0", "utf-8", "true"));
var xCountryList = new XElement("countrylist");
foreach(var kvp in countries)
xCountryList.Add(new XElement("country",
new XAttribute("id", kvp.Key),
new XAttribute("name", kvp.Value.Name)));
Here dude with the dictionary
Dictionary<int, string> fooDictionary = new Dictionary<int, string>();
fooDictionary.Add(1, "foo");
fooDictionary.Add(2, "bar");
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "true"),
new XElement("countrylist")
);
var countryList = doc.Descendants("countrylist").Single(); // Get Country List Element
foreach (var bar in fooDictionary) {
// Add values per item
countryList.Add(new XElement("country",
new XAttribute("id", bar.Key),
new XAttribute("name", bar.Value)));
}
I am new to XML and tried the following but I'm getting an exception. Can someone help me?
The exception is This operation would create an incorrectly structured document
My code:
string strPath = Server.MapPath("sample.xml");
XDocument doc;
if (!System.IO.File.Exists(strPath))
{
doc = new XDocument(
new XElement("Employees",
new XElement("Employee",
new XAttribute("id", 1),
new XElement("EmpName", "XYZ"))),
new XElement("Departments",
new XElement("Department",
new XAttribute("id", 1),
new XElement("DeptName", "CS"))));
doc.Save(strPath);
}
Xml document must have only one root element. But you are trying to add both Departments and Employees nodes at root level. Add some root node to fix this:
doc = new XDocument(
new XElement("RootName",
new XElement("Employees",
new XElement("Employee",
new XAttribute("id", 1),
new XElement("EmpName", "XYZ"))),
new XElement("Departments",
new XElement("Department",
new XAttribute("id", 1),
new XElement("DeptName", "CS"))))
);
You need to add root element.
doc = new XDocument(new XElement("Document"));
doc.Root.Add(
new XElement("Employees",
new XElement("Employee",
new XAttribute("id", 1),
new XElement("EmpName", "XYZ")),
new XElement("Departments",
new XElement("Department",
new XAttribute("id", 1),
new XElement("DeptName", "CS")))));
In my case I was trying to add more than one XElement to xDocument which throw this exception. Please see below for my correct code which solved my issue
string distributorInfo = string.Empty;
XDocument distributors = new XDocument();
XElement rootElement = new XElement("Distributors");
XElement distributor = null;
XAttribute id = null;
distributor = new XElement("Distributor");
id = new XAttribute("Id", "12345678");
distributor.Add(id);
rootElement.Add(distributor);
distributor = new XElement("Distributor");
id = new XAttribute("Id", "22222222");
distributor.Add(id);
rootElement.Add(distributor);
distributors.Add(rootElement);
distributorInfo = distributors.ToString();
Please see below for what I get in distributorInfo
<Distributors>
<Distributor Id="12345678" />
<Distributor Id="22222222" />
</Distributors>
So let's assume this is what i want to achieve:
<root>
<name>AAAA</name>
<last>BBBB</last>
<children>
<child>
<name>XXX</name>
<last>TTT</last>
</child>
<child>
<name>OOO</name>
<last>PPP</last>
</child>
</children>
</root>
Not sure if using XElement is the simplest way
but this is what I have so far:
XElement x = new XElement("root",
new XElement("name", "AAA"),
new XElement("last", "BBB"));
Now I have to add the "children" based on some data i have.
There could be 1,2,3,4 ...
so I need to iterate thru my list to get every single child
foreach (Children c in family)
{
x.Add(new XElement("child",
new XElement("name", "XXX"),
new XElement("last", "TTT"));
}
PROBLEM:
Doing this way I will be missing the "CHILDREN Parent node".
If I just add it before the foreach, it will be rendered as a closed node
<children/>
and that's NOT what we want.
QUESTION:
How can I add to the 1st part a parent node and as many as my list has?
Try this:
var x = new XElement("root",
new XElement("name", "AAA"),
new XElement("last", "BBB"),
new XElement("children",
from c in family
select new XElement("child",
new XElement("name", "XXX"),
new XElement("last", "TTT")
)
)
);
XElement root = new XElement("root",
new XElement("name", "AAA"),
new XElement("last", "BBB"));
XElement children = new XElement("children");
foreach (Children c in family)
{
children.Add(new XElement("child",
new XElement("name", c.Name),
new XElement("last", c.Last));
}
root.Add(children);
var children = new XElement("children");
XElement x = new XElement("root",
new XElement("name", "AAA"),
new XElement("last", "BBB"),
children);
foreach (Children c in family)
{
children.Add(new XElement("child",
new XElement("name", "XXX"),
new XElement("last", "TTT"));
}