How to get the value of an XML attribute? - c#

I have a XML file:
<SourceMessage xmlns="test.test">
<updated>2011</updated>
<title type="p1"/>
<title type="p2"/>
<title type="p3"/>
<entry>
</entry>
</SourceMessage>
How could I use LINQ to get the <type> attribute of the <title> element, i.e. "p1", "p2" and "p3"?

Use XDocument.Load or XDocument.Parse to load the XML data into an XDocument. Then, using LINQ, you can get the type for each <title> element under the document root as follows:
XNamespace test = "test.test";
XDocument doc = XDocument.Load(file);
// - or -
XDocument doc = XDocument.Parse("<SourceMessage ...");
IEnumerable<string> query = from title in doc.Root.Elements(test + "title")
select (string)title.Attribute("type");
foreach (string item in query)
{
Console.WriteLine(item);
}
Output:
p1
p2
p3

var xElement XElement.Parse(xmlString);
var result = xElement.Descendants("title")
.Select(e => e.Attribute("type").Value);

XDocument xml = XDocument.Parse (#"<SourceMessage xmlns="test.test">
<updated>2011</updated>
<title type="p1"/>
<title type="p2"/>
<title type="p3"/>
<entry>
</entry>
</SourceMessage>");
foreach (var t in xml.Root.Descendants("title"))
Console.Write(t.Attribute("type").Value);

Related

moving to a node values in linq to xml C#?

I am trying get the email value under author node in C#. But nothing is coming. My Code is=
XDocument xDoc = XDocument.Parse("myxml");
var foos = from xelem in xDoc.Descendants("author")
select xelem.Element("email").Value;
XML which i am using is -
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:batch="http://schemas.google.com/gdata/batch"
xmlns:gContact="http://schemas.google.com/contact/2008" xmlns:gd="http://schemas.google.com/g/2005"
xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">
<id>yogeshcp13#gmail.com</id>
<updated>2015-02-09T04:03:31.220Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/contact/2008#contact"/>
<title type="text">Yogesh Adhikari's Contacts</title>
<link rel="alternate" type="text/html" href="https://www.google.com/"/>
<link rel="next" type="application/atom+xml" href="https://www.google.com/m8/feeds/contacts/yogeshcs2003%40gmail.com/full?max-
results=1&start-index=2"/>
<author>
<name>Yogesh Adhikari</name>
<email>yogeshcp13#gmail.com</email>
</author>
<generator version="1.0" uri="http://www.google.com/m8/feeds">Contacts</generator>
<openSearch:totalResults>3099</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>1</openSearch:itemsPerPage>
</feed>
Can someone point out what is wrong?
Thanks
You need to specify the namespace along with the name when getting the descendants.
XDocument xDoc = XDocument.Parse("myxml");
string ns = xDoc.Root.Name.Namespace;
var foos = from xelem in xDoc.Descendants(ns + "author")
select xelem.Element(ns + "email").Value;
Alternatively, you can find your nodes by getting an enumeration over all descendants, then filtering by LocalName. If email is a node only within authors in your schema, you can also avoid the unnecessary step of drilling down from author nodes, and just find your email nodes directly:
var foos = xdoc.Descendants().Where(e => e.Name.LocalName == "email");
XDocument xDoc = XDocument.Load("myxml.xml");
var foos = xDoc.Descendants().Where(e => e.Name.LocalName == "email");
Console.WriteLine(foos.FirstOrDefault().Value);
Use Load method if you are refering to xml file else parse should be fine. Also make sure xml is along with your binaries' folder if not using specific path.

Replace a nodeset in XmlDocument with another XmlDocument file

I was wondering what would be the best way to do the following:
There are 2 XML files in a directory "Input.xml" and "Metadata.xml".
Input.xml:
<Root>
<Header>
<ID>1</ID>
<Name>Test</Name>
</Header>
<Body>
<MetaDataSet>
<ID>23568</ID>
<Value>metadatavalue1</Value>
</MetaDataSet>
</Body>
</Root>
Metadata.xml:
<MetaDataSet>
<metadatasetvalue>Test</metadatasetvalue>
<Valid>true</Valid>
</MetaDataSet>
What I would like to do is to be able to replace the node set "MetaDataSet" of "Input.xml" with the entire content of the file "Metadata.xml".
So the resulting output would be:
<Root>
<Header>
<ID>1</ID>
<Name>Test</Name>
</Header>
<Body>
<MetaDataSet>
<metadatasetvalue>Test</metadatasetvalue>
<Valid>true</Valid>
</MetaDataSet>
</Body>
</Root>
Is it possible in c# to replace a nodeset with an XmlDocument?
You can read the two Xml documents in two XmlDocument classes, call SelectSingleNode and then replace the InnerXml of the found element with the OuterXml of the meta DocumentElement, like so:
var i = #"
<Root>
<Header>
<ID>1</ID>
<Name>Test</Name>
</Header>
<Body>
<MetaDataSet>
<ID>23568</ID>
<Value>metadatavalue1</Value>
</MetaDataSet>
</Body>
</Root>";
var m = #"
<MetaDataSet>
<metadatasetvalue>Test</metadatasetvalue>
<Valid>true</Valid>
</MetaDataSet>
";
var input2 = new XmlDocument();
input2.Load(new StringReader(i));
var meta2 = new XmlDocument();
meta2.Load(new StringReader(m));
var body2 = input2.DocumentElement["Body"];
body2.InnerXml = meta2.DocumentElement.OuterXml;
// helper to show the result
sb = new StringBuilder();
using(var xw = XmlWriter.Create(sb)) {
input2.Save(xw);
}
sb.Dump("2");
If you are open to change to the XDocument class you can use ReplaceNodes on an element:
var inDoc = XDocument.Parse(i);
var metaDoc = XDocument.Parse(m);
var body = inDoc.Root.Element("Body");
body.ReplaceNodes(metaDoc.Root);
// helper to show the result
var sb = new StringBuilder();
using(var xw = XmlWriter.Create(sb))
{
inDoc.WriteTo(xw);
}
sb.Dump(); // LinqPad helper
It's also possible using ReplaceWith and XPath with LINQ-to-XML.
Assuming the same init as in #rene's answer for variables i and m:
using System.Xml.Linq;
using System.Xml.XPath;
var inDoc = XElement.Parse(i);
var metaDoc = XElement.Parse(m);
inDoc.XPathSelectElement("//Body/MetaDataSet").ReplaceWith(metaDoc);

Simple Xml parse with Xdocument

I want parse xml in windows store app with Xdocument.
I tried this,but returned with null:
XDocument xDoc;
string title= "";
xDoc = XDocument.Load(url);
var elements = from x in xDoc.Descendants()
select new
{
title = x.Descendants("title").First().Value,
};
foreach (var el in elements)
_title = title;
Xml contents:
<title type='text'>tiitle</title>
<content type='text'> gfgdgdggd</content>
<link rel='related' type='application/atom+xml' href='http....'/>
How can is retrive text from attributes ?
As ZevSpitz already mentioned, your XML is invalid. I modified it a bit to be able to test my code:
<root>
<title type="text">title</title>
<content type="text">gfgdgdggd</content>
</root>
You can retrieve values from the type attributes with the following code:
XDocument xDoc = XDocument.Parse(xml);
var types =
from x in xDoc.Root.Descendants()
select x.Attribute("type").Value;
In my case xml is declared as follows:
private string xml =
#"<root>
<title type=""text"">title</title>
<content type=""text"">gfgdgdggd</content>
</root>";
You can still use your code to load the XML from a URL if the file contents are the same.
Try:
var types =
from e in xDoc.Descendants()
select (string)e.Attribute("type");
foreach (string type in types) {
Console.WriteLine(type);
}

Filter XDocument more efficiently

I would like to filter with high performance XML elements from an XML document.
Take for instance this XML file with contacts:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="asistentes.xslt"?>
<contactlist evento="Cena Navidad 2010" empresa="company">
<contact type="1" id="1">
<name>Name1</name>
<email>xxxx#zzzz.es</email>
<confirmado>SI</confirmado>
</contact>
<contact type="1" id="2">
<name>Name2</name>
<email>xxxxxxxxx#zzzze.es</email>
<confirmado>Sin confirmar</confirmado>
</contact>
</contaclist>
My current code to filter from this XML document:
using System;
using System.Xml.Linq;
class Test
{
static void Main()
{
string xml = #" the xml above";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants("contact")) {
Console.WriteLine(element);
var id = element.Attribute("id").Value;
var valor = element.Descendants("confirmado").ToList()[0].Value;
var email = element.Descendants("email").ToList()[0].Value;
var name = element.Descendants("name").ToList()[0].Value;
if (valor.ToString() == "SI") { }
}
}
}
What would be the best way to optimize this code to filter on <confirmado> element content?
var doc = XDocument.Parse(xml);
var query = from contact in doc.Root.Elements("contact")
let confirmado = (string)contact.Element("confirmado")
where confirmado == "SI"
select new
{
Id = (int)contact.Attribute("id"),
Name = (string)contact.Element("name"),
Email = (string)contact.Element("email"),
Valor = confirmado
};
foreach (var contact in query)
{
...
}
Points of interest:
doc.Root.Elements("contact") selects only the <contact> elements in the document root, instead of searching the whole document for <contact> elements.
The XElement.Element method returns the first child element with the given name. No need to convert the child elements to a list and take the first element.
The XElement and XAttribute classes provide a wide selection of convenient conversion operators.
You could use LINQ:
foreach (XElement element in doc.Descendants("contact").Where(c => c.Element("confirmado").Value == "SI"))

