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 результата для точной фразы сообщения об исключении, каждый на языке, на котором я не говорю. Гугл переводя их, ничего не выявил.
Экспериментально я пробовал 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
(все они добавляются в список, который преобразуется в массив и повторяется во время фазы замещения).
Что не так (что на самом деле означает исключение) и как мне это исправить?
Append: класс, который на самом деле выдает исключение (System.Xml.DocumentXmlWriter
), похоже, не документировано в MSDN (или, по крайней мере, я не смог найти его ни с помощью поиска Google, ни с помощью поиска MSDN).
Добавить: я определил, что данные для одной замены, вызывающей проблему, это просто один пробел (т.е. " "
). Я не понимаю, почему это может быть проблемой для XPathNavigator
, но, видимо, это... Кажется, пустая строка (т.е. ""
) слишком. Возможно, проблема заключается в попытке заменить элемент только пробелами. Я не понимаю, почему это должно быть проблемой, хотя.
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 без записи какого-либо узла.
Это не ответ на ваш вопрос (который в любом случае довольно стар), но для людей, которые пришли сюда в поисках причины No content generated as the result of the operation.
что происходит при установке значения InnerXml на листовом узле, вы можете увидеть успех, используя SetValue
вместо.
Почему это важно для конечного узла, я не могу вам точно сказать. Я предполагаю, что это ошибка при попытке разобрать узлы в простой строке.
См. Дополнительную информацию о разнице между Value и InnerXml в этом вопросе stackru или в этом вопросе 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.