How do I use XML prefixes in C#? - c#

EDIT: I have now published my app: http://pastebin.com/PYAxaTHU
I was trying to make console-based application that returns my temperature.
using System;
using System.Xml;
namespace GetTemp
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(downloadWebPage(
"http://www.andrewmock.com/uploads/example.xml"
));
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
man.AddNamespace("aws", "www.aws.com/aws");
XmlNode weather = doc.SelectSingleNode("aws:weather", man);
Console.WriteLine(weather.InnerText);
Console.ReadKey(false);
}
}
}
Here is the sample XML:
<aws:weather xmlns:aws="http://www.aws.com/aws">
<aws:api version="2.0"/>
<aws:WebURL>http://weather.weatherbug.com/WA/Kenmore-weather.html?ZCode=Z5546&Units=0&stat=BOTHL</aws:WebURL>
<aws:InputLocationURL>http://weather.weatherbug.com/WA/Kenmore-weather.html?ZCode=Z5546&Units=0</aws:InputLocationURL>
<aws:station requestedID="BOTHL" id="BOTHL" name="Moorlands ES" city="Kenmore" state=" WA" zipcode="98028" country="USA" latitude="47.7383346557617" longitude="-122.230278015137"/>
<aws:current-condition icon="http://deskwx.weatherbug.com/images/Forecast/icons/cond024.gif">Mostly Cloudy</aws:current-condition>
<aws:temp units="°F">40.2</aws:temp>
<aws:rain-today units=""">0</aws:rain-today>
<aws:wind-speed units="mph">0</aws:wind-speed>
<aws:wind-direction>WNW</aws:wind-direction>
<aws:gust-speed units="mph">5</aws:gust-speed>
<aws:gust-direction>NW</aws:gust-direction>
</aws:weather>
I'm just not sure how to use XML prefixes correctly here. What is wrong with this?

OK, so based on this XML from the example:
<aws:weather xmlns:aws="http://www.aws.com/aws">
<aws:api version="2.0"/>
<aws:WebURL>http://weather.weatherbug.com/WA/Kenmore-weather.html?ZCode=Z5546&Units=0&stat=BOTHL</aws:WebURL>
<aws:InputLocationURL>http://weather.weatherbug.com/WA/Kenmore-weather.html?ZCode=Z5546&Units=0</aws:InputLocationURL>
<aws:station requestedID="BOTHL" id="BOTHL" name="Moorlands ES" city="Kenmore" state=" WA" zipcode="98028" country="USA" latitude="47.7383346557617" longitude="-122.230278015137"/>
<aws:current-condition icon="http://deskwx.weatherbug.com/images/Forecast/icons/cond024.gif">Mostly Cloudy</aws:current-condition>
<aws:temp units="°F">40.2</aws:temp>
<aws:rain-today units=""">0</aws:rain-today>
<aws:wind-speed units="mph">0</aws:wind-speed>
<aws:wind-direction>WNW</aws:wind-direction>
<aws:gust-speed units="mph">5</aws:gust-speed>
<aws:gust-direction>NW</aws:gust-direction>
</aws:weather>
You're trying to read out which value?
What's wrong with your code is that your XML namespace is wrong:
You have:
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
man.AddNamespace("aws", "www.aws.com/aws");
but the XML namespace is: http://www.aws.com/aws
so you should have:
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
man.AddNamespace("aws", "http://www.aws.com/aws");
So to read out e.g. the temperature, use something like this:
XmlDocument doc = new XmlDocument();
doc.LoadXml(downloadWebPage("http://www.andrewmock.com/uploads/9/1/0/7/9107466/example.xml"));
XmlNamespaceManager man = new XmlNamespaceManager(doc.NameTable);
man.AddNamespace("aws", "http://www.aws.com/aws");
XmlNode temps = doc.SelectSingleNode("/aws:weather/aws:temp", man);
string tempValue = temps.InnerText;
Gives you a value of "40.2" in tempValue
And as Henk Holtermann recommended in his comment - it would be even easier to read this with Linq-to-XML:
XDocument doc = XDocument.Load("http://www.andrewmock.com/uploads/9/1/0/7/9107466/example.xml");
XNamespace aws = "http://www.aws.com/aws";
var weatherNode = doc.Document.Descendants(aws + "weather");
var tempNode = weatherNode.Descendants(aws + "temp").FirstOrDefault();
string tempValue = tempNode.Value;
Of course, this doesn't include any error handling just yet (checking for things like the weatherNode being NULL and stuff like that) - but it gives you an idea.

Related

Using xpath select how do I get the value of this element in example?

