System.Xml.XmlDocument,System.Xml.XPath.XPathNavigator {ReplaceSelf,OuterXml}:替换文档中的占位符

时间:2011-05-04 20:47:01

标签: .net xmldocument xpathnavigator outerxml

我目前正在维护一个大约一年前我写的工作的Web应用程序。基本上它允许用户创建自定义XHTML报告模板。我使用XmlDocumentXPathNavigator等。人。用数据验证,消毒和替换占位符。

它在大多数情况下工作正常,但我刚刚意识到我实际上并没有用数据替换占位符元素,而是用数据文本替换占位符的文本。

受挫的例子:

<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抛出一条消息,“没有因操作而生成的内容“。所以我不确定它们中的任何一个是否正常工作,但我认为它们是因为以前的替换都没有例外。

我无法弄清楚这意味着什么,谷歌只有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)
   ...剪切私有应用程序符号......

ReplaceSelf System.InvalidOperationException描述了它抛出的异常,但抛出的唯一XPathNavigator异常是“当XPathNavigator没有定位在元素,文本,处理指令上时,或评论节点。“从Visual Studio调试器,我可以确认它位于元素上。我的代码同意了。指向占位符的System.Xml.XPath.XPathNodeIterator.Current实际上是System.Xml.DocumentXmlWriter的克隆(所有这些都被添加到列表中,转换为数组,并在替换阶段迭代)。

有什么问题(异常实际意味着什么)以及如何解决?

附加:实际上抛出异常(" ")的类似乎没有在MSDN上记录(或者至少,我在Google搜索中找不到它也不是MSDN搜索)。

附加:我已经确定导致问题的一个替换的数据只是一个单一空格(即XPathNavigator)。我不明白为什么这可能是""的问题,但显然它是......似乎是一个空字符串(即{{1}})也是如此。也许问题是尝试用空格替换元素。我不明白为什么这应该是一个问题。

2 个答案:

答案 0 :(得分:1)

我也收到了同样的错误消息:

  

操作无法生成任何内容

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对象。

答案 1 :(得分:0)

这不是你的问题的答案(无论如何都是这个问题),但对于那些来到这里寻找在叶子节点上设置InnerXml值时发生No content generated as the result of the operation.的原因的人来说,你可能会使用SetValue代替成功。

为什么它对叶节点很重要,我无法肯定地告诉你。我猜想尝试将节点解析成一个简单的字符串是错误的。

查看有关Value和InnerXml in this stackoverflow question之间差异的更多信息,或in this InfoPathDev question(在我看来,这个更有帮助)。

  

所以如果我在这个节点上放置了一个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.