So this is how a portion of the XML I am trying to parse looks like:
<azsa:Views>
<azsa:Spatial_Array>
<azsa:Spatial>
<azsa:ViewName>Spatial</azsa:ViewName>
<azsa:BBox>
<azsa:PointLo>
<azsa:x>0</azsa:x>
<azsa:y>0</azsa:y>
<azsa:z>0</azsa:z>
</azsa:PointLo>
<azsa:PointHi>
<azsa:x>2925</azsa:x>
<azsa:y>3375</azsa:y>
<azsa:z>2775</azsa:z>
</azsa:PointHi>
</azsa:BBox>
</azsa:Spatial>
</azsa:Spatial_Array>
</azsa:Views>
I have to read the x,y and z coordinates for both PointHi and PointLo
I was using the XMLReader() class to perform the task.
XmlTextReader reader = new XmlTextReader(openFileDialog1.FileName);
while (reader.Read())
{
reader.ReadToFollowing("azsa:Views");
reader.ReadToFollowing("azsa:Spatial_Array");
reader.ReadToFollowing("azsa:Spatial");
reader.ReadToFollowing("azsa:ViewName");
reader.ReadToFollowing("azsa:BBox");
reader.ReadToFollowing("azsa:PointLo");
reader.ReadToFollowing("azsa:x");
low[0] = (int)(Double.Parse(reader.ReadElementString()));
reader.ReadToFollowing("azsa:y");
low[1] = (int)(Double.Parse(reader.ReadElementString()));
reader.ReadToFollowing("azsa:z");
low[2] = (int)(Double.Parse(reader.ReadElementString()));
reader.ReadToFollowing("azsa:PointHi");
reader.ReadToFollowing("azsa:x");
high[0] = (int)(Double.Parse(reader.ReadElementString()));
reader.ReadToFollowing("azsa:y");
high[1] = (int)(Double.Parse(reader.ReadElementString()));
reader.ReadToFollowing("azsa:z");
high[2] = (int)(Double.Parse(reader.ReadElementString()));
}
The reader works perfectly until it gets to the first x in the PointLo and then it just skips to the y in PointHi instead. I have tried using descendants, subtrees and readinnerxml but it still does the same thing.
NOTE: 1. There is more code in the while loop for reading the remaining part of the XML but was not necessary for this problem so I have not included it in the post. 2. Changing the way the XML is organized is not possible because that's how they are required to be stored for the task I am performing. 3. XMLReader is the preferable method as I am dealing with a large number of documents and there is no scope for having this use cache memory.
I had a fairly similar issue a while back when reading subtrees. The solution in that scenario was to dispose the subtree XmlReaders. Granted, the situation here is slightly different, but could you consider an approach such as below (note that I removed the element prefixes for simplicity of testing, as well as read in the XML string rather than a file)?
It is certainly ugly looking, but this was more a proof of concept and could be tidied up a bit. It is also lacking the appropriate error checking, but again this was more for demonstration purposes. It does at least parse out the different point values.
As a side note, I think perhaps a lot of the ugliness could be abstracted away by making classes to represent the different components (or objects) within the XML stream, and making those classes responsible for parsing out their own properties.
Just one way (of many I'm sure) to skin a cat...
private void ParseXml(string xml)
{
double[] low = null;
double[] hi = null;
using (StringReader stringReader = new StringReader(xml))
{
using (XmlReader xmlReader = XmlReader.Create(stringReader))
{
while (xmlReader.Read())
{
if (xmlReader.NodeType != XmlNodeType.Element) continue;
if (xmlReader.Name == "PointLo")
{
low = ParsePoint(xmlReader);
}
else if (xmlReader.Name == "PointHi")
{
hi = ParsePoint(xmlReader);
}
}
}
}
}
private double[] ParsePoint(XmlReader xmlReader)
{
double[] point = new double[3];
using (XmlReader pointReader = xmlReader.ReadSubtree())
{
while (pointReader.Read())
{
if (pointReader.NodeType != XmlNodeType.Element) continue;
if (pointReader.Name == "x")
{
point[0] = GetDimensionValue(pointReader);
}
else if (pointReader.Name == "y")
{
point[1] = GetDimensionValue(pointReader);
}
else if (pointReader.Name == "z")
{
point[2] = GetDimensionValue(pointReader);
}
}
}
return point;
}
private double GetDimensionValue(XmlReader reader)
{
using (XmlReader dimensionReader = reader.ReadSubtree())
{
dimensionReader.Read();
return reader.ReadElementContentAsDouble();
}
}