with this XML
<?xml version="1.0" encoding="UTF-8"?>
<createTransactionResponse xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<refId>999999999</refId>
<messages>
<resultCode>Ok</resultCode>
<message>
<code>I00001</code>
<text>Successful.</text>
</message>
</messages>
<transactionResponse>
<responseCode>1</responseCode>
<authCode>HH1D69</authCode>
<avsResultCode>Y</avsResultCode>
<cvvResultCode>P</cvvResultCode>
<cavvResultCode>2</cavvResultCode>
<transId>2228993425</transId>
<refTransID />
<transHash>916EE7527B17B62F62AA72B4C71F8322</transHash>
<testRequest>0</testRequest>
<accountNumber>XXXX0015</accountNumber>
<accountType>MasterCard</accountType>
<messages>
<message>
<code>1</code>
<description>This transaction has been approved.</description>
</message>
</messages>
<userFields>
<userField>
<name>MerchantDefinedFieldName1</name>
<value>MerchantDefinedFieldValue1</value>
</userField>
<userField>
<name>favorite_color</name>
<value>blue</value>
</userField>
</userFields>
</transactionResponse>
</createTransactionResponse>
I would like to get "resultCode", from here
<messages><resultCode>Ok</resultCode><message>
But the xpath I'm using does not give me the value of resultCode Ok.
What am I doing wrong?
--
static void Main(string[] args)
{
string myXML = #"<?xml version=""1.0"" encoding=""utf-8""?><createTransactionResponse xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""AnetApi/xml/v1/schema/AnetApiSchema.xsd""><refId>999999999</refId><messages><resultCode>Ok</resultCode><message><code>I00001</code><text>Successful.</text></message></messages><transactionResponse><responseCode>1</responseCode><authCode>HH1D69</authCode><avsResultCode>Y</avsResultCode><cvvResultCode>P</cvvResultCode><cavvResultCode>2</cavvResultCode><transId>2228993425</transId><refTransID /><transHash>916EE7527B17B62F62AA72B4C71F8322</transHash><testRequest>0</testRequest><accountNumber>XXXX0015</accountNumber><accountType>MasterCard</accountType><messages><message><code>1</code><description>This transaction has been approved.</description></message></messages><userFields><userField><name>MerchantDefinedFieldName1</name><value>MerchantDefinedFieldValue1</value></userField><userField><name>favorite_color</name><value>blue</value></userField></userFields></transactionResponse></createTransactionResponse>";
string myValue = XMLSelect(myXML, "createTransactionResponse/messages/message/resultCode");
//myValue should = "Ok" but it does not :(
}
public static string XMLSelect(string _xmldoc, string _xpath)
{
string returnedValue = string.Empty;
XmlDocument doc = new XmlDocument();
try
{
doc.LoadXml(_xmldoc);
XmlElement root = doc.DocumentElement;
returnedValue = (string)doc.SelectNodes(_xpath)[0].InnerText;
}
catch (Exception ex)
{
return "";
}
return returnedValue;
}
Your first problem is that the XML you originally gave isn't valid. You're masking that by returning "" whenever you encounter an exception, so you don't have any information any more.
So the first thing to do IMO is remove the spurious exception handling:
public static string XMLSelect(string _xmldoc, string _xpath)
{
string returnedValue = string.Empty;
XmlDocument doc = new XmlDocument();
doc.LoadXml(_xmldoc);
XmlElement root = doc.DocumentElement;
return (string)doc.SelectNodes(_xpath)[0].InnerText;
}
Now, the problem with the XPath is that all the elements in your XML are in a namespace of AnetApi/xml/v1/schema/AnetApiSchema.xsd - so you'll probably want an XmlNamespaceManager. It's slightly tricky to separate that properly given the way that you've split the load from the XPath, but for the moment you could just introduce an alias of ns for the right namespace.
Next, your XPath is incorrect in that it looks for message/resultCode, when those two elements are peers. You don't want the message part.
Here's a short but complete program which fixes all those problems:
using System;
using System.Xml;
public class Program
{
static void Main(string[] args)
{
// As per the question
string myXML = "...";
string myValue = XMLSelect(myXML, "ns:createTransactionResponse/ns:messages/ns:resultCode");
Console.WriteLine(myValue);
}
public static string XMLSelect(string _xmldoc, string _xpath)
{
string returnedValue = string.Empty;
XmlDocument doc = new XmlDocument();
doc.LoadXml(_xmldoc);
var nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace("ns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd");
XmlElement root = doc.DocumentElement;
return (string)doc.SelectNodes(_xpath, nsm)[0].InnerText;
}
}
If you could use LINQ to XML instead, and simply work on the document instead of passing in the XML text and an XPath selector, it would be simpler:
XDocument doc = XDocument.Parse(xml);
XNamespace ns = "AnetApi/xml/v1/schema/AnetApiSchema.xsd";
string code = (string) doc.Root
.Element(ns + "messages")
.Element(ns + "resultCode");
Console.WriteLine(code);

