views:

367

answers:

2

Hi,

Trying to parse some XML but apparently this is too much for a lazy sunday afternoon,

this is my code: (I Tried the XPathDocument and XmlDocument approach too but this also failed miserably)

 XmlDocument xmlDoc = new XmlDocument();
 xmlDoc.LoadXml(postData);
 XDocument xDoc = XDocument.Load(new XmlNodeReader(xmlDoc)); 
 XNamespace soapEnv = "http://schemas.xmlsoap.org/soap/envelope/";
 XElement xEnv = xDoc.Descendants(soapEnv + "Envelope").First();
 XElement xBody = xEnv.Descendants(soapEnv + "Body").First();
 XElement xReadReply = xBody.Descendants("ReadReplyReq").First();

The last line fails with the exception: no elements in this collection however if I change this last line into:

 XElement xReadReply = xBody.Descendants().First();

it returns the first node which in fact is the "ReadReplyReq" node.

Having finally gotten these Namespaces working, it now fails on the first node without a namepace... ooh bitter irony ;^)

This is the XML I'm trying to parse:

 <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"&gt;
      <SOAP-ENV:Header>
           <TransactionID xmlns="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2" SOAP-ENV:actor="" SOAP-ENV:mustUnderstand="1">12345678</TransactionID>
      </SOAP-ENV:Header>
      <SOAP-ENV:Body>
           <ReadReplyReq xmlns="http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2"&gt;
                <MMStatus>Read</MMStatus>
                <TimeStamp>2007-12-13T14:05:27+01:00</TimeStamp>
                <MessageID>54321</MessageID>
                <Sender>
                     <ShortCode>+12345</ShortCode>
                </Sender>
                <Recipient>
                     <Number>+12345</Number>
                </Recipient>
                <StatusText>Message has been read</StatusText>
                <MM7Version>5.3.0</MM7Version>
           </ReadReplyReq>
       </SOAP-ENV:Body>
 </SOAP-ENV:Envelope>

what last step am I missing here?

thanks

R

p.s. and why can't the XPath not just be something more intuitive like: "//SOAP-ENV:Envelope/SOAP-ENV:Body/ReadReplyReq/MMStatus", instead of all these crazy hoops one has to jump through.

+1  A: 

I am guessing what you want is to add a namespace manager so you can XPath select on prefixed nodes?

If so then something like:

XmlDocument doc = new XmlDocument();

doc.LoadXml(postData);
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
ns.AddNamespace("def", "http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2");
XmlNode list = doc.SelectSingleNode("//SOAP-ENV:Envelope/SOAP-ENV:Body/def:ReadReplyReq/def:MMStatus", ns);

Is probably what you want.

tyranid
where did you get this namespace def from???
Toad
def is just a dummy prefix put into the namespace manager to identify the default namespace used on the sub-nodes of Body
tyranid
I've converted your answer to my linq code and indeed it works. The default namespace did the trick. How could you see that the url you have is indeed the needed value for the default namespace? in the xml I only see the attribute somewhere: xmlns (xml namespace?) Is this some default tag which is always used?
Toad
Err I guess you perhaps need to read up more on XML Namespace support :) If you specify xmlns= it will apply that namespace URL to all sub-nodes without a prefix. So as MMStatus is under ReadReplyRequest it takes up the default set above.
tyranid
I never encountered namespaces before...never needed it. I was already happy that with a lot of googling I got as far as I got ;^) I really think xml has gotten a bit over the top. Thank god for json ;^)
Toad
A: 

You don't need XPath you just need a namespace for the xReadReply element. Declare the namespace just like you did for the soap elements and use it when searching for that element.

    XNamespace transNS = "http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2";

XElement xReadReply = xBody.Descendants(transNS + "ReadReplyReq").First();
Mike