How to format XDocument code to make it the most readable - c#

I've written a method to serialize a list (containing class objects) into an xml string, but with so many nests I can't figure out how to format my code to make it the most readable. Here's the xml example:
<Text>
<Info name="example" language="en-US">example</Info>
<Info name="example" language="en-GB">example</Info>
</Text>
And here's the (most likely) terribly formatted code:
XDocument xdoc = new XDocument
(
new XElement
("Text",
Infos.Select(item =>
new XElement
("Info",
new XAttribute("name", item.Name),
new XAttribute("language", item.Language),
item.Value)
)
)
);
return xdoc.ToString();
This is a fairly short example, but it may grow in the future and as such, I'd like to make my code the most readable - how do I do that here?

I like this format
//Option 1
XDocument xdoc1 = new XDocument();
xdoc1.Add(new XElement("Text",
Infos.Select(item => new XElement("Info",
new XAttribute("name", item.Name),
new XAttribute("language", item.Language),
item.Value
)
)
));
//Option 2
XDocument xdoc2 = new XDocument();
xdoc2.Add(new XElement("Text", new object[] {
Infos.Select(item => new XElement("Info", new object[] {
new XAttribute("name", item.Name),
new XAttribute("language", item.Language),
item.Value
}))
}));

Related

Produces data annotation not working for xml in asp.net core 2.1

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

Generate XML from Dictionary

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

Create XML document with namespaces in C#

I'm trying to generate an XML document like the one below. I tried several solution but when I add the namespace, I have the namespace almost everywhere
like
<FieldB xlmns="">BBBBB</FieldB>
Do you have an idea how to get this ?
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<value attributeA="A" attributeB="B" xmlns:XXX="http://MyURLA" xmlns="http://MyURLB">
<FieldA>AAAAA</FieldA>
<FieldB>BBBBB</FieldB>
<FieldB>BBBBB</FieldB>
<status attributeC="C">
<FieldC>ValueFieldC</FieldC>
</status>
<LastUpdate date="2011-02-11T10:00:56.350" login="testing"/>
<XXX:Infos>
<XXX:Info>
<XXX:InfoA>false</XXX:InfoA>
<XXX:InfoB>false</XXX:InfoB>
</XXX:Info>
</XXX:Infos>
</value>
You could use a XNamespace:
public class Program
{
static void Main()
{
XNamespace nsA = "http://MyURLA";
XNamespace nsB = "http://MyURLB";
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement(
nsB + "value",
new XAttribute(XNamespace.Xmlns + "XXXX", nsA),
new XAttribute("attributeA", "A"),
new XAttribute("attributeB", "B"),
new XElement("FieldA", "AAAA"),
new XElement("FieldA", "BBBB"),
new XElement("FieldC", "CCCC"),
new XElement(
"status",
new XAttribute("attributeC", "C"),
new XElement("FieldC", "ValueFieldC")
),
new XElement(
"LastUpdate",
new XAttribute("date", DateTime.Now),
new XAttribute("login", "testing")
),
new XElement(
nsA + "Infos",
new XElement(nsA + "InfoA", false),
new XElement(nsA + "InfoB", false)
)
)
);
Console.WriteLine(doc.ToString());
}
}
I suspect the problem is that you're not putting FieldA, FieldB etc in the right namespace - you don't want to have an explicit namespace declaration in the XML, but the XML you've shown will actually have them in the namespace with URL http://MyURLB, due to the way defaults are inherited.
I suspect if you just use:
XNamespace nsB = "http://MyURLB";
var doc = ... {
new XElement(nsB + "value",
...
new XElement(nsB + "FieldA", "AAAA");
new XElement(nsB + "FieldB", "BBBB");
new XElement(nsB + "FieldC", "CCCC");
...
)
};
then it'll be fine. The FieldA (etc) elements won't have an explicit namespace reference, because they're in the same namespace as their parent element.

XMLString needs to change the format

my xml DATA IS like:(This is xmlstring not an xmlfile and i need to transform without saving....)
<ProductGroups>
<ProductGroup>
<Name>ABC</Name>
<Id>123</Id>
</ProductGroup>
<ProductGroup>
<Name >xyz</Name>
<Id>456</Id>
</ProductGroup>
<ProductGroup>
<Name>PQR</Name>
<Id>789</Id>
</ProductGroup>
.
.
</ProductGroups>
I want to transform like this
<PRODUCTGROUPS>
<Name ID="123"> ABC</NAME>
<Name ID="456"> XYZ</NAME>
<Name ID="789">PQR</NAME>
.
.
</PRODUCTGROUPS>
I'm using C# with .NET.
From memory, may contain some errors:
var doc = XDocument.Load(...);
var groups = doc.Descendants(ProductGroup);
var newDoc = new XElement("ProductGroups",
groups.Select(pg => new XElement("Name",
new XAttribute("Id", pg.Element("Id").Value),
pg.Element("Name").Value) ));
newDoc.Save(...);
You could try it with linq2xml : (EDIT : roughly the same aproach as Henk Holterman)
XDocument sourceDocument = XDocument.Load("D:\\XmlFile.xml");
XDocument targetDocument = new XDocument();
var productGroupsElement = new XElement("ProductGroups");
sourceDocument.Descendants("ProductGroup").ToList().ForEach(productGroup =>
{
if (productGroup.Element("Name") != null && productGroup.Element("Id") != null)
{
var nameElement = new XElement("Name", productGroup.Element("Name").Value);
nameElement.Add(new XAttribute("Id", productGroup.Element("Id")));
productGroupsElement.Add(nameElement);
}
});
targetDocument.Add(productGroupsElement);
var resultXml = targetDocument.ToString(SaveOptions.None);

XElement => Add children nodes at run time

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

Categories