Я пытаюсь проанализировать XML-файл с помощью C# в среде.NET, и он продолжает пропускать элементы
Вот как выглядит фрагмент XML, который я пытаюсь разобрать:
<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>
Я должен прочитать координаты X, Y и Z для PointHi и PointLo
Я использовал класс XMLReader() для выполнения задачи.
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()));
}
Считыватель работает отлично, пока не достигнет первого x в PointLo, а затем просто перейдет к y в PointHi. Я пытался использовать потомков, поддеревьев и readinnerxml, но он все еще делает то же самое.
ПРИМЕЧАНИЕ: 1. В цикле while имеется больше кода для чтения оставшейся части XML, но он не был необходим для этой проблемы, поэтому я не включил его в статью. 2. Изменить способ организации XML невозможно, потому что именно так они должны храниться для задачи, которую я выполняю. 3. XMLReader является предпочтительным методом, так как я имею дело с большим количеством документов, и нет возможности использовать эту кэш-память.
2 ответа
У меня была довольно похожая проблема, когда я читал поддеревья. Решением в этом сценарии было удаление поддерева XmlReaders. Конечно, ситуация здесь немного другая, но не могли бы вы рассмотреть такой подход, как приведенный ниже (обратите внимание, что я убрал префиксы элементов для простоты тестирования, а также прочитал в XML-строке, а не в файле)?
Это, конечно, некрасиво выглядит, но это было скорее доказательством концепции и могло бы немного привести в порядок. Также не хватает соответствующей проверки ошибок, но опять же это было больше для демонстрационных целей. Это, по крайней мере, анализирует различные значения точек.
В качестве примечания, я думаю, что, возможно, большая часть уродства может быть удалена путем создания классов, представляющих различные компоненты (или объекты) в потоке XML, и возложения на эти классы ответственности за разбор их собственных свойств.
Только один способ (из многих я уверен), чтобы снять кожу с кошки...
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();
}
}
Итак, как я упоминал в комментариях к решению Мандерсона, что по какой-то причине он не видит элемент y как элемент, а вместо этого видит его как текстовый элемент, я внес следующие изменения в цикл while в ParsePoint()
while (pointReader.Read())
{
if (pointReader.NodeType == XmlNodeType.Element || pointReader.NodeType== XmlNodeType.Text)
{
if (pointReader.Name == "azsa:x")
{
point[0] = pointReader.ReadElementContentAsDouble();
}
else if (pointReader.Name == "")
{
point[1] = Double.Parse(pointReader.Value);
}
else if (pointReader.Name == "azsa:z")
{
point[2] = pointReader.ReadElementContentAsDouble();
}
}
}
Хотя я не утверждаю, что это идеальный способ сделать это, он работает для файлов XML, с которыми я имею дело. Я также удалил метод GetDimensionValue и просто делаю чтение значений / элементов в самом методе.