Start reading from last value in xml - c#

I have this kind of xml file. Root node is Sim and there are multiple "test" subnodes. Also each "test" has an instructor. Finally each instructor has own name,surname and rank values.
<Sim>
<Test ID="1" Description="test1" Date="17/01/2023">
<Instructor Num="1">
<Name>instructor1</Name>
<Surname></Surname>
<Rank></Rank>
</Instructor>
</Test>
<Test ID="2" Description="test2" Date="16/01/2023">
<Instructor Num="22">
<Name>instructor22</Name>
<Surname></Surname>
<Rank></Rank>
</Instructor>
</Test>
</Sim>
With xelement.load, the test ids of this file are read as they are in the file. I want xelement.load to read after test ids are sorted from largest to smallest. How can i do this? instructor part is also included in second code.
<Sim>
<Test ID="3" Description="test3" Date="18/01/2023"></Test>
<Test ID="2" Description="test2" Date="17/01/2023"></Test>
<Test ID="1" Description="test1" Date="16/01/2023"></Test>
</Sim>

Try with XDocument and LINQ
var xDoc = XDocument.Parse(File.ReadAllText("XMLFile2.xml"));
var elements = xDoc.Descendants("Test").OrderByDescending(x=> Convert.ToInt16(x.Attribute("ID").Value));

Related

Select XML node without have the namespace included

I have some XML that has a namespace..
<batch xmlns="http://www.mydomain.uk/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="applications.xsd">
<header>
...
</header>
<applications>
<application>
<details>
<Title>MR</Title>
<Forename>Jonathh</Forename>
<Middlenames>
<Middlename>on</Middlename>
<Middlename>ath</Middlename>
</Middlenames>
<PresentSurname>H</PresentSurname>
</details>
</application>
</applications>
</batch>
I am need to pull out the applications.. which I am able to do - but only by specifying the namespace..
var namespaceManager = new XmlNamespaceManager(doc.NameTable);
namespaceManager.AddNamespace("eb", "http://www.mydomain.uk/batch");
var protectedElement = doc.SelectSingleNode("/eb:batch/eb:applications", namespaceManager);
The problem for me is that the namespace then propagates down to the selected node E.G.
<applications xmlns="http://www.mydomain.uk/batch">
<application>
<details>
<Title>MR</Title>
<Forename>Jonathh</Forename>
<Middlenames>
<Middlename>on</Middlename>
<Middlename>ath</Middlename>
</Middlenames>
<PresentSurname>H</PresentSurname>
</details>
</application>
</applications>
Note the sneaky little xmlns in the applications tag now.. that wasn't there before.. I've tried all sorts of things to remove..
I am so desperate I am considering a regular expression instead (I know!) - which I actually don't think would be too awful here....
Anyone got any suggestions?

Reading data from XML using C#

I have to read the ordertext ("This is an example text") from this XML File:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<order id="">
<users>
<user id="123456" nick="nick" done="false" />
</users>
<machines>
<machine id="1234" sd="1234" ref="" done="false" />
</machines>
<todos />
<ordertexts>
<ordertext>This is an example text </ordertext>
</ordertexts>
</order>
My C# Code looks like this:
XmlDocument xDoc = new XmlDocument();
xDoc.Load(file);
XmlElement node = (XmlElement)xDoc.SelectSingleNode("/order/ordertexts/ordertext");
When I write the selected data in another XML File it looks like this:
<order>
<oldOrderText>System.Xml.XmlElement</oldOrderText>
</order>
What did I do wrong? Is the XPath incorrect?
I am a C# newbie so I really need every help I can get!
Thanks in advance, geibi
What you're looking for is XmlElement.InnerText.
When you get the node using this:
XmlElement node = (XmlElement)xDoc.SelectSingleNode("/order/ordertexts/ordertext");
You still need to use this:
string neededText = node.InnerText;
to get the value of that node.
Suppose that you're writing the results in a console application. If you try to write the node variable, this way:
Console.WriteLine(node);
Since node is not a string, and it's an XmlElement object, the ToString method of XmlElement is going to be called, which returns the object name, hence your new XML had the result as System.Xml.XmlElement and not the desired text.

How to extract a node from xml string C#

I have am xml string like mentioned below:
<?xml version="1.0" encoding="utf-8" ?>
<NodeA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.air-watch.com/webapi/resources">
<AdditionalInfo>
<Links>
<Link xsi:type="link">
</Link>
</Links>
</AdditionalInfo>
<TotalResults>100</TotalResults>
<NodeB>
<NodeC>
<Id>1</Id>
<A>valueA</A>
<B>valueB</B>
</NodeC>
<NodeC>
<Id>2</Id>
<A>valueA</A>
<B>valueA</B>
</NodeC>
</NodeB>
</NodeA>
I want to extract NodeB and its child nodes (NodeC elements). How can I do it? Below solution does somewhat similar operation but it needs the xml string to be loaded in a XDocument first:
XDocument doc=XDocument.Parse(xmlstr);
String response=doc.Elements("question")
.Where(x=>x.Attribute("id")==id)
.Single()
.Element("response")
.Value;
Is there a way to do it without having to load it in a doc? Some operation on string object itself.
Why cant you use this
XDocument doc=XDocument.Parse(xmlstr);
String response=doc.Elements("question")
.Where(x=>x.Attribute("id")==id)
.Single()
.Element("response")
.Value; ?
you can use Regular Expressions then.

