C# Convert xmlnode to key value pair - c#

I am trying to convert the below xml
<variants>
<item>
<name>sport</name>
<description>sport desc</description>
<item-values>
<item-value>
<item>ball</item>
<value>stichball</value>
</item-value>
</item-values>
</item>
</variants>
to xml like below as the nodes splitted to key value pair
<variants>
<item name="sport" description="sport desc">
<item-values>
<item-value item="ball" value="stichball"/>
</item-values>
</item>
</variants>
Is it possible to make this in a generic way

Related

c# custom xml serialization, do not include the name of the nested class list in the xml tags [duplicate]

This question already has an answer here:
Deserializing into a List without a container element in XML
(1 answer)
Closed 2 years ago.
In .NET Coew 3.1 I am trying to generate an XML file of the following class, but without the orders tag showing in the XML file, meaning I have the root tag, than only the list of items
[XmlRoot("data")]
public class PurchaseOrder
{
[XmlElement("orders")]
public Item [] ItemsOrders;
}
[XmlRoot("item")]
public class Item
{
[XmlElement("itemid")]
public string ItemID;
[XmlElement("price")]
public decimal ItemPrice;
}
would result in
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<orders>
<item>
<itemid>aaa111</itemid>
<ItemPrice>34.22</ItemPrice>
</item>
<item>
<itemid>bbb222</itemid>
<price>2.89</price>
</item>
</orders>
</data>
but I need to remove the orders tag. The result I need to produce is
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<item>
<itemid>aaa111</itemid>
<ItemPrice>34.22</ItemPrice>
</item>
<item>
<itemid>bbb222</itemid>
<price>2.89</price>
</item>
</data>
The best way to get the correct classes you require would be to copy the XML you want to the clipboard, and then (in VS2019) Edit/Paste Special/Paste Classes As XML.
This will create the correct classes for the XML you supplied.

XPathSelectElement select the second when there is more than one

Hi Not sure if this can be done but I know someone here will know :)
using
XElement oNodeEquip = xmlDoc.XPathSelectElement("//ItemAry/Item/Equip");
how would I select Equip from the second in the following:
<TestInfo>
<ItemAry>
<Item>
<testData>ABC</testData>
</Item>
<Item>
<testData>XYZ</testData>
<Equip>xxx</Equip>
</Item>
</ItemAry>
</TestInfo>
there will always be at lease 2 <Item> and the node I want the value from will always be in the second <Item>
this is a WPF app using .Net 4.0
Try this XPath expression:
//ItemAry/Item[2]/Equip
It considers only the second <Item> element.
You can easily do it with Linq to Xml:
XDocument xdoc = XDocument.Load(path_to_xml);
var second = (string)xdoc.Descendants("Item").Skip(1).Element("Equip");
Use:
(/*/ItemAry/Item)[2]/Equip
The currently selected answer can produce unexpected results, depending on the specific XML document at hand:
//ItemAry/Item[2]/Equip
selects the Equip children of all Item elements that are the second Item child of their ItemAry parent.
So, if the source XML document is:
<TestInfo>
<ItemAry>
<Item>
<testData>ABC</testData>
</Item>
<Item>
<testData>XYZ</testData>
<Equip>xxx</Equip>
</Item>
</ItemAry>
<ItemAry>
<Item>
<testData>DEF</testData>
</Item>
<Item>
<testData>TUW</testData>
<Equip>yyy</Equip>
</Item>
</ItemAry>
</TestInfo>
the above potentially-wrong expression selects two elements:
<Equip>xxx</Equip>
<Equip>yyy</Equip>
The correct expression provided in this answer:
(/*/ItemAry/Item)[2]/Equip
selects just:
<Equip>xxx</Equip>
If you are ceratin about position of the node, you can use position() function in your XPath:
XElement oNodeEquip = xmlDoc.XPathSelectElement("//ItemAry/Item[position()=2]/Equip");

Ordering XMLDocument.SelectNodes results

I have the following XML which I want to order by priority. Don't fancy using XPath and thought LINQ might work but I get an argument exception thrown with the message "At least one object must implement IComparable."
Can I order the results somehow?
<Root>
<Item>
<Priority><![CDATA[4]]</Priority>
</Item>
<Item>
<Priority><![CDATA[1]]</Priority>
</Item>
<Item>
<Priority><![CDATA[3]]</Priority>
</Item>
</Root>
var result = doc.SelectNodes("//Item");
var ordered = ddddd.Cast<XmlNode>().OrderBy(x => x.SelectSingleNode("Priority")); //EXCEPTION!!!
Change x => x.SelectSingleNode("Priority") to x => x.SelectSingleNode("Priority").InnerText
Oh, and remember, that you will compare strings, not ints, that way.

