LINQ To XML Getting a value without the nodes inside - c#

I have this XML:
<chunk type="manufacturer_info" id="" note="">test: <chunk type="style" style="link">${manufacturer_website}</chunk></chunk>
I need to get "test: " separately from the inner element.
EDIT:
This is coming into a function as an XElement.

The <chunk> element has two child nodes: a text node and a <chunk> element.
You can get the value of the text node as follows:
var element = XElement.Parse(#"<chunk type=""manufacturer_info"" ...");
var result = string.Concat(element.Nodes().OfType<XText>());
// result == "test: "

Here you go.
string xml = #"<Chunks><chunk type='manufacturer_info' id='' note=''>test: <chunk type='style' style='link'>${manufacturer_website}</chunk></chunk></Chunks>";
var xDoc = XDocument.Parse(xml);
var res = xDoc.DescendantNodes().OfType<XText>().First().Value;

Related

How to replace element of xml using xdocument in c#

example xml:
<string-name>
<given-name>Sisgon</given-name>
</string-name>
changes of xml element:
<string-name>
<surname>Sisgon</surname>
</string-name>
I want to change the given-name tag to surname without changing the inner text.
How about this
XDocument xmlDoc = XDocument.Parse(content);
var event_nodes = xmlDoc.Descendants("given-name");
foreach(var node in event_nodes)
{
node.Name = "surname";
}
System.Diagnostics.Debug.WriteLine(xmlDoc.ToString());
To add an attribute add the following in the for each:
XAttribute attribute = new XAttribute("Name","value");
node.Add(attribute)

Get Top Most Parent From XML

How do I get the top most parent element from XML? I need the entire element with its attributes.
It wont always be the first line as there might be comments.
string xmlStr = File.ReadAllText(#"C:\Users\GRPAdmin\Desktop\Test.xml");
XElement str = XElement.Parse(xmlStr);
var h1 = str.Parent;
var h2 = str.XPathSelectElements("..").FirstOrDefault();
var h3 = str.XPathSelectElement("..").Parent;
<FILE NAME="ABC" version="14.0.0.112" State="WIP" Template="ABC123" origin="designer">
<REC NAME="Recipient">
<FLD NAME="FirstName">James</FLD>
</REC>
<REC NAME="Message">
<FLD NAME="Key">123</FLD>
</REC>
<REC NAME="Details">
<FLD NAME="Key">default</FLD>
</REC>
</File>
I would expect to have a var that equals <FILE NAME="ABC" version="14.0.0.112" State="WIP" Template="ABC123" origin="designer"> as the desired result
In XML data model, the opening tag (including all the attributes), tag content, and the closing tag is single XML element object, so it isn't natural to request only the opening tag. I'm not aware of a bult-in .NET function to get that, but you can reconstruct the opening tag string by combining information of the tag name, and all the attribute name-value pairs, for example :
string xmlStr = File.ReadAllText(#"C:\Users\GRPAdmin\Desktop\Test.xml");
XElement str = XElement.Parse(xmlStr);
var attributes = String.Join(" ", str.Attributes().Select(o => String.Format("{0}=\"{1}\"", o.Name, o.Value)));
var result = string.Format("<{0} {1}>", str.Name, attributes);
Console.WriteLine(result);
Dotnetfiddle Demo
output :
<FILE NAME="ABC" version="14.0.0.112" State="WIP" Template="ABC123" origin="designer">
You can use XElement.AncestorsAndSelf() to walk up the chain of parent XML elements to the root element. Enumerable.Last then gives you the root element:
var root = element.AncestorsAndSelf().Last();
If the XElement is contained by some XDocument, you can always do
var root = element.Document.Root;
But in your case you parsed directly to an XElement without bothering to create an XDocument container.
as #har07 already said, str is the top most element. If you want the attributes just iterate over them
string xmlStr = File.ReadAllText(#"C:\Users\GRPAdmin\Desktop\Test.xml");
var root = XElement.Parse(xmlStr);
foreach (var attribute in root.Attributes())
{
Console.WriteLine("{0} : {1}", attribute .Name, attribute.Value);
}

Adding info to a xml file

I have a XML file which contains about 850 XML nodes. Like this:
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>
........ 849 more
And I want to add a new Childnode inside each and every Node. So I end up like this:
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
<Description>TestDescription</Description>
</NameValueItem>
........ 849 more
I've tried the following:
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
XmlNodeList nodes = doc.GetElementsByTagName("NameValueItem");
Which gives me all of the nodes, but from here am stuck(guess I need to iterate over all of the nodes and append to each and every) Any examples?
You need something along the lines of this example below. On each of your nodes, you need to create a new element to add to it. I assume you will be getting different values for the InnerText property, but I just used your example.
foreach (var rootNode in nodes)
{
XmlElement element = doc.CreateElement("Description");
element.InnerText = "TestDescription";
root.AppendChild(element);
}
You should just be able to use a foreach loop over your XmlNodeList and insert the node into each XmlNode:
foreach(XmlNode node in nodes)
{
node.AppendChild(new XmlNode()
{
Name = "Description",
Value = [value to insert]
});
}
This can also be done with XDocument using LINQ to XML as such:
XDocument doc = XDocument.Load(xmlDoc);
var updated = doc.Elements("NameValueItem").Select(n => n.Add(new XElement() { Name = "Description", Value = [newvalue]}));
doc.ReplaceWith(updated);
If you don't want to parse XML using proper classes (i.e. XDocument), you can use Regex to find a place to insert your tag and insert it:
string s = #"<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>";
string newTag = "<Description>TestDescription</Description>";
string result = Regex.Replace(s, #"(?<=</Code>)", Environment.NewLine + newTag);
but the best solution is Linq2XML (it's much better, than simple XmlDocument, that is deprecated at now).
string s = #"<root>
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>
<NameValueItem>
<Text>Test2</Text>
<Code>Test2</Code>
</NameValueItem>
</root>";
var doc = XDocument.Load(new StringReader(s));
var elms = doc.Descendants("NameValueItem");
foreach (var element in elms)
{
element.Add(new XElement("Description", "TestDescription"));
}
var text = new StringWriter();
doc.Save(text);
Console.WriteLine(text);

xpath to select elements with last child value

This is my xml file
<profiles>
<profile id='8404'>
<name>john</name>
<name>mark</name>
</profile>
<profile id='8405'>
<name>john</name>
</profile>
</profiles>
and I want to select profiles where last "name" child value= john, the result should contains the profile with id=8405 only
what it the xpath that can evaluate this?
here is my trial:
var filterdFile = profilefileXML.XPathSelectElements("/profiles/profile[name[last()]='john']");
but it doesn't make sense.
Updated:
My trail is correct, there was only a syntax error in it. Thanks all
You can apply multiple indexing operations with successive [...]:
var doc = XDocument.Parse(xml); //the xml from your question
var node = doc.XPathSelectElement("/profiles/profile[name='john'][last()]");
Console.WriteLine(node.Attribute("id").Value); //outputs 8405
This will return the last profile element that contains the element name with a value of john.
If you on the other hand want to return all elements which last name element has a value of john, your XPath should work already:
var nodes = doc.XPathSelectElements("/profiles/profile[name[last()]='john']");
foreach (var node in nodes)
{
Console.WriteLine(node.Attribute("id").Value);
}
You can also try LINQ
XDocument xDoc = XDocument.Load("data.xml");
var matches = xDoc.Descendants("profile")
.Where(profile => XElement.Parse(profile.LastNode.ToString()).Value == "john");
And you can access the xml data with a foreach
foreach(XElement xEle in lastEle)
{
var xAttribute = xEle.Attribute("id");
if (xAttribute != null)
{
var id = xAttribute.Value;
}
var lastName = XElement.Parse(xEle.LastNode.ToString()).Value;
}

how to read value from XML?

The data:
<sys>
<id>SCPUCLK</id>
<label>CPU Clock</label>
<value>2930</value>
</sys>
<sys>
<id>CPUTEMP</id>
<label>CPU Temp</label>
<value>39</value>
</sys>
This is the code that I'm using to read the data:
XmlDocument document = new XmlDocument();
document.LoadXml(data);
XmlElement node = document.SelectSingleNode("/sys/value") as XmlElement;
Console.WriteLine("node = " + node);
The issue: Console.WriteLine("node = " + node); doesn't give me any output besides node: but no actual value like 2930 from the sample above.
Thanks
use node.value ie., XmlElement.value
As an alternative to using XmlDocument, you can also use LINQ to XML (which is my preference):
using System.Xml.Linq;
XDocument xDoc = new XDocument();
// Parse loads the XDocument with XML from a string
xDoc = XDocument.Parse(data);
string node = (from x in xDoc.Root.Elements("value")
select x.Value).SingleOrDefault();
Console.WriteLine("node = " + node);
Nothing wrong with using XmlDocument, especially for what you're doing, but you might want to check out LINQ to XML when you get a chance, as I find it a lot easier to work with than XmlDocument.
If you want to get all the "value" elements, simply remove the SingleOrDefault() from the query, and then you can loop through the result, like this:
var nodes = from x in xDoc.Root.Elements("value")
select x.Value;
foreach (var node in nodes)
{
Console.WriteLine("node = " + node);
}
Here's a site worth checking out:
LINQ to XML - 5 Minute Overview

Categories

Resources