【问题标题】:Java: Escape XML text content instead of entire textJava:转义 XML 文本内容而不是整个文本
【发布时间】:2019-09-03 13:44:24
【问题描述】:

我想发送下面的 XML 请求。文本内容应该被转义,而不是标签。

我已尝试使用以下转义逻辑。
String str = escapeXml11(req);

但是,我的整个请求都被逃脱了。因此,它不再是有效的 XML。

我的原始字符串:

String req =
"<request>\r\n" 
  + " <Products>\r\n" 
    + " <Product>\r\n" 
      + " <ProductName>H < M</ProductName>\r\n" 
      + " <quantity>1</quantity>\r\n" 
      + " <totalProductCost>17.03</totalProductCost>\r\n" 
    + " </Product>\r\n" 
  + " </Products>\r\n" 
+ "</request>"; 

转义后:

&lt;request&gt;
    &lt;ProductName&gt;H &lt; M&lt;/ProductName&gt;
    &lt;quantity&gt;1&lt;/quantity&gt;
    &lt;totalProductCost&gt;17.03&lt;/totalProductCost&gt;
&lt;/request&gt

预期结果:

<request>
    <ProductName>H &lt; M</ProductName>
    <quantity>1</quantity>
    <totalProductCost>17.03</totalProductCost>
</request>

如何只转义文本内容?

【问题讨论】:

  • 构建 XML 后无法转义值,因为未转义值的 XML 字符串 不是有效的 XML,因此您不会能够正确解析它以将值与标签分开。您需要在构建 XML 时转义各个值字符串。另外,我建议研究一下 Jackson 之类的东西,而不是手动构建 XML。
  • 感谢乔丹的建议。我从第三方收到这个请求 XML 字符串,它是字符串格式的。我想将此字符串用作有效的 XML。
  • 嗯,那就有问题了。因为第 3 方发送给您的是非有效的 XML,他们绝对应该正确地转义值。恐怕我不知道有任何特定工具可以修复格式错误的 XML。但这并不意味着它们不存在!
  • 你称它为 XML 字符串,但它不是。您需要澄清您与第三方的合同:如果您同意以 XML 格式交换数据,那么他们将不得不更改其代码以使其成为有效的 XML。如果您同意其他格式,那么您有责任。如果您不同意交换的规范,那么双方都需要从错误中吸取教训。

标签: java xml special-characters


【解决方案1】:

所以这个问题的根源在于第 3 方提供给您的“XML”格式不正确。

<request>
  <Products>
    <Product>
      <ProductName>H < M</ProductName>
      <quantity>1</quantity>
      <totalProductCost>17.03</totalProductCost>
    </Product>
  </Products> 
</request>

要更正此问题,您需要将 "H &lt; M" 转换为 "H &amp;lt; M"。如果人类必须做很多这样的事情,那么人类很容易做到这一点,模精度问题。但是自动化很困难。

显然,简单地调用转义方法是行不通的。转义方法无法在不解析 XML 的情况下确定需要转义的内容。 (escapeXml11 之类的方法仅在需要转义整个字符串时才有效。)

普通的 XML 解析器会看到 "&lt; M" 并尝试将其视为元素标记的开始。然后它会看到下一个 "&lt;" ... 和错误。为了进一步进行,它必须回溯到"&lt; M" 并将"&lt;" 处理就好像它被转义了。

我知道有一种 HTML / XML 解析器 (JSoup) 可以处理错位的 "&lt;" 字符。但是,如果我理解正确,它会以错误的方式为您的用例处理这个问题。它不会将"&lt; M" 视为数据,而是将其转换为开始标记:

<request>
  <Products>
    <Product>
      <ProductName>H <M></ProductName>
      <quantity>1</quantity>
      <totalProductCost>17.03</totalProductCost>
    </Product>
  </Products> 
</request>

这让您有两种选择:

  • 您可以尝试通过一些模式匹配来检测和解决问题。例如,如果您知道格式错误的数据位于 &lt;ProductName&gt;...&lt;/ProductName&gt; 元素中,则可以使用正则表达式搜索这些元素,检查并(如有必要)更正内容,然后替换它。

  • 您可以使用上下文相关的词法分析器为您的 XML 编写自定义解析器。当解析器看到&lt;ProductName&gt; 时,它会将词法分析器切换到将“&lt;”视为数据的不同模式除非它是&lt;/ProductName&gt; 的开头。


但是在您花费时间和费用编写一堆自定义代码来处理这个无效的 XML 之前:

  • 向创建它的第 3 方投诉。他们不应该像那样排放垃圾。他们的软件或他们的数据收集/清理存在缺陷。他们应该修复它。

  • 确保支付软件开发和维护费用的人都知道这一点。例如,如果您被委托编写一些处理 XML 的软件,那么这不是 XML。如果客户没有警告您您的软件需要处理格式错误的 XML,这就是需求的变化,并且可能(应该)是合同的变体。

    李>

另见@Michael Kay 的评论。

【讨论】:

  • 感谢 Michael 和 Stephen 提供的宝贵意见。是的,确实收到有效的 Xml 是我在报告问题时建议的第一件事。但是,有人建议我四处寻找任何可能的解决方案。
【解决方案2】:

这是我在到处寻找解决方案后发现的:

获取 Jsoup 库:

<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.12.1</version>
</dependency>

然后:


Document doc = Jsoup.parse(new ByteArrayInputStream(YOUR_XML_STRING_HERE.getBytes("UTF-8")), "UTF-8", "", Parser.xmlParser())
doc.outputSettings().charset("UTF-8")
doc.outputSettings().escapeMode(Entities.EscapeMode.base)

println doc.toString()

希望这对某人有所帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-20
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多