Get and Set XML elements with Namespaces

NEWBIE QUESTION.
I haven't worked that much with xml, nothing like this anyway. I have some XML as shown below that I receive which has several namespaces.
I need to read some values, then update others before returning the revised XML with namespaces intact - don't want them removed.
I am given the path to some of the elements like this cred/sub/aa or trip/items/item[0]/customerInfo/custName.
But it seems that namespaces make it difficult to get to those elements so simply.
Does anybody know how I can read some of the values like NON-SMOKING from custPref or get the value CABBAGE from bossman/zz.
Also, I want to be able to then set a value such as custName to say Mr. X.
Any ideas?
Thanks.
<?xml version="1.0" encoding="utf-16" ?>
<A1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<cred xmlns="https://blah-blah.com/?foobar">
<sub>
<aa>Zippo</aa>
<bb>lighter</bb>
</sub>
<reqId>
<cc></cc>
<dateOfBirth></dateOfBirth>
</reqId>
</cred>
<reqName xmlns="http://blah-blah/vader/base">qwerty</reqName>
<reqId xmlns="http://blah-blah/vader/base">12345</reqId>
<machine xmlns="http://blah-blah/vader/base">
<qqq>hello</qqq>
<www>goodbye</www>
<eee>99999</eee>
<rrr>88888</rrr>
</machine>
<monkey xmlns="http://blah-blah/vader/base">alskdjfhg</monkey>
<math xmlns="http://blah-blah/vader/base">
<language></language>
</math>
<trip xmlns="http://blah-blah/simple">
<tripOverview xmlns="http://blah-blah/vader/base">
<description></description>
<cost></cost>
</tripOverview>
<bossman xmlns="http://blah-blah/vader/base">
<zz>CABBAGE</zz>
<yy>BANANA</yy>
<xx>MELON</xx>
<ww>SYRUP</ww>
</bossman>
<items>
<item>
<itemSummary xmlns="http://blah-blah/vader/base">
<description></description>
<cost></cost>
<reference></reference>
</itemSummary>
<customerInfo xmlns="http://blah-blah/vader/base">
<custName></custName>
<custPref>NON-SMOKING</custPref>
</customerInfo>
<seatId xmlns="http://blah-blah/vader/base">1</seatId>
</item>
</items>
</trip>
</A1>
string xml = "<Root><Options></Options></Root>";
var xdocs = XDocument.Parse(xml);
xdocs.Descendants().Where(q => q.Name == "Options").FirstOrDefault().Value = "FoundIt";

LINQ for XML, having trouble reading in multiple elements of varying occurences

Let's say I have the following XML file below. My question is, how to I account for a different number of name elements (child of environment element) when querying using LINQ. I can read the file and even query when there are the same number of name elements (for example, they all have 3). My goal is to populate an object that has a list caled environment with the names in the XML file. Any help would be appreciated.
<database type="prod">
<name>DB1</name>
<server>
<name>prodserver.net</name>
</server>
<connection>
<name>u1</name>
<password>b1</password>
</connection>
<environment>
<name>test1</name>
<name>test2</name>
<name>test3</name>
</environment>
</database>
<database type="dev">
<name>DB2</name>
<server>
<name>devserver.net</name>
</server>
<connection>
<name>u11</name>
<password>b11</password>
</connection>
<environment>
<name>test1</name>
<name>test2</name>
<name>test3</name>
<name>test4</name>
<name>test5</name>
</environment>
</database>
Or maybe to make it even easier, let's say I have the following
<student name="A" class="1">
<classes>
Math
</classes>
</student>
<student name="B" class="2">
<classes>
Programming
</classes>
</student>
And I run the following code:
var students = doc.Root
.Elements("student")
.Select(x => new Student
{
Name = (string)x.Attribute("name"),
Class = (string)x.Attribute("class"),
Type = (string)x.Elements("classes").Single().Value
})
.ToList();
It works fine, but when I add one more classes element, it breaks:
<student name="A" class="1">
<classes>
Math
</classes>
<classes>
Java
</classes>
</student>
<student name="B" class="2">
<classes>
Programming
</classes>
</student>
It's not really clear what you mean... assuming you have (say) an Environment type with a constructor accepting a List<string> as the names, you'd use:
// If element is the <environment> element
Environment = new Environment(element.Elements("name")
.Select(x => x.Value)
.ToList());

Categories