Xpath/C#, getting data from multiple namespaces

So, in the XML below using this code sample, i can successfully grab HomeAddress and Name information for each entry from my XML. What if I also need to grab the ID (drivers license numberxxx) information from each entry?
EDIT: Updated XML sample for clarificaiton
Code Sample:
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(responseFromServer);
XmlNamespaceManager xnsmgr = new XmlNamespaceManager(xDoc.NameTable);
xnsmgr.AddNamespace("ns1", "http://www.w3.org/2005/Atom");
xnsmgr.AddNamespace("ns2", "http://strange.com/ns/1.0/");
XmlNodeList xnlInsuredListMembers = xDoc.SelectNodes("//ns2:InsuredListMember", xnsmgr);
foreach (XmlNode xnMember in xnlInsuredListMembers)
{
XmlNode xnHomeAddress = xnMember.SelectSingleNode("ns2:HomeAddress", xnsmgr);
string sHomeAddress = xnHomeAddress.InnerText;
XmlNode xnName = xnMember.SelectSingleNode("ns2:Name", xnsmgr);
string sName = xnName.InnerText;
MessageBox.Show(sHomeAddress + sName);
}
XML Sample
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>someID</id>
<title type="text">Title</title>
<author>
<name>XML Author</name>
</author>
<updated>2010-10-25T20:05:30.267Z</updated>
<link href="currentURL"></link>
<link href="nextURL"></link>
<entry>
<id>Drivers License Numberxxx</id>
<content type="application/vnd.ctct+xml">
<InsuredListMember xmlns="http://strange.com/ns/1.0/">
<HomeAddress>123 anystreet</HomeAddress>
<Name>doe, somegal</Name>
</InsuredListMember>
</content>
</entry>
<entry>
<id>Drivers License Numberxxx</id>
<content type="application/vnd.ctct+xml">
<InsuredListMember xmlns="http://strange.com/ns/1.0/">
<HomeAddress>321 anystreet</HomeAddress>
<Name>doe, someguy</Name>
</InsuredListMember>
</content>
</entry>
</feed>
First, this //ns2:ContactListMember should be //ns2:InsuredListMember according to your input sample.
Second, if the context node is some ns2:InsuredListMember, the the id attribute is selected by this expresion: #id.
If you want the ns1:id child of ns1:entry for the given ns2:InsuredListMember, this XPath expression: ../../ns1:id

Categories