xml descendants looping issue in c# - c#

I am unable to get values from xml while looping, i want to get values of each and every element inside HostedService. For e.g. service name, Url etc.
Below is my code
XDocument doc;
using (Stream input = System.IO.File.OpenRead(#"D:\Test.xml"))
{
doc = XDocument.Load(input);
foreach (var events in doc.Root.Descendants("HostedServices")) // loop through all events
{
}
}
XML example:
<HostedServices xmlns="http://schemas.microsoft.com/windowsazure"xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<HostedService>
<Url>https://www.google.com</Url>
<ServiceName>sharepoint2013vm</ServiceName>
<HostedServiceProperties>
<Description i:nil="true" />
<Location>East Asia</Location>
<Label>c2hhcmVwb2ludDIwMTN2bQ==</Label>
<Status>Created</Status>
<DateCreated>2015-01-13T03:42:21Z</DateCreated>
<DateLastModified>2015-01-13T03:42:46Z</DateLastModified>
<ExtendedProperties>
<ExtendedProperty>
<Name>ResourceGroup</Name>
<Value>sharepoint2013vm</Value>
</ExtendedProperty>
<ExtendedProperty>
<Name>ResourceLocation</Name>
<Value>East Asia</Value>
</ExtendedProperty>
</ExtendedProperties>
</HostedServiceProperties>
</HostedService>
<HostedService>
</HostedService>
</HostedServices>

Here is one way to do it.
XDocument doc;
using (Stream input = System.IO.File.OpenRead("XMLFile1.xml"))
{
doc = XDocument.Load(input);
XmlNamespaceManager nm = new XmlNamespaceManager(new NameTable());
XNamespace ns = doc.Root.GetDefaultNamespace();
nm.AddNamespace("ns", ns.NamespaceName);
foreach (var hostedService in doc.Root.XPathSelectElements("ns:HostedService",nm)) // loop through all events
{
if (hostedService.XPathSelectElement("ns:ServiceName", nm) != null)
{
var service = hostedService.XPathSelectElement("ns:ServiceName",nm).Value;
}
if (hostedService.XPathSelectElement("ns:Url",nm) != null)
{
var url = hostedService.XPathSelectElement("ns:Url",nm).Value;
}
}
}

Use this:
XDocument doc = XDocument.Load(#"D:\Test.xml");
to load the XML file in memory.
You have to use XNamespace since your original XML declares one:
XNamespace ns = "http://schemas.microsoft.com/windowsazure";
To loop through all elements of <HostedService> use this:
foreach (var events in doc.Descendants(ns+"HostedService").Elements())
{
}
The above foreach will give you access to all child Elements() of <HostedService>, i.e.
<Url>
<ServiceName> and
<HostedServiceProperties>
If, on the other side, you want to access all elements (including child elements etc.) below <HostedService> then use the following ;
foreach (var events in doc.Descendants(ns + "HostedService").DescendantNodes().OfType<XElement>())
{
}
The above gives you access to:
<Url>
<ServiceName>
<HostedServiceProperties>
<Description>
<Location>
<Label>
... etc.

You need to specify XML namespace with your element name:
XNamespace ns = "http://schemas.microsoft.com/windowsazure";
foreach (var events in doc.Root.Descendants(ns + "HostedServices"))
{
}
Have a look at Working with XML Namespaces for more info.

Related

XmlDocument loping (foreach) reomving NameSpace "xmlns"

hey guys I had XML file and I was using XDocument to write on it and using the next void remove the namespace
string path = Server.MapPath(xmlpath);
XDocument doc = XDocument.Load(path)
XElement root = new XElement("url");
foreach (var node in doc.Root.Descendants()
.Where(n => n.Name.NamespaceName == ""))
{
node.Attributes("xmlns").Remove();
node.Name = node.Parent.Name.Namespace + node.Name.LocalName;
}
this function works 100% with the XDocument now I changed
XDocument oldDoc = XDocument.Load(path);// the old doucument
XmlDocument newDoc = new XmlDocument();//the new document
I need a function that allows me to make loping and remove the namespace xmlns from my nodes the same one like above thanks a lot for your time's guys and thanks a lot for reading my question
You were very close, just had to use XMLDocument.CreateElement(string Name) overload which returns a XMLNode and then use .InnerText property to set your value
var mainRoot = doc.DocumentElement; //urlset element
var urlRoot = doc.CreateElement("url"); //create url element
var VidooTree = urlRoot.AppendChild(doc.CreateElement(a, ""));
urlRoot.AppendChild(doc.CreateElement("loc", "http:/domain/site.com"));
VidooTree.AppendChild(doc.CreateElement(b)).InnerText="imgur";
VidooTree.AppendChild(doc.CreateElement(c)).InnerText= "videoTitle";
VidooTree.AppendChild(doc.CreateElement("video:description")).InnerText= "videoDec";
VidooTree.AppendChild(doc.CreateElement(d)).InnerText= "VideoApi";
VidooTree.AppendChild(doc.CreateElement(m)).InnerText= "duration";
VidooTree.AppendChild(doc.CreateElement(nn)).InnerText= "2050-11-05T19:20:30+08:00";
VidooTree.AppendChild(doc.CreateElement(e)).InnerText= "watched";
VidooTree.AppendChild(doc.CreateElement(k)).InnerText= "date";
VidooTree.AppendChild(doc.CreateElement(f)).InnerText= "yes";
VidooTree.AppendChild(doc.CreateElement(g)).InnerText="No";
VidooTree.AppendChild(doc.CreateElement(h)).InnerText= "VideoKindName";
urlRoot.AppendChild(VidooTree);
mainRoot.AppendChild(urlRoot);
Output
<url xmlns="">
<loc xmlns="http:/domain/site.com" />
<video>
<thumbnail_loc>imgur</thumbnail_loc>
<title>videoTitle</title>
<description>videoDec</description>
<content_loc>VideoApi</content_loc>
<duration>duration</duration>
<expiration_date>2050-11-05T19:20:30+08:00</expiration_date>
<view_count>watched</view_count>
<publication_date>date</publication_date>
<family_friendly>yes</family_friendly>
<live>No</live>
<category>VideoKindName</category>
</video>
</url>

Not able to get values of all elements in XML using XmlNodeList and XmlNamespaceManager

I am parsing below XML. I need value 'x2#email.com'.I am able to get the list of nodes successfully, but the problem is that with each iteration I am still getting 'x1#email.com' from the first group of 'Info' element.
XML:
<ClaimAdminContact xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Services.Models">
<claimAdminID>T1</claimAdminID>
<contactInfo>
<Info>
<desc>Level 1 Notifications</desc>
<emailAddress>x1#email.com</emailAddress>
<orgNum>1234</orgNum>
<type>T2</type>
</Info>
<Info>
<desc>Level 2 Notifications</desc>
<emailAddress>x2#email.com</emailAddress>
<orgNum i:nil="true"/>
<type>T2</type>
</Info>
<Info>
<desc>Level 3 Notifications</desc>
<emailAddress>x3#email.com</emailAddress>
<orgNum i:nil="true"/>
<type>T2</type>
</Info>
</contactInfo>
</ClaimAdminContact>
I have tried full xpath but still not able to get the next set of values. Below is the code that I am using to parse xml.
Code:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlEmail.NameTable);
nsmgr.AddNamespace("MsBuild", xmlns);
var contactInfo = xmlEmail.SelectNodes("/MsBuild:ClaimAdminContact/MsBuild:contactInfo/*", nsmgr);
foreach (XmlNode item in contactInfo)
{
_notificationDesc = item.SelectSingleNode("//MsBuild:desc", nsmgr).InnerText;
_reviewEmail = item.SelectSingleNode("//MsBuild:emailAddress", nsmgr).InnerText;
_orgNum = item.SelectSingleNode("//MsBuild:orgNum", nsmgr).InnerText;
}
Please
Use xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace ns = doc.Root.GetDefaultNamespace();
var results = doc.Descendants(ns + "Info").Select(x => new
{
desc = (string)x.Element(ns + "desc"),
email = (string)x.Element(ns + "emailAddress"),
orgNum = (string)x.Element(ns + "orgNum"),
type = (string)x.Element(ns + "type")
}).ToList();
}
}
}
Using System.Xml.Linq:
var xmlFile = #"myxml.xml";
var xDoc = XDocument.Load(xmlFile);
var infos = xDoc.Descendants("Info");
foreach (var info in infos)
{
var email = info.Element("emailAddress").Value;
}
EDIT: How to work with namespaces
If you have multiple namespaces and want to work with that, then you must specify the namespaces like below. Removing namespaces from the file is hardly a good idea.
var xmlFile = #"C:\Users\gurudeniyas\Desktop\myxml.xml";
XNamespace ns = "http://schemas.datacontract.org/2004/07/Services.Models";
XNamespace nsi = "http://www.w3.org/2001/XMLSchema-instance";
var xDoc = XDocument.Load(xmlFile);
var infos = xDoc.Descendants(ns + "Info");
foreach (var info in infos)
{
var email = info.Descendants(ns + "emailAddress").FirstOrDefault().Value;
Console.WriteLine(email);
}
The main challenge I was facing in parsing xml was the namespace attribute in the root element. It was preventing my code to parse the usual way and that was the reason why I tried using 'XmlNamespaceManager'. I decided to remove the namespace from the xml.
I used below recursive method to remove namespace from xml and everything worked!! I am not sure if this is the optimal way, but I was able to achieve what I wanted.
public XElement RemoveAllNamespaces(XElement root)
{
return new XElement(
root.Name.LocalName,
root.HasElements ?
root.Elements().Select(x => RemoveAllNamespaces(x)) :
(object)root.Value
);
}
Calling Code:
XElement noNsDoc = RemoveAllNamespaces(XElement.Parse(xmlString));
var xDoc = XDocument.Parse(noNsDoc.ToString());

