Исправление проблем XmlReader с использованием ReadToDescendant и / или ReadElementContentAsObject - PullRequest
1 голос
/ 12 февраля 2010

Я работаю над таинственной ошибкой в ​​обычно очень хорошем проекте с открытым исходным кодом Excel Data Reader . Он пропускает чтение значений из моей конкретной таблицы OpenXML .xlsx.

Проблема возникает в методе ReadSheetRow (демонстрационный код ниже). Исходный XML сохраняется в Excel и не содержит пробелов, которые возникают при странном поведении. Однако XML, который был переформатирован с пробелами (например, в Visual Studio перейдите в Edit, Advanced, Format Document), работает отлично!

Данные испытаний с пробелами:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
    <sheetData>
        <row r="5" spans="1:73" s="7" customFormat="1">
            <c r="B5" s="12">
                <v>39844</v>
            </c>
            <c r="C5" s="8"/>
            <c r="D5" s="8"/>
            <c r="E5" s="8"/>
            <c r="F5" s="8"/>
            <c r="G5" s="8"/>
            <c r="H5" s="12">
                <v>39872</v>
            </c>
            <c r="I5" s="8"/>
            <c r="J5" s="8"/>
            <c r="K5" s="8"/>
            <c r="L5" s="8"/>
            <c r="M5" s="8"/>
            <c r="N5" s="12">
                <v>39903</v>
            </c>
        </row>
    </sheetData>
</worksheet>

Данные испытаний без пробелов:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheetData><row r="5" spans="1:73" s="7" customFormat="1"><c r="B5" s="12"><v>39844</v></c><c r="C5" s="8"/><c r="D5" s="8"/><c r="E5" s="8"/><c r="F5" s="8"/><c r="G5" s="8"/><c r="H5" s="12"><v>39872</v></c><c r="I5" s="8"/><c r="J5" s="8"/><c r="K5" s="8"/><c r="L5" s="8"/><c r="M5" s="8"/><c r="N5" s="12"><v>39903</v></c></row></sheetData></worksheet>

Пример кода, демонстрирующего проблему:

Обратите внимание, что A выводится после _xmlReader.Read(), B после ReadToDescendant и C после ReadElementContentAsObject.

while (reader.Read())
{
    if (reader.NodeType != XmlNodeType.Whitespace) outStream.WriteLine(String.Format("*A* NodeType: {0}, Name: '{1}', Empty: {2}, Value: '{3}'", reader.NodeType, reader.Name, reader.IsEmptyElement, reader.Value));

    if (reader.NodeType == XmlNodeType.Element && reader.Name == "c")
    {
        string a_s = reader.GetAttribute("s");
        string a_t = reader.GetAttribute("t");
        string a_r = reader.GetAttribute("r");

        bool matchingDescendantFound = reader.ReadToDescendant("v");
        if (reader.NodeType != XmlNodeType.Whitespace) outStream.WriteLine(String.Format("*B* NodeType: {0}, Name: '{1}', Empty: {2}, Value: '{3}'", reader.NodeType, reader.Name, reader.IsEmptyElement, reader.Value));
        object o = reader.ReadElementContentAsObject();
        if (reader.NodeType != XmlNodeType.Whitespace) outStream.WriteLine(String.Format("*C* NodeType: {0}, Name: '{1}', Empty: {2}, Value: '{3}'", reader.NodeType, reader.Name, reader.IsEmptyElement, reader.Value));
    }
}

Результаты теста для XML с пробелами:

*A* NodeType: XmlDeclaration, Name: 'xml', Empty: False, Value: 'version="1.0" encoding="UTF-8" standalone="yes"'
*A* NodeType: Element, Name: 'worksheet', Empty: False, Value: ''
*A* NodeType: Element, Name: 'sheetData', Empty: False, Value: ''
*A* NodeType: Element, Name: 'row', Empty: False, Value: ''
*A* NodeType: Element, Name: 'c', Empty: False, Value: ''
*B* NodeType: Element, Name: 'v', Empty: False, Value: ''
*A* NodeType: EndElement, Name: 'c', Empty: False, Value: ''
*A* NodeType: Element, Name: 'c', Empty: True, Value: ''
*B* NodeType: Element, Name: 'c', Empty: True, Value: ''
...

Результаты теста для XML без пробелов:

*A* NodeType: XmlDeclaration, Name: 'xml', Empty: False, Value: 'version="1.0" encoding="UTF-8" standalone="yes"'
*A* NodeType: Element, Name: 'worksheet', Empty: False, Value: ''
*A* NodeType: Element, Name: 'sheetData', Empty: False, Value: ''
*A* NodeType: Element, Name: 'row', Empty: False, Value: ''
*A* NodeType: Element, Name: 'c', Empty: False, Value: ''
*B* NodeType: Element, Name: 'v', Empty: False, Value: ''
*C* NodeType: EndElement, Name: 'c', Empty: False, Value: ''
*A* NodeType: Element, Name: 'c', Empty: True, Value: ''
*B* NodeType: Element, Name: 'c', Empty: True, Value: ''
...

Изменения в шаблоне указывают на проблему в ReadElementContentAsObject или, возможно, на местоположение, в которое ReadToDescendant перемещает XmlReader в.

Кто-нибудь знает, что здесь может происходить?

1 Ответ

1 голос
/ 12 февраля 2010

Это довольно просто. Как видно из выходных данных, в первый раз, когда вы находитесь в строке " B ", вы позиционируетесь в первом элементе v. Затем вы вызываете ReadElementContentAsObject. Это возвращает текстовое содержимое v, и «перемещает читателя за тег конечного элемента». (из V). Теперь вы указываете на узел пробела, если есть пробел, или узел EndElement (из c), если его нет. Конечно, ваш вывод не печатается, если это пробел. В любом случае, вы затем выполняете Read () и переходите к следующему элементу. В случае непробельного пространства вы потеряли EndElement.

Проблема намного хуже в других ситуациях. Когда вы делаете ReadElementContentAsObject объекта c (назовите его c1), вы затем переходите к следующему объекту c (c2). Затем вы читаете, переходите на c3 и теряете c2 навсегда.

Я не собираюсь пытаться исправить реальный код . Но понятно, о чем нужно беспокоиться, продвигая поток вперед более чем в одном месте. Это общий источник ошибок зацикливания в целом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...