【问题标题】:Replace xml special characters in Java String替换Java字符串中的xml特殊字符
【发布时间】:2018-12-13 20:49:43
【问题描述】:

我们从一个来源获取 XML,然后传递给另一个实体进行进一步处理。但是,获取的 XML 在属性值中包含特殊字符,这些字符不能被下一个进程接受。 例如

示例输入:

"<Message text="<html>Welcome User, <br> Happy to have you. <br>.</html>"

预期输出:

"<Message text="&lt;html&gt;Welcome User, &lt;br&gt; Happy to have you. &lt;br&gt;.&lt;/html&gt;">

示例输入:&lt;Message text="&lt;html&gt;Welcome User, &lt;br&gt; Happy to have you. &lt;/html&gt;" Multi="false"&gt; &lt;Meta source="system" dest="any"&gt;&lt;/Meta&gt;&lt;/Message&gt;

输出:&lt;Message text="&amp;lt;html&amp;gt;Welcome User, &amp;lt;br&amp;gt; Happy to have you. &amp;lt;/html&amp;gt;" Multi="false"&gt; &lt;Meta source="system" dest="any"&gt;&lt;/Meta&gt;&lt;/Message&gt;

但如果输入有多个&lt;br&gt; 标签,&lt;br&gt; 不会被替换。

我们正在使用以下代码:

String xml = "<Message text=\"<html>Welcome User, <br> Happy to have you. <br>.</html>\" Multi=\"false\"><Meta source=\"system\" dest=\"any\"></Meta></Message>";
System.out.println("ORG:" + xml);
xml = replaceChars(xml);
System.out.println("NEW:" + xml);

private static String replaceChars(String xml)
        {
           xml = xml.replace("&", "&amp;");
           xml = xml.replaceAll("\"<([^<]*)>", "\"&lt;$1&gt;");
            xml = xml.replaceAll("</([^<]*)>\"", "&lt;/$1&gt;\"");
            xml = xml.replaceAll("\"([^<]*)<([^<]*)>([^<]*)\"", "\"$1&lt;$2&gt;$3\"");

            return xml;
        }

【问题讨论】:

标签: java regex xml


【解决方案1】:

请不要使用正则表达式转义 XML 中的特殊字符。

你能保证这将适用于所有可能的 html 输入以及所有 HTML 和 XML 怪癖(非常广泛的规范!!!)?

只需使用众多实用程序之一来转义 XML 字符串。

Apache Commons 很受欢迎 - please see this example

【讨论】:

    【解决方案2】:

    要匹配你可以使用正则表达式:

    (?:&lt;)(?&lt;=&lt;)(\/?\w*)(?=.*(?&lt;=&lt;\/html))(?:&gt;)

    • (?:&lt;) 匹配但不捕获 &lt;
    • (?&lt;=&lt;)&lt; 的正面回溯。
    • (\/?\w*) 捕获标签名称。可选的/ 和单词字符。
    • (?=.*(?&lt;=&lt;\/html)) 正向前瞻,然后正向后向查看结束标签。
    • (?:&gt;) 匹配但不捕获 &gt;

    要替换你可以使用:

    • &amp;lt;$1&amp;gt;

    其中$1 是正则表达式中捕获组的结果。 您可以交互地测试正则表达式here

    使用以下 Java 代码:

     public static void main(String []args){
        String xml = "<Message text=\"<html>Welcome User, <br> Happy to have you. <br>.</html>\" Multi=\"false\"><Meta source=\"system\" dest=\"any\"></Meta></Message>";
        String newxml = replaceChars(xml);
        System.out.println(newxml);
     }
    
     private static String replaceChars(String xml)
        {
           xml = xml.replaceAll("(?:<)(?<=<)(\/?\w*)(?=.*(?<=<\/html))(?:>)", "&lt;$1&gt;");
           return xml;
        }
    

    输出是:

    "&lt;Message text="&amp;lt;html&amp;gt;Welcome User, &amp;lt;br&amp;gt; Happy to have you. &amp;lt;/html&amp;gt;" Multi="false"&gt; &lt;Meta source="system" dest="any"&gt;&lt;/Meta&gt;&lt;/Message&gt;"

    【讨论】:

    • 部分正确。整个输出是:&lt;Message text="&amp;lt;html&amp;gt;Welcome User, &amp;lt;br&amp;gt; Happy to have you. &amp;lt;br&amp;gt;.&amp;lt;/html&amp;gt;" Multi="false"&gt; &lt;Meta source="system" dest="any"&gt;&amp;lt;/Meta&amp;gt;&amp;lt;/Message&amp;gt; 观察MetaMessage 的结束标签。基本上,我们只想考虑那些在""(双引号)之间的内容。
    • @Chota 对,我明白了。请尝试(?:&lt;)(?&lt;=&lt;)(\/?\w*)(?=.*(?&lt;=&lt;\/html))(?:&gt;)here。让我知道,我会更新我的答案。
    • 是的,这更好,但这似乎期望它总是以&lt;/html&gt; 结尾,但实际上并非如此。我们可能有一个字符串,其中只有一些 &lt;br&gt;
    • 在第二个lookbehind中添加额外的案例是很简单的,你知道你会想要匹配的标签,即(?&lt;=&lt;\/html|\/br)
    【解决方案3】:

    XML 不是文本。事实上,XML 文档是一种二进制格式

    将 XML 作为文本处理是错误的方法,并且只适用于简单的情况。 需要考虑的事项:

    • XML 文档没有文件编码,但在文档中指定了内容编码(因此它必须由正确处理此问题的 XML 解析器读取)。
    • XML文档使用XML实体(内置如&amp;amp;&amp;lt;&amp;gt;&amp;quot;,其他可以在DDL中任意定义,见https://www.w3resource.com/xml/entities.php)。
    • XML 文档可以包含 CDATA

    因此:

    • 使用适当的 XML 解析器来读取文档
    • 在 DOM(文档对象模型)或流模型上执行操作(文本替换、添加/删除节点)。
    • 使用适当的 XML 处理器来编写文档

    顺便说一下,示例中的 XML 不是 xml(格式错误,因为没有实体用于 &lt;&gt;"

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-07
      相关资源
      最近更新 更多