你怎么能在网页上编辑有效的XML?

我必须启动并运行快速而肮脏的配置编辑器。 流程如下:

配置(服务器上的POCO)序列化为XML。
此时XML已经很好地形成了。 配置将发送到XElements中的Web服务器。
在Web服务器上,XML(是,全部IT)被转储到textarea中进行编辑。
用户直接在网页中编辑XML并单击“提交”。
在响应中,我检索XML配置的更改文本。 此时,所有转义都已通过在网页中显示它们的过程恢复。
我尝试将字符串加载到XML对象(XmlElement,XElement,等等)。 KABOOM。

问题是序列化会转义属性字符串,但在转换过程中会丢失。

例如,假设我有一个具有正则表达式的对象。 以下是Web服务器的配置:

   

所以,我把它放到textarea中,它对用户来说是这样的:

  <Validator Expression="[^  

因此,用户稍作修改并将更改提交回来。 在Web服务器上,响应字符串如下所示:

  <Validator Expression="[^   

因此,用户添加了另一个validation器,现在BOTH具有非法字符的属性。 如果我尝试将其加载到任何XML对象中,它会抛出exception,因为<和&在文本字符串中无效。 我不能不能使用任何类型的编码功能,因为它编码整个血腥的东西:

var result = Server.HttpEncode(editedConfig);

结果是

 <Configuration> <Validator Expression="[^<]" /> <Validator Expression="[^&]" /> </Configuration> 

这不是有效的XML。 如果我尝试将其加载到任何类型的XML元素中,我将会被一个下降的铁砧击中。 我不喜欢掉落的铁砧。

那么,问题仍然存在……我是否可以通过使用正则表达式替换来获得解析为XML对象的XML字符串的唯一方法? 我加载时有没有办法“关闭约束”? 你怎么绕过这个?


最后一个回应,然后维护这个,因为我认为没有一个有效的答案。

我在textarea中放置的XML是有效的,转义的XML。 1)将其放入文本区域的过程2)将其发送给客户端3)将其显示给客户端4)提交表单,然后将其发送回服务器,以及6)从表格REMOVES中检索值任何和所有逃脱。

让我再说一遍:我不会逃避任何事情。 只需在浏览器中显示它就可以了!

需要考虑的事项:有没有办法防止这种无法逃避的事情发生在一开始? 有没有办法采用几乎有效的XML并以安全的方式“清理”它?


这个问题现在有了它的赏金。 要收集赏金,您将演示如何在浏览器窗口中编辑VALID XML而不使用第三方/开源工具,该工具不需要我使用正则表达式手动转义属性值,这不需要用户转义其属性,并且在往返时不会失败(&amp; amp; amp; amp; etc;)

呃…… 怎么序列化? 通常,XML序列化程序永远不应生成无效的XML。

/ EDIT响应您的更新:不要向您的用户显示无效的XML进行编辑! 而是在TextBox中显示正确转义的XML。 修复损坏的XML并不好玩,我实际上没有理由不以有效的转义forms显示/编辑XML。

我再次问:你如何在TextBox中显示XML? 您似乎故意在某些时候忽略XML。

/编辑以回应您的最新评论:是的,显然,因为它可以包含HTML。 在将XML写入HTML页面之前,您需要正确地转义XML。 有了它,我的意思是整个 XML。 所以这:

  

成为这个:

 <foo mean-attribute="&<"> 

当然,当你将实体引用放在textarea中时,它们就会没有转义。 Textareas不是魔法,你必须逃避; 你所放入的所有东西就像其他元素一样。 浏览器可能会在textarea中显示原始的“<”,但这只是因为他们试图清除您的错误。

因此,如果您将可编辑的XML放在textarea中,则需要转义属性值一次以使其成为有效的XML,然后您必须再次转义整个XML以使其成为有效的HTML。 您希望在页面中显示的最终来源是:

  

问题是基于对textarea元素的内容模型的误解 – validation者会立即解决问题。

ETA评论:嗯,还有什么问题? 这是序列化方面的问题。 剩下的就是解析它,为此你必须假设用户可以创建格式良好的XML。

尝试解析非格式良好的XML,以便允许在属性值中使用“<”或“&”非错误等错​​误,这完全违背了XML应该如何工作。 如果您不能信任您的用户编写格式良好的XML,请为它们提供一个更简单的非XML接口,例如一个简单的以新行分隔的正则表达式字符串列表。