XDocument does not load Xml string properly

I'm trying to do the following: load an Xml string into a XDocument object, but when I try to access elements through Descendants method it return nothing when I tried to see the value of inner elements in Visual Studio it does not recognize it as Xml so what is the problem here?
string xml = #"<ArrayOfKeyValueOfstringint xmlns=""http://schemas.microsoft.com/2003/10/Serialization/Arrays"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<KeyValueOfstringint>
<Key>crscmprsn_ttlprt1</Key>
<Value>1</Value>
</KeyValueOfstringint>
<KeyValueOfstringint>
<Key>ptntmntrfrm_ttlprt1</Key>
<Value>1</Value>
</KeyValueOfstringint>
</ArrayOfKeyValueOfstringint>";
var xdoc = XDocument.Parse(xml);
IEnumerable<XElement> elements = xdoc.Descendants("KeyValueOfstringint");
var lst = new List<KeyValuePair<string,int>>();
foreach (var item in elements)
{
var k = item.Element("Key").Value;
int v = int.Parse(item.Element("Value").Value);
var kvp = new KeyValuePair<string,int>(k,v);
lst.Add(kvp);
}
You need to specify namespace to get your elements:
var ns = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
var elements = xdoc.Descendants(ns + "KeyValueOfstringint");
For more information about xml namespaces take a look at: Working with XML Namespaces

