究竟如何才能在网页中编辑有效的 XML?
-
04-07-2019 - |
题
我必须启动并运行一个快速而肮脏的配置编辑器。流程是这样的:
配置(服务器上的 POCO)被序列化为 XML。
此时 XML 的格式已正确。配置将发送到 XElements 中的 Web 服务器。
在 Web 服务器上,XML(是的,全部)被转储到文本区域中进行编辑。
用户直接在网页中编辑XML,然后单击“提交”。
在响应中,我检索 XML 配置的更改文本。此时,所有转义都已通过在网页中显示它们的过程来恢复。
我尝试将字符串加载到 XML 对象(XmlElement、XElement 等)中。轰隆隆。
问题在于序列化会转义属性字符串,但在翻译过程中会丢失这些属性字符串。
例如,假设我有一个包含正则表达式的对象。以下是 Web 服务器的配置:
<Configuration>
<Validator Expression="[^<]" />
</Configuration>
因此,我将其放入文本区域,对于用户来说它看起来像这样:
<Configuration>
<Validator Expression="[^<]" />
</Configuration>
因此用户进行了轻微的修改并将更改提交回来。在 Web 服务器上,响应字符串如下所示:
<Configuration>
<Validator Expression="[^<]" />
<Validator Expression="[^&]" />
</Configuration>
因此,用户添加了另一个验证器,现在两者都具有包含非法字符的属性。如果我尝试将其加载到任何 XML 对象中,它会引发异常,因为 < 和 & 在文本字符串中无效。我不能不能不能不能使用任何类型的编码函数,因为它编码了整个该死的东西:
var 结果 = Server.HttpEncode(editedConfig);
结果是
<Configuration>
<Validator Expression="[^<]" />
<Validator Expression="[^&]" />
</Configuration>
这不是有效的 XML。如果我尝试将其加载到任何类型的 XML 元素中,我都会被掉落的铁砧击中。我不喜欢掉落的铁砧。
所以,问题仍然是......我可以将此字符串 XML 准备好解析为 XML 对象的唯一方法是使用正则表达式替换吗?加载时有什么方法可以“关闭约束”吗?你如何解决这个问题???
最后一个回复,然后将其维基化,因为我认为没有有效的答案。
我放置在文本区域中的 XML 是有效的转义 XML。1) 将其放入文本区域 2) 将其发送到客户端 3) 将其显示给客户端 4) 提交其所在的表单 5) 将其发送回服务器 6) 从表单中检索值 REMOVES任何和所有的逃脱。
让我再说一遍:我不会逃避任何事情。只需在浏览器中显示它即可!
需要考虑的事情:有没有办法从一开始就防止这种无法逃脱的情况发生?有没有一种方法可以安全地获取几乎有效的 XML 并“清理”它?
这个问题现在有悬赏。为了收集赏金,您演示了如何在浏览器窗口中编辑有效的 XML,而无需使用第 3 方/开源工具,该工具不需要我使用正则表达式手动转义属性值,也不需要用户转义其属性,并且在往返(&amp;等)时不会失败
解决方案
Erm <!>#8230; <!> nbsp; 如何序列化?通常,XML序列化程序不应该生成无效的XML。
/ EDIT响应您的更新:不向您的用户显示无效的XML进行编辑!而是在TextBox中显示正确转义的XML。修复损坏的XML并不好玩,我实际上没有理由不以有效的转义形式显示/编辑XML。
我再次问:如何在TextBox中显示XML?您似乎在某些时候故意忘记XML。
/编辑回复您的最新评论:是的,显然,因为它可以包含HTML。在将XML写入HTML页面之前,您需要正确地转义XML。有了它,我的意思是整个 XML。所以这个:
<foo mean-attribute="<">
成为这个:
<foo mean-attribute="&<">
其他提示
当然,当你将实体引用放在textarea中时,它们就会没有转义。 Textareas不是魔法,你必须<逃逸;你放入其中的所有东西就像其他元素一样。浏览器可能显示原始的'<!> lt;'在textarea,但只是因为他们试图清理你的错误。
因此,如果您将可编辑的XML放在textarea中,则需要转义属性值一次以使其成为有效的XML,然后您必须再次转义整个XML以使其成为有效的HTML。您希望在页面中显示的最终来源是:
<textarea name="somexml">
<Configuration>
<Validator Expression="[^&lt;]" />
<Validator Expression="[^&amp;]" />
</Configuration>
</textarea>
问题是基于对textarea元素的内容模型的误解 - 验证者会立即解决问题。
ETA评论:好吧,还有什么问题?这是序列化方面的问题。剩下的就是将其解析回来,为此你必须假设用户可以创建格式良好的XML。
尝试解析格式不正确的XML,以便允许出现'<!> lt;'等错误或'<!> amp;'未归属于属性值是一种损失,完全违背了XML应该如何工作。如果您不能信任您的用户编写格式良好的XML,请为它们提供一个更简单的非XML接口,例如一个简单的换行符分隔的regexp字符串列表。
正如你所说,普通的序列化程序应该为你逃避一切。
问题是文本块:您需要自己处理通过文本块传递的任何内容。
您可以尝试使用HttpUtility.HtmlEncode(),但我认为最简单的方法是将您通过CDATA部分中的文本块的任何内容包住。
通常我当然希望所有内容都能正确转义而不是依赖于CDATA <!>“拐杖<!>”,但我还想使用内置工具进行转义。对于在其中编辑的内容<!>“hibernated <!>”;由用户说明,我认为CDATA可能是最佳选择。
另见之前的问题:
为XML编码文本数据的最佳方法
<强>更新强>结果 基于对另一个响应的评论,我意识到你向用户显示标记,而不仅仅是内容。 Xml解析器很挑剔。我认为在这种情况下你能做的最好的事情就是在接受编辑的xml之前检查格式良好。
也许尝试自动纠正某些类型的错误(例如我链接问题中的错误&符号),然后从.Net xml解析器获取第一个验证错误的行号和列号,并使用它来向用户显示他们的位置错误是直到他们给你一些可接受的东西。如果您还针对架构进行验证,则会获得奖励。
您可以查看 TinyMCE 之类的内容,它允许您在富文本中编辑html框。如果您无法将其配置为完全符合您的要求,则可以将其用作灵感。
笔记:Firefox(在我的测试中)不会像您所描述的那样在文本区域中转义。具体来说,这段代码:
<textarea cols="80" rows="10" id="1"></textarea>
<script>
elem = document.getElementById("1");
elem.value = '\
<Configuration>\n\
<Validator Expression="[^<]" />\n\
</Configuration>\
'
alert(elem.value);
</script>
向用户发出警报并显示 不变, , 作为:
<Configuration>
<Validator Expression="[^<]" />
</Configuration>
因此,也许一种(不可行?)解决方案是让您的用户使用 Firefox。
您的问题似乎有两个部分已被揭示:
1 您显示的 XML 未转义。
例如, ”<
" 未转义为“<”。但由于“<”也未转义为“<”,因此信息会丢失并且无法恢复。
一种解决方案是让你摆脱所有“&
“ 字符,因此 ”<
“成为”&lt;
”。然后,文本区域将不会将其转义为“<
”。当你再读一遍时,它会像最初一样。(我假设文本区域实际上更改了字符串,但 Firefox 的行为并不像您报告的那样,所以我无法检查这一点)
另一个解决方案(我认为已经提到过)是构建/购买/借用一个自定义文本区域(如果简单也不错,但有所有编辑键,ctrl-C,ctrl-shift-left 等等)。
2 您希望用户不必费心转义。
你正处于逃离地狱之中:
正则表达式替换大部分都会起作用......但是当用户可能(合法地,在您给出的条款内)输入时,如何可靠地检测到结束引号(“):
<Configuration>
<Validator Expression="[^"<]" />
</Configuration>
从正则表达式语法的角度来看,它也无法判断最后的 " 是正则表达式的一部分,还是它的结尾。正则表达式语法通常使用显式终止符来解决这个问题,例如:
/[^"<]/
如果用户使用此语法(带有终止符),并且您为其编写了一个解析器,那么您可以确定正则表达式何时结束,因此下一个 " 字符不是正则表达式的一部分,而是 XML 的一部分,并且因此哪些部分需要转义。我不是说你应该这样做!我是说理论上是可行的。它远非快速和肮脏。
顺便提一句:元素内的文本也会出现同样的问题。在您给出的条款内,以下内容是合法的,但具有相同的解析问题:
<Configuration>
<Expression></Expression></Expression>
</Configuration>
允许“任何文本”的语法中的基本规则是分隔符 必须 被逃脱,(例如" 或 <),这样就可以识别结束。为了方便/不便,大多数语法也会转义一些其他东西。(编辑 它需要对转义字符本身进行转义:对于 XML,它是“&
",当字面意义被转义为 "&
“ 对于正则表达式,它是 C/unix 风格的”\
",当字面意义被转义为 "\\
").
嵌套语法,你就进入了逃脱地狱。
对您来说,一个简单的解决方案是告诉您的用户:这是一个 快的 和 肮脏的 配置编辑器,所以你不会得到任何花哨的“无需转义”mamby-pamby:
- 列出字符并逃脱文本区域,例如:“ <” as”
<
". - 对于无法验证的XML,请再次向他们显示列表。
回头看,我看到 博宾斯 在我面前给出了相同的基本答案。
在所有文本周围插入CDATA将为您提供另一种转义机制,该机制将(1)保存用户免于手动转义,以及(2)启用textarea自动转义的文本以便正确读回。
<Configuration>
<Validator Expression="<![CDATA[ [^<] ]]>" />
</Configuration>
: - )
此特殊字符 - <!>“; <!> lt; <!>”; - 应该替换为其他字符,以便您的XML有效。检查此链接是否包含XML特殊字符:
http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
在将TextBlock内容发送到反序列化程序之前,请尝试对其进行编码:
HttpServerUtility utility = new HttpServerUtility();
string encodedText = utility.HtmlEncode(text);
这真的是我唯一的选择吗?这不是一个常见的问题,它在框架中的某个地方有解决方案吗?
private string EscapeAttributes(string configuration)
{
var lt = @"(?<=\w+\s*=\s*""[^""]*)<(?=[^""]*"")";
configuration = Regex.Replace(configuration, lt, "<");
return configuration;
}
(编辑:删除&符号替换,因为它导致问题往返)