How to get elements by name in XML using LINQ

I've chosen the title here as my problem is I need to get the Item nodes mentioned in the example.
I have the following XML and am having problems using LINQ to query it, I've been able to parse XML before - however I've been stuck on this for hours and hope someone can help.
Here is my XML data below (example data):
<a:entry
xmlns:a="http://www.w3.org/2005/Atom">
<a:id>98765</a:id>
<info>Data Catalogue</info>
<data>
<items>
<item>
<id>123456</id>
<value>Item One</value>
</item>
<item>
<id>654321</id>
<value>Item Two</value>
</item>
</items>
</data>
<items>
<item>
<id>123456</id>
<value>Item One</value>
</item>
<item>
<id>654321</id>
<value>Item Two</value>
</item>
</items>
<a:author>
<a:name>Catalogue</a:name>
</a:author>
</a:entry>
I want to be able to extract the ID from the Item XML tag under Items, however there is an Items Tag with Item entries under data I DO NOT want these nodes at all - I want root/items/id/id if this were expressed as path. I've tried everything I know with LINQ so if someone could help, things to note although this is sample data it is based on the system - the format cannot be changed so that is not an acceptable solution.
I can't seem to determine where I'm going wrong - every LINQ expression I try returns nothing, I think the namespace is an issue and have tried to integrate this but I'm going in circles.
Solution must work in Silverlight and C#
I have tried the following:
IEnumerable<XElement> nodes =
element.Elements().Where(e => e.Name.LocalName == "items")
However this gets me all the "items" including the ones under "data" I don't want those.
If I do the following on my XML I do see the Names of the Elements displayed:
XElement element = XElement.Parse(data);
foreach (XElement node in element.Elements())
{
MessageBox.Show(node.Name.LocalName);
}
However when I do this I cannot see the node names under items at all - I've checked the XElement and it does have the node and when I output the names above it "items" shows up along with info and id!
foreach (XElement node in element.Elements("items"))
{
MessageBox.Show(node.Name.LocalName);
}
Assuming element is your <a:entry> element:
var ids = element.Element("items")
.Elements("item")
.Select(item => item.Element("id").Value);
The Element and Elements methods return only direct children, not all descendants, so it doesn't return the <items> element which is under <data>
I had a blank Namespace Declaration in my XML I hadn't noticed once I added this into my code it worked - forgot LINQ is very NameSpace oriented!
XNamespace ns = "http://example.org/namespace";
var ids = element.Element(ns + "items")
.Elements("item")
.Select(item => item.Element("id").Value);

trouble parsing deeply nested attributes using LINQ to XML

I have been trying to parse this xml in c#
<schema uri=http://blah.com/schema >
<itemGroups>
<itemGroup description="itemGroup1 label="itemGroup1">
<items>
<item description="The best" itemId="1" label="Nutella"/>
<item description="The worst" itemId="2" label="Vegemite"/>
</items>
</itemGroup>
</itemGroups>
</schema>
\itemGroup1\Nutella-The best
\itemGroup1\Vegemite-The worst
Any help or direction would be appreciated.
XDocument xDoc = XDocument.Load(myXml); //load your XML from file or stream
var rows = xDoc.Descendants("item").Select(x => string.Format(
#"\{0}-{1}\{2}-{3}",
x.Ancestors("itemGroup").First().Attribute("description").Value,
x.Ancestors("itemGroup").First().Attribute("label").Value,
x.Attribute("label").Value,
x.Attribute("description").Value));
Let's break down what we're doing:
xDoc.Descendants("item") gets us all <item> elements in the entire document
Select(x => string.Format(format, args) projects each <item> we got from the last operation into whatever format we specify in the lambda. In this case, a formatted string.
In terms of the XML tree, we're "sitting at" the <item> level, so we need to roll back up the tree to get the data for the parent group using Ancestors. Since that method returns a sequence of elements, we know we want the first (nearest to us) so we can read its attribute.
Now you have an IEnumerable<string>, one for each <item> in your XML document and the information in the format you specified:
foreach(string row in rows)
{
Console.WriteLine(row);
}

Categories