programmer008
programmer008

Reputation: 7

Parse XML file with namespace

I'm trying the parse the xml file at this link: http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.quakeml.

The problem I am having is that the foreach loop itself is not executing. I think its a problem with namespaces in the xml document.

Below is my code:

protected void btnStoreXMLData_Click(object sender, EventArgs e)
{
    SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["EarthquakeCS"].ConnectionString);
    SqlCommand cmd = new SqlCommand();
    try
    {
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(Server.MapPath("~/App_Data/all_hour.xml"));

        XmlNamespaceManager nmspc = new XmlNamespaceManager(xmlDoc.NameTable);
        nmspc.AddNamespace("", "http://quakeml.org/xmlns/bed/1.2");
        nmspc.AddNamespace("catalog", "http://anss.org/xmlns/catalog/0.1");
        nmspc.AddNamespace("q", "http://quakeml.org/xmlns/quakeml/1.2");

        XmlNodeList dataNodes = xmlDoc.SelectNodes("/quakeml/eventParameters/event", nmspc);

        //ScriptManager.RegisterStartupScript(this, this.GetType(), "Message", "alert('test0');", true);

        foreach (XmlNode node in dataNodes)
        {
            ScriptManager.RegisterStartupScript(this, this.GetType(), "Message", "alert('test1');", true);

            string location = (node.SelectSingleNode("description/text") != null) ? node.SelectSingleNode("description/text").InnerText.ToString() : string.Empty;
            string time = (node.SelectSingleNode("origin/time/value") != null) ? node.SelectSingleNode("origin/time/value").InnerText.ToString() : string.Empty;
            string longitude = (node.SelectSingleNode("origin/longitude/value") != null) ? node.SelectSingleNode("origin/longitude/value").InnerText.ToString() : string.Empty;
            string latitude = (node.SelectSingleNode("origin/latitude/value") != null) ? node.SelectSingleNode("origin/latitude/value").InnerText.ToString() : string.Empty;
            string depth = (node.SelectSingleNode("origin/depth/value") != null) ? node.SelectSingleNode("origin/depth/value").InnerText.ToString() : string.Empty;
            string magnitude = (node.SelectSingleNode("magnitude/mag/value") != null) ? node.SelectSingleNode("magnitude/mag/value").InnerText.ToString() : string.Empty;
            string magnitudeType = (node.SelectSingleNode("magnitude/type/") != null) ? node.SelectSingleNode("magnitude/type/").InnerText.ToString() : string.Empty;

            cmd.CommandText = "INSERT INTO tblEarthquake (Location,Time,Latitude,Longitude,Depth,Magnitude,MagnitudeType) "
                            + "VALUES (@Location,@Time,@Latitude,@Longitude,@Depth,@Magnitude,@MagnitudeType)";
            cmd.CommandType = CommandType.Text;

            cmd.Parameters.Clear();
            cmd.Parameters.AddWithValue("@Location", location);
            cmd.Parameters.AddWithValue("@Time", time);
            cmd.Parameters.AddWithValue("@Latitude", latitude);
            cmd.Parameters.AddWithValue("@Longitude", longitude);
            cmd.Parameters.AddWithValue("@Depth", depth);
            cmd.Parameters.AddWithValue("@Magnitude", magnitude);
            cmd.Parameters.AddWithValue("@MagnitudeType", magnitudeType);

            cmd.Connection = con;

            if (con.State == ConnectionState.Closed)
            {
                con.Open();
            }

            int result = cmd.ExecuteNonQuery();

            if (result > 0)
            {
                //XML data has been inserted
            }
            else
            {
                //XML data has not been inserted
            }
        }

    }
    catch (Exception ex)
    {
        ScriptManager.RegisterStartupScript(this, this.GetType(), "Message", "alert('Error occured : " + ex.Message.ToString() + "');", true);
        return;
    }
    finally
    {
        con.Close();
        cmd.Dispose();
    }
}`

Upvotes: 1

Views: 1354

Answers (5)

nikis
nikis

Reputation: 11244

Change this:

nmspc.AddNamespace("", "http://quakeml.org/xmlns/bed/1.2");

To this:

nmspc.AddNamespace("def", "http://quakeml.org/xmlns/bed/1.2");

And your query should be changed to the following:

/q:quakeml/def:eventParameters/def:event

Why do you need this change? For the answer on this question take a look on a nice explanation here. But as others said, you'll be better to work with XDocument, it is newer and easier.

EDIT Modified queries in a loop:

string location = (node.SelectSingleNode("./def:description/def:text", nmspc) != null) ? node.SelectSingleNode("./def:description/def:text", nmspc).InnerText.ToString() : string.Empty;
string time = (node.SelectSingleNode("./def:origin/def:time/def:value", nmspc) != null) ? node.SelectSingleNode("./def:origin/def:time/def:value", nmspc).InnerText.ToString() : string.Empty;
string longitude = (node.SelectSingleNode("./def:origin/def:longitude/def:value", nmspc) != null) ? node.SelectSingleNode("./def:origin/def:longitude/def:value", nmspc).InnerText.ToString() : string.Empty;
string latitude = (node.SelectSingleNode("./def:origin/def:latitude/def:value", nmspc) != null) ? node.SelectSingleNode("./def:origin/def:latitude/def:value", nmspc).InnerText.ToString() : string.Empty;
string depth = (node.SelectSingleNode("./def:origin/depth/def:value", nmspc) != null) ? node.SelectSingleNode("./def:origin/def:depth/def:value", nmspc).InnerText.ToString() : string.Empty;
string magnitude = (node.SelectSingleNode("./def:magnitude/def:mag/def:value", nmspc) != null) ? node.SelectSingleNode("./def:magnitude/def:mag/def:value", nmspc).InnerText.ToString() : string.Empty;
string magnitudeType = (node.SelectSingleNode("./def:magnitude/def:type", nmspc) != null) ? node.SelectSingleNode("./def:magnitude/def:type", nmspc).InnerText.ToString() : string.Empty;

Upvotes: 2

MRebai
MRebai

Reputation: 5474

I suggest you work with linq to xml it's much easier :

XElement xmlDoc = XElement.Load(Server.MapPath("~/App_Data/all_hour.xml"));
var dataNodes = xmlDoc.Descendants().Where(s => s.Name.LocalName == "event"); 

Upvotes: 1

Johnbot
Johnbot

Reputation: 2179

This is much easier if you can use LinqToXml and XDocument.

var document = XDocument.Load("http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.quakeml");
XNamespace rNs = "http://quakeml.org/xmlns/bed/1.2";

var events = document.Root.Descendants(rNs + "eventParameters").Elements(rNs + "event");
foreach (var ev in events)
{
    var location = ev.Descendants(rNs + "description").Descendants(rNs + "text").Single().Value;

    var originElement = ev.Descendants(rNs + "origin");
    var time = originElement.Descendants(rNs + "time").Descendants(rNs + "value").Single().Value;
    var longitude = originElement.Descendants(rNs + "longitude").Descendants(rNs + "value").Single().Value;
    var latitude = originElement.Descendants(rNs + "latitude").Descendants(rNs + "value").Single().Value;
    var depth = originElement.Descendants(rNs + "depth").Descendants(rNs + "value").Single().Value;

    var magnitudeElement = ev.Descendants(rNs + "magnitude");
    var magnitude = magnitudeElement.Descendants(rNs + "mag").Descendants(rNs + "value").Single().Value;
    var magnitudeType = magnitudeElement.Descendants(rNs + "type").Single().Value;

}

Upvotes: 0

Louis
Louis

Reputation: 59

I prefered to work with XElement/XDoc rather than XMLElement & Co because this it easier.

Basically, your query returns 0 elements, because you don't use the name space.

So foreach has no collection to parse.

You can do something like

using System.Xml.Linq; //to use XElement XDoc etc

XDocument xDoc = new XDocument ();
XDocument doc = XDocument.Parse ( xmlIn );  -> xmlIn contains your XML code to parse as string

// i.e. get all nodes with event (w/o respect of ns) var result = doc.Descendants ().Where ( s => s.Name.LocalName == "event"); foreach ( var item in result ) { Debug.WriteLine ( item.Value ); }

or with namespace

var result = doc.Descendants ().Where ( s => s.Name.LocalName == "event" 
&& 
s.Name.NameSpaceName == "myNamespace");

HTH

Upvotes: 1

Henk Holterman
Henk Holterman

Reputation: 273701

You have filled the NamespaceManager but you're not using any.
A quick glance suggests you should at least indicate that the root is in q:. Roughly, not tested:

// ... xmlDoc.SelectNodes("/quakeml/eventParameters/event", nmspc);
   ... xmlDoc.SelectNodes("/q:quakeml/eventParameters/event", nmspc);

PS: Working with namespaces and XML in general is a lot easier with the XElement class. It's worth investigating.

Upvotes: 2

Related Questions