4

我必须启动并运行一个快速而肮脏的配置编辑器。流程是这样的:

配置(服务器上的 POCO)被序列化为 XML。
在这一点上,XML 格式良好。配置被发送到 XElements 中的 Web 服务器。
在 Web 服务器上,XML(是的,全部)被转储到文本区域中进行编辑。
用户直接在网页中编辑 XML 并单击提交。
在响应中,我检索了 XML 配置的更改文本。此时,所有转义都已通过在网页中显示它们的过程恢复。
我尝试将字符串加载到 XML 对象(XmlElement、XElement 等)中。卡布姆。

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

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

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

所以,我把它放到了一个 textarea 中,对用户来说它看起来像这样:

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

因此,用户进行了轻微的修改并将更改提交回来。在 Web 服务器上,响应字符串如下所示:

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

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

var 结果 = Server.HttpEncode(editedConfig);

结果是

&lt;Configuration&gt;
  &lt;Validator Expression="[^&lt;]" /&gt;
  &lt;Validator Expression="[^&amp;]" /&gt;
&lt;/Configuration&gt;

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

所以,问题仍然存在......我可以让这个字符串 XML 准备好解析为 XML 对象的唯一方法是使用正则表达式替换吗?加载时有什么方法可以“关闭约束”吗?你怎么解决这个问题???


最后一个回复,然后对其进行维基化,因为我认为没有有效的答案。

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

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

需要考虑的事情:有没有办法从一开始就防止这种无法逃脱的事情发生?有没有办法获取几乎有效的 XML 并以安全的方式“清理”它?


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

4

8 回答 8

7

呃……<em>你是怎么序列化的?通常,XML 序列化程序绝不应该产生无效的 XML。

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

我可以再次问:如何在 TextBox 中显示 XML?您似乎在某些时候故意对 XML 进行转义。

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

<foo mean-attribute="&lt;">

变成这样:

&lt;foo mean-attribute="&amp;&lt;"&gt;
于 2008-10-28T18:22:35.263 回答
5

当然,当您将实体引用放在 textarea 中时,它们不会转义。文本区域不是魔法,你必须 &escape; 您放入其中的所有内容都与其他元素一样。浏览器可能会在 textarea 中显示原始的“<”,但这仅仅是因为它们试图清理您的错误。

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

<textarea name="somexml">
    &lt;Configuration&gt;
        &lt;Validator Expression="[^&amp;lt;]" /&gt;
        &lt;Validator Expression="[^&amp;amp;]" /&gt;
    &lt;/Configuration&gt;
</textarea>

问题是基于对 textarea 元素的内容模型的误解——验证器会立即发现问题。

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

试图解析格式不正确的 XML,以允许在属性值中未转义 '<' 或 '&' 等错误是一种损失,这完全违背了 XML 的工作方式。如果您不能信任您的用户编写格式良好的 XML,请给他们一个更简单的非 XML 接口,例如一个简单的换行符分隔的正则表达式字符串列表。

于 2008-10-29T12:46:22.117 回答
1

正如您所说,普通的序列化程序应该为您转义一切。

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

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

通常,我当然希望所有内容都正确转义,而不是依赖 CDATA“拐杖”,但我也想使用内置工具进行转义。对于用户在“休眠”状态下编辑的内容,我认为 CDATA 可能是要走的路。

另请参阅这个较早的问题:
Best way to encode text data for XML


更新
基于对另一个回复的评论,我意识到您正在向用户展示标记,而不仅仅是内容。Xml 解析器非常挑剔。我认为在这种情况下你可以做的最好的事情是在接受编辑的 xml 之前检查格式是否正确。

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

于 2008-10-28T18:42:14.850 回答
1

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

于 2009-01-28T02:55:17.490 回答
1

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

<textarea cols="80" rows="10" id="1"></textarea>

<script>
elem = document.getElementById("1");

elem.value = '\
<Configuration>\n\
  <Validator Expression="[^&lt;]" />\n\
</Configuration>\
'
alert(elem.value);
</script>

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

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

所以也许一个(不可行的?)解决方案是让您的用户使用 Firefox。


您的问题的两个部分似乎已被揭示:

1您显示的 XML 未转义。

例如,“ &lt;”未转义为“<”。但由于“<”也未转义为“<”,因此信息丢失并且无法取回。

一种解决方案是让您转义所有“ &”字符,使“ &lt;”变为“ &amp;lt;”。然后,这将被 textarea 转义为“ &lt;”。当你读回来时,它会和最初一样。(我假设 textarea 实际上更改了字符串,但 Firefox 的行为不像您报告的那样,所以我无法检查)

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

2您希望用户不必费心转义。

你在逃生地狱:

正则表达式替换将主要工作......但是当用户可能(合法地,在您给出的条款内)输入时,您如何可靠地检测到结束引号(“):

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

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

/[^"<]/

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

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

<Configuration>
  <Expression></Expression></Expression>
</Configuration>

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

嵌套语法,你就在逃生地狱里。

一个简单的解决方案是告诉您的用户:这是一个快速肮脏的配置编辑器,因此您不会得到任何花哨的“无需逃避”mamby-pamby:

  • 列出文本区域旁边的字符和转义符,例如:“<”为“ &lt”。
  • 对于不会验证的 XML,请再次向他们显示列表。

回首往事,我看到bobince在我面前给出了相同的基本答案。

于 2009-01-29T18:46:18.873 回答
1

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

 <Configuration>
   <Validator Expression="<![CDATA[  [^<]   ]]>" />
 </Configuration>

:-)

于 2009-02-07T02:20:02.180 回答
0

这个特殊字符 - “<” - 应该替换为其他字符,以便您的 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);
于 2008-10-28T18:31:25.603 回答
0

这真的是我唯一的选择吗?这不是一个足够普遍的问题,它在框架的某个地方有解决方案吗?

private string EscapeAttributes(string configuration)
{
    var lt = @"(?<=\w+\s*=\s*""[^""]*)<(?=[^""]*"")";
    configuration = Regex.Replace(configuration, lt, "&lt;");

    return configuration;
}

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

于 2008-10-28T19:41:49.690 回答