Handling duplicate nodes in XML - c#

Scenario:
I am parsing values from an XML file using C# and have the following method:
private static string GetXMLNodeValue(XmlNode basenode, string strNodePath)
{
if (basenode.SelectSingleNode(strNodePath) != null)
return (basenode.SelectSingleNode(strNodePath).InnerText);
else
return String.Empty;
}
To get a particular value from the XML file, I generally pass the root node and a path like "parentnode/item"
I recently ran into an issue where two nodes at the same document level share the same name.
Why:
The duplicate nodes all need to be read and utilized; they have child nodes with differing values (which can distinguish them). At present I just have two nodes, each named <Process> and sub-nodes named <Name> which contain unique names. Other sub-nodes contain various values such as memory usage. When processing and storing the values for the sub-nodes, I would essentially ignore the parent node name and use my own names based on the sub-node <Name> value.
Question:
What is the best way to get the values for duplicate-named nodes distinctly? My thought was to load all values matching the node name into an array and then using the array index to refer to them. I'm not sure how to implement that, though. (I'm not well-versed in XML navigation.)
Sample XML
<?xml version="1.0" ?>
<info>
<processes>
<process>
<name>program1</name>
<memory_use>24.8</memory_use>
</process>
<process>
<name>program2</name>
<memory_use>19.0</memory_use>
</process>
</processes>
</info>

Use SelectNodes method instead it gives you a list of all nodes matching your Xpath

The answer to your question is, "it depends".
It depends on what you intend to do with the "duplicate" nodes. What does it mean for there to be more than one with the same name? Was it an error in the program that generated the XML? Was it correct, and an unlimited number of such nodes is permitted? What do they mean when there are more than one?
You need to answer those questions first, before designing code that processes "duplicate" nodes.

Related

How to insert the new element on XMLNode in C#

I am trying to insert a new element into the XmlNode in C# code,
How to insert the <delimiter>##<delimiter> element in inside the "/TestBooks/template/field" root. (Screenshot1)
enter image description here
Inside the <field> element, i need to insert the <delimiter> element, based on id element <Id>11-09-2020-505</Id>. (Screenshot2)
enter image description here
First of all you really shouldn't use pictures in questions -- we are taking the time to type you an answer you can take the time to use copy and paste and format your questions.
I'd like to answer your questions but I'm concerned about the questions because it implies that you are adding in markers to aid in the parsing of the data. You really shouldn't need to parse XML.
There are many great parsers of XML including one built into C# you should not roll your own.
In the XML standard the order of the children not defined. If you put a child as the "first" child, there is no reason to expect that a parser would list it as first.
(To have order in children you should just add an order attribute)
Because of these reason it should not matter where in the list of children you add the child.
So we can tell you how to add a child but we can't "put it in a specific spot" since children don't have an order.
In summary, it is not possible to do what you ask.

Nested XML to CSV, generic code

This is a tough one.
I have to deal with some XML files we've got from our suppliers. The files contain the products and the variants (color, size, and such). Some of the suppliers send us plain XMLs, containing one root node per variant, having the product name repeated on every row, other suppliers send us nested XMLs, containing the product as root, variants as children nodes.
I have searched the site before asking this question, all the answers I found start with the assumption the XML structure is known.
In my case, it's not. Tomorrow I can get files from a new supplier, with a different structure/different column names.
My goal is to convert the nested xml into a plain xml (i.e. having only root nodes, and repeat the product name for all the new created rows).
Is this even possible? Any idea?

How do you cycle through nodes in XML file [duplicate]

This question already has answers here:
Reading Xml with XmlReader in C#
(7 answers)
Closed 6 years ago.
I have an XML file and the structure is roughly like this:
<ScenarioList>
<Scenario>
... various things
</Scenario>
</ScenarioList>
This is being read into a WPF dialog box. Every time the user selects 'Next' I want to read the next Scenario data into the various fields. Obviously, the same thing goes for the user clicking on the 'Last' button, too.
But the question is: how do i just read in the information from the selected Scenario node?
Let me to try and clarify the question since it appears that it is 'overly broad':
I am familiar with loading and reading entire XML files. I just want to selectively read specific nodes. For example: How can I read just the data for the first Scenario node? Then, depending on user input, read just the data for the second Scenario node? Then, depending on user input, read just the data for the first scenario node? Or just the third scenario node?
In essence, I'm asking since XML doesn't have an 'index' how do I specify which instance of a node to read?
First you need to load the xml into an XmlDocument, then you can select the specific nodes and iterate over them, like this:
XmlDocument xml = new XmlDocument();
xml.LoadXml("your xml");
XmlNodeList list = xml.SelectNodes("/ScenarioList/Scenario");
foreach (XmlNode xn in list)...
You can traverse to node by using JXPath.
If you need to evaluate multiple paths relative to a certain node in the object graph, you might want to create a relative JXPathContext.
First, obtain the pointer for the location that is supposed to be the root the relative context. Then obtain the relative context by calling
JXPathContext context = JXPathContext.newContext(bean);
Pointer addressPtr = context.getPointer("/employees[1]/addresses[2]");
JXPathContext relativeContext =
context.getRelativeContext(addressPtr);
// Evaluate relative path
String zipCode = (String)relativeContext.getValue("zipCode");
// Evaluate absolute path
String name = (String)relativeContext.getValue("/employees[1]/name");
// Use the parent axis to locate the employee for the current address
Double salary = (Double)relativeContext.getValue("../salary");
you can refer in more detail from here

How to generically map XML element to Enum value

I'm receiving a xml string, and I want to get each element in the xml and pass it to a scriptprocessor in another system. The other system accepts xml input, so I want to map from:
<elements>
<element1>value1<element1/>
<element2>value2<element2/>
<elements/>
to:
<functions>
<function objectypeid="othervalue1" objectid="anothervalue1" attributetypeID="element1" value="value1"/>
...
<functions/>
othervalue and anothervalue comes from other enums in the system. The only values I'm interested in is the element name and its value.
The problem is that I don't know exactly what the name of the elements from the first xml are, and I have a enum for all legal attributetypeIDs.
The first xml can be null, contain only a closing tag or contain a tag with several childs. There is never more than one level beneath root. I don't know how many childs or the name of the childs.

Cloning elements and changing its order by comparing xml's

I have a source xml which needs to be compared against xml template(another xml file).
The following needs to be implemented,
The order of the source xml needs to be transformed as per the order in the template xml.
If the elements in the template xml are not found in the source xml then it should be added.
Basically what should I need to do this, compare 2 xml's and need to change one xml based on other.
I have an idea of creating XDocument with 2 xml's and by accessing xpath of source xml from template xml, Rearrange the elements and add elements if not found.
Please advise whether this is a better approach, or anything can be added into this?

Categories