【问题标题】:How to skip the validation of texts within an xml tag?如何跳过 xml 标签内的文本验证?
【发布时间】:2018-05-18 07:31:26
【问题描述】:

我正在以这种格式从 bugzilla 下载 xml:

<bugzilla>
     <bug>
          <bug_id>111</bug_id>
          <short_desc>text 1 & 2</short_desc>
      </bug>
      <bug>
          <bug_id>222</bug_id>
          <short_desc>text 2 <this is a short desc> </short_desc>
     </bug>
</bugzilla>

如您所见,当我尝试使用 jaxb 解析器解析它时,它失败的原因有两个:

  1. 第一个标签内的&(需要改成&amp;amp; 错误信息:The entity name must immediately follow the '&amp;' in the entity reference.

  2. &lt;this is a short desc&gt; 文本的大小写相同。错误信息The entity name must immediately follow the '&amp;' in the entity reference.

但我不明白的是这些都是有效标签的内容。那么为什么要为这些内容运行验证逻辑。在第二种情况下,它不仅仅是一个标记为&lt;thisisashortdesc&gt;,它可能会引发实际的有效错误,说明缺少结束标记。但这种情况下有空格。

找到下面使用过的代码g:

文件file = new File("C:\test\file.xml");

    JAXBContext jaxbContext = JAXBContext.newInstance(Bugzilla.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    Bugzilla bugzillaReport = (Bugzilla) jaxbUnmarshaller.unmarshal(file);

无论如何解决这个问题。

【问题讨论】:

  • 这不是验证,而是格式良好。这不是关于验证是否尊重某些约束,而是关于是否可以阅读此内容。 XML 文档必须是格式正确的,否则解析器将无法知道应该表示什么数据以及如何从那里继续解析,换句话说,它无法完成预期的工作,所以假装没有意义。验证可以跳过,而且经常是这样。格式正确是必须的,因为它是解析的一部分。
  • @kumesana 谢谢你的信息..

标签: java xml parsing xsd xml-parsing


【解决方案1】:

如您所知,必须解析有效的 XML,因为没有 HTML 中的模糊匹配。标准解决方案是放置一个&lt;![CDATA[....]]&gt;。 (CDATA 代表字符数据。)

<short_desc><![CDATA[text 1 & 2]]></short_desc>
<short_desc><![CDATA[text 2 <this is a short desc> ]]></short_desc>

这很麻烦,问题是当需要文本而不是 CData 时,使用是否仍然有效。并且创建正确的 XML 可能更容易。 Apache commons 也有一个 StringEscapeUtils.escapeXml10(String) 用于此目的。

先试试(CDATA)。

String xml = new String(Files.readAllBytes(Paths.get("C:\\test\\file.xml")),
         StandardCharsets.UTF_8);
xml = "<?xml version=\"1.0\">\n" + xml;
xml = xml.replace("<short_desc>", "<short_desc><![CDATA[");
xml = xml.replace("</short_desc>", "]]></short_desc>");
jaxbUnmarshaller.unmarshal(new StreamSource(new StringReader(xml)));

请注意,反斜杠 \ 必须在 java 字符串中进行自我转义。

Java 9 修复:

xml = xml.replaceAll("(?s)<short_desc>(.*)</short_desc>",
        matchResult -> "<short_desc>"
                       + StringEscapeUtils.escapeXml10(matchResult.group(1))
                       + "</short_desc>");

或者没有 apache common lang StringEscapeUtils:

xml = xml.replaceAll("(?s)<short_desc>(.*)</short_desc>",
        matchResult -> "<short_desc>"
                       + matchResult.group(1)
                             .replace("&", "&amp;")
                             .replace("\"", "&quot;")
                             .replace("<", "&lt;")
                             .replace(">", "&gt;")
                       + "</short_desc>");

【讨论】:

  • 成功了。我无法控制修改 xml 文件。所以就像你建议的那样,我将标签内容包含在 CDATA 标签中,它工作正常。非常感谢。您能否解释一下解析器如何以及为什么会跳过 CDATA 标记,或者如何考虑 cdata 标记中的内容。
  • CDATA 部分由]]&gt; 分隔,是一种包含未处理文本的方法(应该检查不包含“]]>”)。在 DOM 树中,它不是 #text 节点,而是它自己的节点。然而大多数 XML API 提供了一个get text content,收集几个连续的#text 节点等等。因此它可以工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-22
  • 1970-01-01
  • 2010-10-03
  • 2015-11-25
  • 1970-01-01
  • 2011-06-26
  • 1970-01-01
相关资源
最近更新 更多