0

Can anybody tell me why navigating xml with an instruction fails :

StringBuilder   sb2 = new System.Text.StringBuilder();
XmlDocument     doc = new XmlDocument( );

// --- XML without instruction -> Parsing succeeds 
sb1.AppendLine( @"<MetalQuote>");
sb1.AppendLine( @"<Outcome>Success</Outcome>");
sb1.AppendLine( @"<Ask>1073.3</Ask>");
sb1.AppendLine( @"</MetalQuote>");

doc.LoadXml( sb1.ToString( ));
System.Diagnostics.Debug.WriteLine( doc.SelectSingleNode( "//MetalQuote/Outcome").InnerText);

This works well, but the same XML with an instruction fails :

// --- XML with instruction -> Parsing fails 
sb2.AppendLine( @"<MetalQuote xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""http://www.xignite.com/services"" >");
sb2.AppendLine( @"<Outcome>Success</Outcome>");
sb2.AppendLine( @"<Ask>1073.3</Ask>");
sb2.AppendLine( @"</MetalQuote>");

doc.LoadXml( sb2.ToString( ));
System.Diagnostics.Debug.WriteLine( doc.SelectSingleNode( "//MetalQuote/Outcome").InnerText);

I get an exception at the doc.SelectSingleNode statement.

Steef
  • 569
  • 5
  • 21
  • 1
    @varocarbas: um, this *is* how you escape quotes in C# verbatim strings (`@"..."`). – Luke Woodward Dec 12 '15 at 20:25
  • Your last reference (xignite.com/services) is wrong; your code works fine with the first 2 first elements. Regarding the last one, you would have to adapt it to the expected format (do some research, finding it out should be easy). – varocarbas Dec 12 '15 at 20:28
  • Thanks, but do you mean with 'wrong' ? What exactly is wrong ? – Steef Dec 12 '15 at 20:32
  • You might need a `XmlNameSpaceManager` object because you've added a namespace in the failing example. [See MSDN for the `SelectSingleNode()` override](https://msdn.microsoft.com/en-us/library/h0hw012b%28v=vs.110%29.aspx) – radarbob Dec 12 '15 at 20:32
  • @varocarbas It just reads nicer – Steef Dec 12 '15 at 20:33
  • @Steef The XML format has very specific rules, which has to be respected. When parsing it there are some options to relax these checks. – varocarbas Dec 12 '15 at 20:33
  • Ok, but this xml is not made by me but I am receiving it from a stock provider.... – Steef Dec 12 '15 at 20:34
  • Thanks to all of you for, very helpful! – Steef Dec 12 '15 at 20:36
  • @Steef this problem has been asked many times here in SO : http://stackoverflow.com/questions/33852858/how-to-select-particular-node-from-xml/33853184#33853184 . I understand it is hard to find a good keyword for searching if you didn't know the term "default namespace" – har07 Dec 13 '15 at 02:43

2 Answers2

1

In your version with instructions you are using a custom namespace. Each node will inherit that and you have to take it into account when requesting the node data. One way to do it is to use XmlNamespaceManager. Below a version of your code that applies the manager:

class Program
{
    static void Main(string[] args)
    {
        StringBuilder sb2 = new System.Text.StringBuilder();
        XmlDocument doc = new XmlDocument();

        // --- XML with instruction -> Parsing fails 
        sb2.AppendLine(@"<MetalQuote xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""http://www.xignite.com/services"" >");
        sb2.AppendLine(@"<Outcome>Success</Outcome>");
        sb2.AppendLine(@"<Ask>1073.3</Ask>");
        sb2.AppendLine(@"</MetalQuote>");
        doc.LoadXml(sb2.ToString());

        // Create a manager
        XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
        xnm.AddNamespace("abc", @"http://www.xignite.com/services");

        // Use the namespace for each node
        System.Diagnostics.Debug
            .WriteLine(doc.SelectSingleNode(@"//abc:MetalQuote/abc:Outcome", xnm).InnerText);
    }
}

There other options available as well. Check this blog post for more details.

PiotrWolkowski
  • 8,408
  • 6
  • 48
  • 68
0

Here are two ways with 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
    {
        static void Main(string[] args)
        {
            StringBuilder sb2 = new System.Text.StringBuilder();

            sb2.AppendLine(@"<MetalQuote xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""http://www.xignite.com/services"" >");
            sb2.AppendLine(@"<Outcome>Success</Outcome>");
            sb2.AppendLine(@"<Ask>1073.3</Ask>");
            sb2.AppendLine(@"</MetalQuote>");

            XDocument doc = XDocument.Parse(sb2.ToString());
            XElement outCome = doc.Descendants().Where(x => x.Name.LocalName == "Outcome").FirstOrDefault();

            XElement metalQuote = (XElement)doc.FirstNode;
            XNamespace ns = metalQuote.Name.Namespace;
            XElement outCome2 = doc.Descendants(ns + "Outcome").FirstOrDefault();


        }
    }
}
​
jdweng
  • 33,250
  • 2
  • 15
  • 20