Reading xml file on some condition - c#

I want to use a xml file which is as below
<?xml version="1.0" encoding="utf-8" ?>
<pages>
<page name="Default.aspx">
<method name="Login_click">
<message code="0" description="this is a test description">
<client code="0000000000" description="this is a description for clent 0000000000" />
</message>
</method>
</page>
</pages>
Now I want to create a function like below
public static string GetAppMessage(string pageName, string methodName, string clientCode, string code)
{
var xmlFile = HttpContext.Current.Server.MapPath("~/App_Data/Theme.xml");
var doc = new XmlDocument();
doc.Load(xmlFile);
if (string.IsNullOrEmpty(clientCode))
{
//go to node who page name to pageName
//and read the vlue
}
else
{
//read for a particular client code
}
}
How can I do this.
Edit 1
Do I need to loop through each node or can I reach to a particular node directly and find the decedent nodes.
like below
foreach (XmlNode chldNode in doc.ChildNodes)
{
....

Instead of XmlDocument you can use XDocument and LINQ to xml:
var xmlFile = HttpContext.Current.Server.MapPath("~/App_Data/Theme.xml");
XDocument xmlDoc = XDocument.Load(xmlFile);
var xmlPage = (from page in xmlDoc.Descendants()
where page.Name.LocalName == "page"
&& page.Attribute("name").Value == pageName
select page).FirstOrDefault();
if (xmlPage != null)
{
//do what you need
}

When you use XmlDocument and you know how the XML-file will look like (I mean you know the names of the nodes where the information is inside) then you could do something like this:
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlElement root = doc["NameOfRootNode"];
if (root != null)
{
//For nodes you just need to bypass to get to another subnode:
XmlNode node = root.SelectSingleNode("nameOfAnotherNode");
//For nodes you actually want to do something with, like read text, attribute etc.
if (node != null && node.SelectSingleNode("nameOfOneMoreNode") != null)
{
var xmlElement = node["nameOfOneMoreNode"];
if (xmlElement != null)
{
//Read from the xmlElement you selected and do something with it...
}
}
//...
}
With SelectSingleNode or SelectNodes you can maneuver to a specific known node and can read the InnerText or an Attribute.

You can use XPath to get <page> element by it's name attribute, for example :
string xpath = "//page[#name='{0}']";
XmlNode page = doc.SelectSingleNode(string.Format(xpath, pageName));
//and read the vlue
Basically, above XPath look for <page> element having name attribute equals pageName parameter.

Related

c# adding xml element where attribute equals

I have an xml file that has a bunch of channels, and I want to append a channel category to every single one of them. Depending on what channel it is. I'm very new to this so please excuse me if this is an obvious error.
example:
<channel-category>Entertainment</channel-category>
or
<channel-category>News</channel-category>
I have tried the following:
string path;
string xmlfile = "/channels.xml";
path = Environment.CurrentDirectory + xmlfile;
if (exists("channelname1"))
{
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNode root = doc.DocumentElement;
XmlNode node = root.SelectSingleNode("list/channel[#id='channelname1'");
XmlNode category = doc.CreateElement("channel-category");
category.InnerText = "channelcataegorygoeshere";
node.AppendChild(category);
doc.DocumentElement.AppendChild(node);
}
else
{
Console.WriteLine("not found");
}
Console.ReadKey();
}
static bool exists(string channelname)
{
string path;
string xmlfile = "/channels.xml";
path = Environment.CurrentDirectory + xmlfile;
XDocument xmlDoc = XDocument.Load(path);
bool doesexists = (from data in xmlDoc.Element("list").Elements("channel")
where (string)data.Attribute("id") == channelname
select data).Any();
return doesexists;
}
but it's giving me the following error and I can't figure it out.. What am I doing wrong?
An unhandled exception of type 'System.Xml.XPath.XPathException' occurred in System.Xml.dll
Additional information: 'list/channel[#id='channelname1'' has an invalid token.
from this line
XmlNode node = root.SelectSingleNode("list/channel[#id='channelname1'");
My XML looks like this
<?xml version="1.0" encoding="UTF-8"?>
<list info="list">
<channel id="channelname1">
<display-name lang="en">channelname1</display-name>
<icon src="http://locationtologo.com/" />
<url>http://someurl.com</url>
</channel>
<channel id="channelname2">
<display-name lang="en">channelname2</display-name>
<icon src="http://locationtologo.com/" />
<url>http://someurl.com</url>
</channel>
<channel id="channelname3">
<display-name lang="en">channelname3</display-name>
<icon src="http://locationtologo.com/" />
<url>http://someurl.com</url>
</channel>
<channel id="channelname4">
<display-name lang="en">channelname4</display-name>
<icon src="http://locationtologo.com/" />
<url>http://someurl.com</url>
</channel>
</list>
You dont have closing bracket in list/channel[#id='channelname1'(HERE).
Moreover, you are actually trying to do following:
var doc = new XmlDocument();
doc.Load(Environment.CurrentDirectory + "\\channels.xml");
var nodes = doc.SelectNodes("list/channel[#id=\"channelname1\"]");
if (nodes != null)
{
foreach (XmlNode node in nodes)
{
var el = doc.CreateElement("channel-category");
el.InnerText = "SomeValue";
node.AppendChild(el);
}
}
bool doesexists = (from data in xmlDoc.Element("tv").Elements("channel")
where (string)data.Attribute("id") == channelname
select data).Any();
You are trying to reach the channel node where the id equals the channelname inside tv. The problem is that tv does not exist, the channels are inside this:
<list info="list">
Solution: either put the channels into tv, or use a selector appropriate to your current structure.
Why you are using tv instead of list thats why xml library not getting your path of your elements and throwing this error.
try this..
XmlNode node = root.SelectSingleNode("list/channel");
node.Attributes["id"].Value=="channelname1"?true:false;

Select single node

From the following xml:
<response>
<content>
<Result xmlns="http://www.test.com/nav/webservices/types">
<Name>Test</Name>
</Result>
</content>
<status>ok</status>
</response>
I am trying to get the value of the Name element the following way but that does not work:
private static void Main()
{
var response = new XmlDocument();
response.Load("Response.xml");
var namespaceManager = new XmlNamespaceManager(response.NameTable);
namespaceManager.AddNamespace("ns", "http://www.test.com/nav/webservices/types");
Console.WriteLine(response.SelectSingleNode("/response/content/Result/Name", namespaceManager).InnerXml);
}
How can I select the Name element?
Your code would have worked just fineif the Xml had defined the namespace with a "ns:" prefix.
But in this case, the namespace is given without any prefix, which sets the default namespace for everything in the Result tag to ".../webservice/types".
To reflect this, you need to modify the Xpath, and tell the XmlDocument that the nodes you are looking for under Resultare in the webservice/types namespace. So your query will look like this:
Console.WriteLine(response.SelectSingleNode(#"/response/content/ns:Result/ns:Name", namespaceManager).InnerXml);
For getting directly the text value of a node there is a text() function, if used in the query it would look like:
/response/content/Result/Name/text()
Try this:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.InnerXml = "<response><content><Result xmlns=\"http://www.test.com/nav/webservices/types\"><Name>Test</Name></Result></content><status>ok</status>";
string elementValue = String.Empty;
if (xmlDoc != null)
{
xNode = xmlDoc.SelectSingleNode("/Result");
xNodeList = xNode.ChildNodes;
foreach (XmlNode node in xNodeList)
{
elementValue = node.InnerText;
}
}

How to check XMLNode is exist or not in Windows Phone

I am writing Windows Phone 8 application, and I am getting XML data from web service,in some response, in my XML document I am getting some "Tags" and in other response I do not getting those tags, so how do I check that XNode is exist or not?
See my XML document below:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<Group>
<Id>205647</Id>
<Name>Docs</Name>
</Group>
<Group>
<Id>205648</Id>
<Name>Photos</Name>
</Group>
</root>
Now, in above document, the Descendant "GROUP" is exist in some results and doesn't exist in other results,How do I check that?
Create an extension method like this :
public static string TryGetElementValue(this XElement parentEl, string elementName, string defaultValue = null)
{
var foundEl = parentEl.Element(elementName);
if(foundEl != null)
{
return foundEl.Value;
}
else
{
return defaultValue;
}
}
This approach allows you to keep a clean code with isolating the check of element presence. It also allow you to define a default value, which can be helpful
You could go through all nodes with the XmlTextReader and look for a specific XmlNode Name.
http://www.w3schools.com/xpath/xpath_syntax.asp
Try this snippet with your xml:
XmlDocument doc = new XmlDocument();
doc.Load("your.xml");
//Select the book node with the matching attribute value.
XmlNode nodeToFind;
XmlElement root = doc.DocumentElement;
// Selects all the title elements that have an attribute named group
nodeToFind = root.SelectSingleNode("//title[#group]");
if( nodeToFind != null )
{
// It was found, manipulate it.
}
else
{
// It was not found.
}
Have a look at this too. updating an existing xml file in Windows Phone
Hope it helps!

C# XML How to retrive innerText of field by attribute?

Here is the XML sample:
<?xml version="1.0" ?>
<XMLScreen xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CX>80</CX>
<CY>24</CY>
<Formatted>true</Formatted>
<Field>
<Location position="1" left="1" top="0" length="69" />
<Attributes Base="226" Protected="false" FieldType="High" />
*SDC SCHEDULING CATEGORY UPDATE
</Field>
</XMLScreen>
I want to retrive the Inner text of each field based on its Location position.
What I have so far is:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(myEm.CurrentScreenXML.GetXMLText());
XmlNodeList fields = xmlDoc.GetElementsByTagName("Field");
MessageBox.Show("Field spot: " + i + " Contains: " + fields[i].InnerText);
And I want to be able to just extract the inner text of the field by passing in a number of the location position. So if I say foo[i] I want to be able to get the innertext
*SDC SCHEDULING CATEGORY UPDATE
You should use a xpath search query :
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
int nodeId = 4;
XmlNode node = xmlDoc.SelectSingleNode(String.Format(#"//Location[#position='{0}']", nodeId));
if (node != null)
{
String field = node.ParentNode.InnerText;
}
Something like that, with XDocument instead of XmlDocument (well, if you're not in .net 3.5 or higher, we'll have a problem).
private string GetTextByLocationId(XDocument document, int id)
{
var field = document.Descendants("Field").FirstOrDefault(m => m.Element("Location").Attribute("position").Value == id.ToString());
if (field == null) return null;
return field.Value;
}
and usage
var xDocument = XDocument.Load(<pathToXmlFile or XmlReader or string or ...>);
var result = GetTextByLocationId(xDocument, 1);
EDIT
or if you want a dictionary with :key = position / value = text
private static Dictionary<int, string> ParseLocationAndText(XDocument document)
{
var fields = document.Descendants("Field");
return fields.ToDictionary(
f => Convert.ToInt32(f.Element("Location").Attribute("position").Value),
f => f.Value);
}
Try,
XElement root = XElement.Parse(myEm.CurrentScreenXML.GetXMLText());
XElement field = root.XPathSelectElement(
string.Format("Field[Location/#position='{0}']", 1));
string text = field.Value;
You will need to use the following using to use XPath with XElements.
using System.Xml.XPath;

Parsing XmlDocument with Variable Parent Tags

Assuming I have an XmlDocument like this:
<xmlFile>
<details>
<code1>ADJ</code1>
<code2>ADC </code2>
<Shipment>
<foo></foo>
<bar></bar>
</Shipment>
<Shipment>
<foo></foo>
<bar></bar>
</Shipment>
</details>
<details>
<code1>ADJ</code1>
<code2>SCC </code2>
<Shipment>
<foo></foo>
<bar></bar>
</Shipment>
</details>
</xmlFile>
I need to process each in an xml file but only shipments that fall under the tags with a child node with a value of "ADC". So far I have:
// Assume there is an XmlDocument named xml
XmlNodeList details= xml.GetElementsByTagName("details");
foreach (XmlNode node in details)
{
if (node["code2"].InnerText == "ADC ")
{
// Get each shipment and process it accordingly.
}
}
I can't figure out what to do next. Thanks.
Assuming Data\Sample.xml contains xml as mentioned in the question,
Following is the XLINQ query
XElement root = XElement.Parse(File.ReadAllText(#"Data\Sample.xml"));
var adcShipment = root.Descendants().Where(e=>String.Equals(e.Value, "ADC "));
//next query for nodes/elements inside/next to ADC shipments
XPath can simplify your search for matches:
foreach (XmlNode node in xml.SelectNodes("/xmlFile/details[normalize-space(code2)='ADC']"))
{
string foo = node.SelectSingleNode("foo").InnerText;
string bar = node.SelectSingleNode("bar").InnerText;
}
I'm in the process of adding XPath parsing to this library: https://github.com/ChuckSavage/XmlLib/
I modified it so you can do this:
XElement root = XElement.Load(file);
var shipments = root.XPath("details[starts-with(*,'ADC')]/Shipment");
Long-hand that looks like:
var shipments = root.Elements("details")
.Where(x => x.Elements().Any(xx => ((string)xx).StartsWith("ADC")))
.Elements("Shipment");
This is the sort of thing you're after
XmlNodeList details = xml.GetElementsByTagName("details");
foreach (XmlNode node in details)
{
if (node["code2"].InnerText.Trim() == "ADC")
{
// Get each shipment and process it accordingly.
foreach(XmlNode shipment in node.SelectNodes("Shipment"))
{
var foo = shipment.SelectSingleNode("foo");
var bar = shipment.SelectSingleNode("bar");
}
}
}

Categories

Resources