1

I am simply trying to read a particular node from an XML and use it as a string variable in a condition. This gets me to the XML file and gives me the whole thing.

string url = @"http://agent.mtconnect.org/current";
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(url);
        richTextBox1.Text = xmlDoc.InnerXml;

But I need the power state "ON" of "OFF" (XML section below, can view the whole XML online)

<Events><PowerState dataItemId="p2" timestamp="2013-03-11T12:27:30.275747" name="power" sequence="4042868976">ON</PowerState></Events>

I have tried everything I know of. I am just not that familiar with XML files. and the other posts get me nowhere. HELP PLEASE!

2 Answers2

2

You may try LINQ2XML for that:

  string value = (string) (XElement.Load("http://agent.mtconnect.org/current")
            .Descendants().FirstOrDefault(d => d.Name.LocalName == "PowerState"))
the_joric
  • 11,986
  • 6
  • 36
  • 57
  • tried this and got An unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll – user2139891 Mar 11 '13 at 17:39
  • Linq seems to stay connected to the XML where the other just runs once and its done. Whats missing from the_joric's code? – user2139891 Mar 11 '13 at 22:19
  • My fault. Fixed the code. Your document has root namespace. In this case you need to either use `LocalName` or specify namespace in the name. Also I changed `First()` to `FirstOrDefault()`. Former raises an exception when element is not found while latter just returns null. – the_joric Mar 12 '13 at 15:02
0

If you wanted to avoid LINQ, or if it is not working for you you can use straight XML traversal for this:

    string url = @"http://agent.mtconnect.org/current";
    System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
    xmlDoc.Load(url);
    System.Xml.XmlNamespaceManager theNameManager = new System.Xml.XmlNamespaceManager(xmlDoc.NameTable);
    theNameManager.AddNamespace("mtS", "urn:mtconnect.org:MTConnectStreams:1.2");
    theNameManager.AddNamespace("m", "urn:mtconnect.org:MTConnectStreams:1.2");
    theNameManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");

    System.Xml.XmlElement DeviceStreams = (System.Xml.XmlElement)xmlDoc.SelectSingleNode("descendant::mtS:DeviceStream", theNameManager);
    System.Xml.XmlNodeList theStreams = DeviceStreams.SelectNodes("descendant::mtS:ComponentStream", theNameManager);

    foreach (System.Xml.XmlNode CompStream in theStreams)
    {
        if (CompStream.Attributes["component"].Value  == "Electric")
        {
            System.Xml.XmlElement EventElement = (System.Xml.XmlElement)CompStream.SelectSingleNode("descendant::mtS:Events", theNameManager);
            System.Xml.XmlElement PowerElement = (System.Xml.XmlElement)EventElement.SelectSingleNode("descendant::mtS:PowerState", theNameManager);
            Console.Out.WriteLine(PowerElement.InnerText);
            Console.In.Read();
        }
    }

When traversing any document with a default namespace in the root node, I have found it is imperative to have a namespace manager. Without it the document is just un-navigable.

I created this code in a console application. It worked for me. Also I am no guru and I may be making some mistakes here. I am not sure if there is some way to have the default namespace referenced without naming it (mtS). Anyone who knows how to make this cleaner or more efficient please comment.

EDIT:

For one less level of 'clunk' you can change this:

if (CompStream.Attributes["component"].Value  == "Electric")
{
    Console.Out.WriteLine(((System.Xml.XmlElement)CompStream.SelectSingleNode("descendant::mtS:Events", theNameManager)).InnerText;);
    Console.In.Read();
}

because there is only one element in there and its innerText is all you will get.

Pow-Ian
  • 3,607
  • 1
  • 22
  • 31
  • This worked. But it seems to be clunky. As you can see this XML changes continuously and I was looking at it on a timer, every 30 sec. was I going down the wrong road? would Linq be better for what I am trying to do? – user2139891 Mar 11 '13 at 17:43
  • Probably but I have no idea how to use LINQ2XML. If the code that @the_joric posted works, I would suggest using it. Way fewer lines. Also it may seem clunky but the longest part of that process is going to be getting the file. The rest is just very fancy text manipulation. Try in your use case and see what you get. you may be surprised by the performance. Also the nice thing about this solution is if you end up needing to use any of the other nodes you can easily capture them. – Pow-Ian Mar 11 '13 at 17:49