System.Xml.XmlDocument, System.Xml.XPath.XPathNavigator{ReplaceSelf,OuterXml}: замена заполнителей в документе

В настоящее время я поддерживаю веб-приложение, которое я написал около года назад для работы. По сути, это позволяет пользователям создавать собственные шаблоны отчетов XHTML. Я использую XmlDocument, XPathNavigator и т.д. др. для проверки, очистки и замены заполнителей данными.

По большей части это работает нормально, но я только что понял, что на самом деле я не заменял элементы-заполнители данными, а заменял текст заполнителя текстом данных.

Надуманный пример:

<span class="my-placeholder">{CompanyName}</span>

Станет...

<span class="my-placeholder">Castopulence</span>

Раньше это не было проблемой, потому что шаблоны обрабатывались только один раз; когда пользователь решил запустить его для набора выбранных данных. Однако теперь мы предлагаем им возможность предварительно просмотреть полученный результат и изменить его перед печатью. Результатом этого является то, что он обрабатывается механизмом подстановки более одного раза: сначала для создания исходного вывода, а затем снова, когда измененный вывод «распечатывается». Механизм подстановки находит заполнитель, который на самом деле является данными, не может найти соответствующий элемент данных для замены, и процесс завершается с ошибкой.

Исходный код использовал свойство XPathNavigator.InnerXml для изменения содержимого элемента-заполнителя с "{CompanyName}" на "Castopulence" (например):

placeholder.InnerXml = this.Server.HtmlEncode(value);

Поэтому кажется разумным, что если бы я хотел полностью заменить этот элемент-заполнитель, я бы вместо этого использовал XPathNavigator.OuterXml:

placeholder.OuterXml = this.Server.HtmlEncode(value);

Кажется, это работает в большинстве случаев, или, по крайней мере, я предполагаю, что это так, но кажущаяся случайной замена всегда приводит к тому, что System.InvalidOperationException выдается с сообщением «Нет контента, сгенерированного в результате операции». Поэтому я не совсем уверен, что какой-либо из них работает, но я предполагаю, что они работают, поскольку для предыдущих замен не выдается никаких исключений.

Я не могу понять, что это значит, и у Google есть только 4 результата для точной фразы сообщения об исключении, каждый на языке, на котором я не говорю. Google, переводивший их, не дал ничего подходящего.

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

Трассировка стека в обоих случаях:

в System.Xml.DocumentXmlWriter.Close(WriteState currentState)
в System.Xml.XmlWellFormedWriter.Close()
в System.Xml.XPath.XPathNavigator.ReplaceSelf(XmlReader newNode)
в System.Xml. XPath.XPathNavigator.ReplaceSelf(String newNode)
...Обрезаны частные символы приложения...

В справочнике MSDN для ReplaceSelf описаны исключения, которые он генерирует, но единственное System.InvalidOperationException возникает исключение, когда «XpathNavigator не расположен на элементе, тексте, инструкции обработки или узле комментария». Из отладчика Visual Studio я могу подтвердить, что он расположен на элементе. Мой код согласен. XPathNavigator, указывающие на заполнители, на самом деле являются клонами System.Xml.XPath.XPathNodeIterator.Current (все они добавляются в список, который преобразуется в массив и повторяется на этапе замены).

Что не так (что на самом деле означает исключение) и как мне это исправить?

Добавить: класс, который на самом деле выдает исключение (System.Xml.DocumentXmlWriter), похоже, не задокументирован в MSDN (или, по крайней мере, я не смог найти его ни с помощью поиска Google, ни с помощью поиска MSDN).

Добавить: я определил, что данные для одной замены, вызвавшей проблему, представляют собой одиночный пробел (т. е. " "). Я не понимаю, почему это может быть проблемой для XPathNavigator, но, видимо, это так... Кажется, пустая строка (т.е. "") тоже. Возможно, проблема заключается в попытке заменить элемент только пробелами. Хотя я не понимаю, почему это должно быть проблемой.


person bambams    schedule 04.05.2011    source источник


Ответы (2)


Я также получаю то же сообщение об ошибке:

Контент не генерируется в результате операции

XmlWriter writer = replaceTextIterator.Current.ReplaceRange(replaceTextIterator.Current);

XPathNodeIterator iterator5 = replaceTextIterator.Current.SelectChildren(XPathNodeType.All);
while (iterator5.MoveNext())
{
  writer.WriteNode(iterator5.Current, true);
}

writer.Close();

Если iterator.count = 0, я получаю это сообщение об ошибке, поэтому не закрывайте объект xmlwriter без записи какого-либо узла.

person kalai    schedule 12.08.2011

Это не ответ на ваш вопрос (который в любом случае довольно старый), но для людей, которые пришли сюда в поисках причины No content generated as the result of the operation., возникающей при установке значения InnerXml на конечном узле, вы можете увидеть успех, используя вместо этого SetValue.

Почему это важно для листового узла, я не могу вам точно сказать. Я бы предположил, что это ошибка из-за попытки разобрать узлы из простой строки.

Дополнительную информацию о разнице между Value и InnerXml см. в этом вопросе о stackoverflow или в этом вопросе InfoPathDev (на мой взгляд, этот более полезен).

Итак, если у меня есть XPathNavigator, расположенный в этом узле:

<my:group2 my:field4="Hi">
    <my:field1>Hello</my:field1>
    <my:field2 my:field5="yay">Goodbye</my:field2>
    <my:field3></my:field3>
</my:group2>

InnerXml would be:

        <my:field1>Hello</my:field1>
        <my:field2 my:field5="yay">Goodbye</my:field2>
        <my:field3></my:field3>

And Value would be:

        Hello
        Goodbye

For leaf nodes, InnerXml and Value should typically be the same, but I'd suggest using Value for getting a node's value as that's what it's intended for.
person Chris    schedule 22.08.2014