正如你所说,普通的序列化器应该为你逃避一切。

那么问题就是文本块:您需要自己处理通过文本块传递的任何内容。

您可以尝试使用HttpUtility.HtmlEncode(),但我认为最简单的方法是将您通过CDATA部分中的文本块的任何内容包住。

通常我当然希望所有东西都能正常逃脱,而不是依靠CDATA“拐杖”,但我也想使用内置工具进行转义。 对于用户在其“hibernate”状态下编辑的内容,我认为CDATA可能是最佳选择。

另见前面的问题:
编码XML文本数据的最佳方法


更新
基于对另一个响应的评论,我意识到你向用户显示标记,而不仅仅是内容。 Xml解析器很挑剔。 我认为在这种情况下你能做的最好的事情就是接受编辑的xml 之前检查格式是否良好。

也许尝试自动纠正某些类型的错误(例如我链接问题中的错误&符号),然后从.Net xml解析器获取第一个validation错误的行号和列号,并使用它来向用户显示他们的错误,直到他们给你一些可接受的东西 如果您还针对架构进行validation,则会获得奖励积分。

您可以查看类似TinyMCE的内容 ,它允许您在富文本框中编辑html。 如果您无法将其配置为完全符合您的要求,则可以将其用作灵感。

注意:firefox(在我的测试中)不会像你描述的那样在文本区域中消失。 具体来说,这段代码:

   

被警告并向用户显示不变 ,如:

    

那么也许一个(不可行的?)解决方案是让你的用户使用firefox。


看来你的问题的两个部分已经揭晓:

1 您显示的XML未转义。

例如,“ < ”未转义为“<”。 但由于“<”也未转义为“<”,因此信息丢失,您无法将其取回。

一种解决方案是让您转义所有“ & ”字符,以便“ < ”变为“ &lt; ”。 这将被textarea取消为“ < ”。 当你读回来的时候,它就像它在第一时间一样。 (我假设textarea实际上改变了字符串,但是firefox没有按照你的报告行事,所以我无法检查这个)

另一个解决方案(我已经提到过)是建立/购买/借用一个自定义文本区域(如果简单,那就不错了,但是有所有编辑键,ctrl-C,ctrl-shift-left等等)。

2 您希望用户不必费心逃避。

你在逃避地狱:

正则表达式替换将主要起作用……但是当用户可能(合法地,在您给出的术语中)输入时,如何可靠地检测结束引用(“):

    

从正则表达式语法的角度来看,它也无法判断最终的“是正则表达式的一部分,还是它的结尾。正则表达式语法通常用一个显式终结符来解决这个问题,例如:

 /[^"<]/ 

如果用户使用了这种语法(带有终结符),并且你为它编写了一个解析器,那么你可以确定正则表达式何时结束,因此下一个“字符不是正则表达式的一部分,而是XML的一部分,以及因此,哪些部分需要逃脱。我不是说你应该这样做!我说它在理论上是可行的。它远非快速而肮脏。

顺便说一句:元素中的文本也出现同样的问题。 以下内容在您给出的条款中是合法的,但具有相同的解析问题:

    

允许“任何文本”的语法中的基本规则是必须对分隔符进行转义(例如“或”),以便可以识别结尾。为了方便/不方便,大多数语法也逃避了许多其他内容。 ( 编辑它需要为转义字符本身进行转义:对于XML,它是“ & ”,当文字转义为“ & ”时对于正则表达式,它是C / unix样式的“ \ ”,其中当文字被转义为“ \\ ”时)。

嵌套语法,你在逃避地狱。

一个简单的解决方案是告诉你的用户:这是一个快速肮脏的配置编辑器,所以你没有得到任何幻想“不需要逃避”mamby-pamby:

  • 列出文本区域旁边的字符和转义符,例如:“<”为“ &lt ”。
  • 对于无法validation的XML,请再次向其显示列表。

回想起来,我看到鲍比斯在我面前给出了同样的基本答案。

在所有文本周围插入CDATA将为您提供另一种转义机制,它将(1)保存用户免于手动转义,以及(2)启用textarea自动转义的文本以便正确读回。

     

🙂

这个特殊字符 – “<” - 应该替换为其他字符,以便您的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; } 

(编辑:删除&符号替换,因为它会导致问题往返)