Reputation: 7
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
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
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
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
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
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