Get XmlNodeList if a particular element value or its attribute value is present in a given list of strings

I would like to get XmlNodeList from a huge XML file.
Conditions:
I have a List of unique ID values, say IDList
Case I: Collect all the nodes where element called ID has value from IDList.
Case II: Collect all nodes where one of the attribute called idName of element ID has value from IDList.
In short, extract only the nodes which match with the values given in the IDList.
I did this using some loops like load this XML to XmlDocument to iterate over all nodes and ID value but what I am looking for is some sophisticated method to do it faster and in quick way.
Because looping isn't a solution for a large XML file.
My try:
try
{
using (XmlReader reader = XmlReader.Create(URL))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNodeList nodeList = doc.GetElementsByTagName("idgroup");
foreach (XmlNode xn in nodeList)
{
string id = xn.Attributes["id"].Value;
string value = string.Empty;
if (IDList.Contains(id))
{
value = xn.ChildNodes[1].ChildNodes[1].InnerText; // <value>
if (!string.IsNullOrEmpty(value))
{
listValueCollection.Add(value);
}
}
}
}
}
catch
{}
XML (XLIFF) structure:
<XLIFF>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2">
<file date="2013-07-17">
<body>
<id idName="test_001" >
<desc-group name="test_001">
<desc type="text"/>
</desc-group>
<result-unit idName="test_001_text">
<source>abcd</source>
<result>xyz</result>
</result-unit>
</id>
</body>
</file>
</xliff>
Collect all the nodes like above where idName matches.
EDIT
This is a test that can parse the example you are giving. It attempts to reach the result node directly, so that it stays as efficient as possible.
[Test]
public void TestXPathExpression()
{
var idList = new List<string> { "test_001" };
var resultsList = new List<string>();
// Replace with appropriate method to open your URL.
using (var reader = new XmlTextReader(File.OpenRead("fixtures\\XLIFF_sample_01.xlf")))
{
var doc = new XmlDocument();
doc.Load(reader);
var root = doc.DocumentElement;
// This is necessary, since your example is namespaced.
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("x", "urn:oasis:names:tc:xliff:document:1.2");
// Go directly to the node from which you want the result to come from.
foreach (var nodes in idList
.Select(id => root.SelectNodes("//x:file/x:body/x:id[#idName='" + id + "']/x:result-unit/x:result", nsmgr))
.Where(nodes => nodes != null && nodes.Count > 0))
resultsList.AddRange(nodes.Cast<XmlNode>().Select(node => node.InnerText));
}
// Print the resulting list.
resultsList.ForEach(Console.WriteLine);
}
You can extract only those nodes you need by using an XPath query. A brief example on how you 'd go about it:
using (XmlReader reader = XmlReader.Create(URL))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
foreach(var id in IDList) {
var nodes = doc.SelectNodes("//xliff/file/body/id[#idName='" + id + "']");
foreach(var node in nodes.Where(x => !string.IsNullOrEmpty(x.ChildNodes[1].ChildNodes[1].InnerText)))
listValueCollection.Add(node.ChildNodes[1].ChildNodes[1].InnerText);
}
}
The xpath expression is of course an example. If you want, you can post an example of your XML so I can give you something more accurate.