Reading an XML document with XMLDocument C# 'password' string not returning

I'm trying to read the text in between <keyMaterial></keyMaterial>
I tried using //WLANProfile/MSM/security/sharedKey as the element route, seen in the code below. It refuses to return a value. I have run through the debugger and after the breakpoint at the line: XmlNodeList sharedKeyNodes = wifiProfile.SelectNodes("//WLANProfile/MSM/security/sharedKey");
the SharedKeyNodes object doesn't return a count for. I know it's just a matter of figuring out the element route so I'm not coming here completely hopeless...
System.Xml.XPathNodeList
My XML looks like this:
<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
<name>nosignal</name>
<SSIDConfig>
<SSID>
<hex>6E6F7369676E616C</hex>
<name>nosignal</name>
</SSID>
<nonBroadcast>true</nonBroadcast>
</SSIDConfig>
<connectionType>ESS</connectionType>
<connectionMode>auto</connectionMode>
<autoSwitch>false</autoSwitch>
<MSM>
<security>
<authEncryption>
<authentication>WPA2PSK</authentication>
<encryption>AES</encryption>
<useOneX>false</useOneX>
<FIPSMode xmlns="http://www.microsoft.com/networking/WLAN/profile/v2">false</FIPSMode>
</authEncryption>
<sharedKey>
<keyType>passPhrase</keyType>
<protected>true</protected>
<keyMaterial>01000000D</keyMaterial>
</sharedKey>
</security>
</MSM>
</WLANProfile>
[ EDIT with the help of LB the new code looks like this and it WORKS! ]
[ For anyone that is struggling with a similar problem. ]
My Class is:
class ProfileManager
{
public static string readProfile() {
XmlDocument wifiProfile = new XmlDocument();
string path = #"C:\temp\nosignal.xml";
string password = "";
wifiProfile.Load(path);
XmlNamespaceManager mgr = new XmlNamespaceManager(wifiProfile.NameTable);
mgr.AddNamespace("ns", "http://www.microsoft.com/networking/WLAN/profile/v1");
XmlNodeList sharedKeyNodes = wifiProfile.SelectNodes("//ns:WLANProfile/ns:MSM/ns:security/ns:sharedKey", mgr);
foreach (XmlNode itemNode in sharedKeyNodes)
{
XmlNode keyMaterialNode = itemNode.SelectSingleNode("ns:keyMaterial", mgr);
if (keyMaterialNode != null)
{
password = keyMaterialNode.InnerText;
}
}
return password;
}
}
I'm close, but still just a bit stuck. Any help would be appreciated!!! Thank you!
You don't use the default XmlNamespace "http://www.microsoft.com/networking/WLAN/profile/v1"
wifiProfile.Load(path);
XmlNamespaceManager mgr = new XmlNamespaceManager(wifiProfile.NameTable);
mgr.AddNamespace("ns", "http://www.microsoft.com/networking/WLAN/profile/v1");
XmlNodeList sharedKeyNodes = wifiProfile.SelectNodes("//ns:WLANProfile/ns:MSM/ns:security/ns:sharedKey",mgr);

How to process webdav server XML request in C#

I am writing a custom WebDAV server in C#. One of the client test programs I am using is NetDrive and it claims and appears to be a WebDAV compliant client. My problem is I am receiving a request on the server in the following format:
<?xml version="1.0" encoding="utf-8"?>
<propfind xmlns="DAV:">
<allprop/>
</propfind>
But other clients do this:
<?xml version="1.0" encoding="utf-8"?>
<D:propfind xmlns:D="DAV:">
<D:allprop/>
</D:propfind>
The two different namespace formats keep on fooing up my logic to look for the "allprop" element. My code looks a bit like this:
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\"><allprop/></propfind>"; //Hardcode to make all the StackOverflow users' lives easier
XPathDocument doc = new XPathDocument(new StringReader(xml));
XPathNavigator nav = doc.CreateNavigator();
XPathNodeIterator it = nav.Select("/propfind/*");
Now, I know I need to put in some type of namespace manager for the "DAV:", so I tried this:
XmlNamespaceManager nsman = new XmlNamespaceManager(nav.NameTable);
nsman.AddNamespace("", "DAV");
XPathNodeIterator it = nav.Select("/propfind/*", nsman);
But I'm getting no nodes in my iterator for the first XML file. It seems the default namespace isn't working like I thought it should.
What am I doing wrong? How do I query this XML for the existence of an allprop node when the namespace may be the default, or may be explicitly named?
You are using the wrong namespace in your code. Unforunalely the WebDAV specs use
'DAV:' as the namespace for WebDAV nodes and attributes (this seems to be caused by
a missunderstanding of the XML namespace mechanism).
I ended up looking for the namespace URI (DAV:) and adding it if it didn't exist. Then I just did a namespace-qualified SELECT and it worked in all my test cases:
XPathDocument document = new XPathDocument(xml);
XPathNavigator navigator = document.CreateNavigator();
//Get namespaces & add them to the search
bool hasDAV = false;
string davPrefix = "D";
XmlNamespaceManager nsman = new XmlNamespaceManager(navigator.NameTable);
foreach (KeyValuePair<string, string> nskvp in navigator.GetNamespacesInScope(XmlNamespaceScope.All))
{
if (string.Compare(nskvp.Value, "DAV:", StringComparison.InvariantCultureIgnoreCase) == 0)
{
hasDAV = true;
davPrefix = nskvp.Key;
}
nsman.AddNamespace(nskvp.Key, nskvp.Value);
}
if (!hasDAV)
nsman.AddNamespace(davPrefix , "DAV:");
XPathNodeIterator iterator = navigator.Select("/" + davPrefix + ":" + WebDavXML.PropFind + "/*", nsman);

Append xml string into Existing xmlfile using c#

I have an xml like this :
<name>
<class>
</class>
</name>
then i want to add the tag like this
<tia:Demographic><Age/><DOB/></tia:Demographic>
in between
<class>
How can we do that .
i am using following code.
XDoc.LoadXml(#"<name><class></class></name>");
XmlDocumentFragment xfrag = XDoc.CreateDocumentFragment();
xfrag.InnerXml = #"<tia:Demographic><Age/><DOB/></tia:Demographic>";
XDoc.DocumentElement.FirstChild.AppendChild(xfrag);
XDoc.Save(#"D:\test.xml");
but it throws an error that tia: not a registered namespace
Register the namespace using a XmlNamespaceManager .
You will need to register a namespace:
class Program
{
static void Main()
{
var xdoc = new XmlDocument();
xdoc.LoadXml(#"<name><class></class></name>");
xdoc.DocumentElement.SetAttribute("xmlns:tia", "http://tia.com");
var node = xdoc.CreateElement("tia", "Demographic", "http://tia.com");
var xfrag = xdoc.CreateDocumentFragment();
xfrag.InnerXml = #"<Age/><DOB/>";
node.AppendChild(xfrag);
xdoc.DocumentElement.FirstChild.AppendChild(node);
xdoc.Save(Console.Out);
}
}

"An object reference is required for the non-static field, method, or property"

i am stuck with this small problem in my code.
I am trying to make small console application which will write into xml document.
I have used xmldocument and xmlnode concept.
ERROR i am getting is;
*An object reference is required for the non-static field, method, or property 'Write_xml.Program.give_node(System.Xml.XmlDocument)' C:\Documents and Settings\Administrator\Desktop\Write_xml\Write_xml\Program.cs*
code is okay except 1 error. I am not able to resolve it ,i want somebody to check it and correct it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace Write_xml
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
XmlDocument lets = new XmlDocument();
string path = #"D:\XMLFile.xml";
doc.Load(path);
XmlNode Rootnode = doc.SelectSingleNode("Number");
XmlNode TakenOde = give_node(doc);
Rootnode.AppendChild(TakenOde);
doc.Save(path);
}
public XmlNode give_node(XmlDocument lets)
{
// On this xmldoc we will perform XMLNODE operations
// for creat new nods and append child nodes
//XmlNode RootNode = xmldoc.CreateElement("Root");
XmlNode PersonsNode = lets.CreateElement("Person");
XmlNode NameNode = lets.CreateElement("Name");
PersonsNode.AppendChild(NameNode);
NameNode.InnerText = "1st";
XmlNode AgeNode = lets.CreateElement("Age");
PersonsNode.AppendChild(AgeNode);
AgeNode.InnerText = "2nd";
XmlNode CityNode = lets.CreateElement("City");
PersonsNode.AppendChild(CityNode);
CityNode.InnerText = "3rd";
return PersonsNode;
}
}
}
please let me what small mistake i am doing.
You're trying to call an instance method, but without specifying an instance.
The simplest fix for this is to make the give_node method static.
I haven't looked at the rest of the code to see whether it's okay or not, although give_node should be called GiveNode to follow .NET naming conventions.

Categories

Resources