Using XPath in C# for get all the node values from XML

I have got XML below:
<tcm:Component ID="tcm:481-636667" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink">
<tcm:Context>
<tcm:Publication xlink:type="simple" xlink:title="07 Internal Test Publication" xlink:href="tcm:0-481-1"/>
<tcm:OrganizationalItem xlink:type="simple" xlink:title="System Resources" xlink:href="tcm:481-92640-2"/>
</tcm:Context>
<tcm:Data>
<tcm:Title>IBE - Skywards</tcm:Title>
<tcm:Type>Normal</tcm:Type>
<tcm:Schema xlink:type="simple" xlink:title="Resources" xlink:href="tcm:481-190471-8"/>
<tcm:Content>
<Resources xmlns="http://www.sdltridion.com/tridion/schemas">
<Text>
<Key>SKYRL_MBD</Key>
<Value>Miles Breakdown</Value>
</Text>
<Text>
<Key>ltSR_MB.Text</Key>
<Value>View Miles Breakdown</Value>
</Text>
<Text>
<Key>ltSR_HMB.Text</Key>
<Value>Hide Miles Breakdown</Value>
</Text>
<Text>
<Key>SKYRL_MBD_LK</Key>
<Value>Miles Breakdown</Value>
</Text>
</Resources>
</tcm:Content>
<tcm:Metadata>
<Metadata xmlns="http://www.sdltridion.com/tridion/schemas">
<Language>
<Language>English</Language>
</Language>
</Metadata>
</tcm:Metadata>
</tcm:Data>
</tcm:Component>
Now I want to write a method in C# which will take this XML as input and will return all the "Key" and "Value" data in List.
Please suggest.
First, declare the lists to keep values:
using System.Collections.Generic;
List<string> keysList = new List<string>();
List<string> valuesList = new List<string>();
Then:
using System.Xml; // System.Xml.dll
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml); // Load(file)
var ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("tcm", "http://www.tridion.com/ContentManager/5.0");
ns.AddNamespace("xlink", "http://www.w3.org/1999/xlink");
foreach (XmlNode node in doc.SelectNodes("//*[local-name()=\"Key\"]"))
{
keysList.Add(node.InnerText);
}
foreach (XmlNode node in doc.SelectNodes("//*[local-name()=\"Value\"]"))
{
valuesList.Add(node.InnerText);
}
if you don't need XML DOM, only XPath to evaluate:
using System.Xml.XPath; // System.Xml.dll
XPathDocument doc = null;
using (TextReader reader = new StringReader(xml))
{
doc = new XPathDocument(reader); // specify just path to file if you have such one
}
XPathNavigator nav = doc.CreateNavigator();
foreach (XPathNavigator node in (XPathNodeIterator)nav.Evaluate("//*[local-name()=\"Key\"]"))
{
keysList.Add(node.Value);
}
foreach (XPathNavigator node in (XPathNodeIterator)nav.Evaluate("//*[local-name()=\"Value\"]"))
{
valuesList.Add(node.Value);
}
Use XElement or XDocument ( Linq2Xml )
XElement xml = XElement.Parse("inputxml");
var keys = xml.Descendants("Key");
OP says he uses .Net 2.0. Then this won't work!
Have a look at the classes in the System.Xml.Linq namespace. If you start with an XDocument you can load your XML and just query the contents using Linq.

Categories