【问题标题】:org.xml.sax.SAXParseException: The reference to entity "T" must end with the ';' delimiterorg.xml.sax.SAXParseException:对实体“T”的引用必须以“;”结尾分隔符
【发布时间】:2010-12-29 00:00:07
【问题描述】:

我正在尝试使用 DOM 解析器解析包含一些特殊字符(如“&”)的 XML 文件。我收到了 saxparse 异常“对实体的引用必须以分隔符结尾”。有什么办法可以克服这个异常,因为我无法修改 XML 文件以删除特殊字符,因为它来自不同的应用程序。请提出一种解析此 XML 文件以获取根元素的方法?

提前致谢

这是我正在解析的 XML 部分

<P>EDTA/THAM WASH 
</P>

<P>jhc ^ 72. METER SOLVENT: Meter 21 LITERS of R. O. WATER through the add line into 
FT-250. Start agitator. 
</P>

<P>R. O. WATER &lt;ZLl LITERS </P>

<P>•     NOTE: The following is a tool control operation. The area within 10 feet of any open vessel or container is under tool control. </P>

<P>-af . 73. CHARGE SOLIDS: Remove any unnecessary items from the tool controlled area. Indicate the numbers of each item that will remain in the tool controlled area during the operation in the IN box of the Tool Control Log. </P>

<P>^___y_ a. To minimize the potential for cross contamination, confirm that no other solids are being charged or packaged in adjacent equipment. </P>

<P>kk k WARNING: Wear protective gloves, air jacket and use local exhaust when handling TROMETHAMINE USP (189400) (THAM) (K-l--Irritant!). The THAM may be dusty. </P>

<P>-&lt;&amp;^b .   Charge 2.1 KG of TROMETHAMINE USP (189400) (THAM) into FT-250 through the top. </P>

<P>TROMETHAMINE USP (189400) (THAM) </P>

<P>Scale ID:     / / 7S </P>

<P>LotNo.:   qy/o^yo^ </P>

<P>Gross:    ^ . S </P>

<P>Tare: 10 ,1 </P>

<P>Net:     J^l </P>

<P>Total:   JL'J </P>

<P><Figure ActualText="&T ">

<ImageData src="images/17PT 07009K_img_1.jpg"/>
&amp;T </Figure>
Checked by </P>

【问题讨论】:

    标签: java xml


    【解决方案1】:

    我不确定我是否理解这个问题。据我所知,除非你在 CDATA 内,否则没有结束 ; 的裸 &amp; 字符是无效的。

    如果您的 XML 文件不是这种情况,那么它是无效的,您需要找到另一种解析它的方法,或者在 SAX 获取它之前修复它。

    如果我在这里有什么误解,您可能应该发布一个实际 XML 的示例,以便我们进一步了解。

    更新:

    看起来像:

    Figure ActualText="&T "
    

    是违规行。此部分是否在 CDATA 内?如果不是,这不是有效的 XML,你不应该期望 SAX 能够处理它。

    您需要:

    • 更改创建它的应用程序;或
    • 在它被 SAX 加载之前修复它(如果你不能改变那个应用程序)像“Figure ActualText="&amp;amp;T "”这样的东西;或
    • 找到一种非 SAX 方法进行解析。

    【讨论】:

      【解决方案2】:

      作为一种解决方法,您可以:

      1. 将原始输入中所有出现的&amp;amp; 替换为&amp;amp;
      2. 解析它;
      3. 在处理结果的代码中,处理现在出现转义字符的情况(例如,&amp;lt; 而不是 &lt;)。

      根据您使用的解析器,您还可以尝试找到负责解析和取消转义&amp;amp;-strings 的类,看看您是否可以扩展它/提供您自己的解析器。 (我说的很模糊,但具体取决于您使用的工具。)

      【讨论】:

      • 带弹簧:HtmlUtils.htmlEscape(字符串输入)
      【解决方案3】:

      您的输入是无效的 XML。具体来说,您不能在属性值中包含“&”字符,除非它是格式良好的字符实体引用的一部分。

      AFAIK,你有两个选择:

      • 自己编写一个“不完全是 XML”的解析器。我严重怀疑你会找到一个现有的。任何自尊的 XML 解析器都会拒绝无效输入。
      • 修复创建此(所谓)XML 的任何内容,使其不会将随机“&”字符放在不允许的位置。这真的很简单。在构建 XML 时,将不属于字符引用的“&”字符替换为“&”

      【讨论】:

        【解决方案4】:

        正如其他人所说,您的 XML 肯定是无效的。但是,如果您无法更改生成应用程序并且可以添加清理步骤,那么以下内容应该清理 XML:

        String clean = xml.replaceAll( "&([^;]+(?!(?:\\w|;)))", "&amp;$1" );
        

        该正则表达式正在做的是寻找任何格式错误的实体引用并转义&符号。

        具体来说,(?!(?:\\w|;)) 是一个负前瞻,它使匹配停止在任何不是单词字符 (a-z,0-9) 且不是分号的地方。所以整个正则表达式从 & 中获取所有不是 ;直到第一个非单词、非分号字符。

        它将除 & 符号之外的所有内容放在第一个捕获组中,以便可以在替换字符串中引用它。那是 1 美元。

        请注意,这不会修复看似有效但实际上无效的引用。例如,如果你有 &T;除非 XML 实际定义了实体,否则这将完全引发不同类型的错误。

        【讨论】:

        • 只是一点评论。无论模式如何,它当然都是无效的,但首先它的格式不正确。我们不是在这里讨论模式。
        • String xml = "Aaa & Bbb & Ccc";结果 Aaa & Bbb & Ccc。这可以在输入字符串中对多个 & 起作用吗?
        • 是的。尝试 "&([^;&]+(?!(?:\\w|;)))" (在位置 6 上添加 &) - 这应该适用于输入中的多个 &。
        • 这里有很好的解释:stackoverflow.com/questions/1944392/…
        【解决方案5】:

        在向您的 XML 模板添加或更改任何代码时,有些人可能熟悉错误“对实体 XX 的引用必须以';'分隔符结尾”。甚至当我尝试更改或添加一些代码到我的博客模板 (XML) 时,有时也会出现该错误。

        大多数此类错误发生在我们将任何第三方横幅或小部件添加到我们的 XML 模板时。我们可以通过对我们添加的代码稍作改动来轻松纠正该错误!

        Just replace “&” with “&amp;” in your HTML/Javascript code!
        

        示例

        Original Code:
        <!– Begin Code –>
        <script src="http://XXXXXX.com/XXX.php?sid=XXX&br=XXX&dk=XXXXXXXXXXXX" type="text/javascript"/>
        <!– End Code –>
        
        Altered Code:
        
        <!– Begin Code –>
        <script src="http://XXXXXX.com/XXX.php?sid=XXX&amp;br=XXX&amp;dk=XXXXXXXXXXXX" type="text/javascript"/>
        <!– End Code –>
        

        【讨论】:

          【解决方案6】:

          基于 PSpeed 的上述答案,以下 replaceAll 正则表达式和替换文本将用转义的 & 符号替换所有未转义的 & 符号。

          String clean = xml.replaceAll( ("(&(?!amp;))", "&amp;") );
          

          该模式是一个负前瞻,以匹配任何尚未转义的 & 符号,并且替换字符串只是一个转义的 & 符号。这可以通过使用静态编译的模式进一步优化性能。

          private final static Pattern unescapedAmpersands = Pattern.compile("(&(?!amp;))");
          
          ...
          
          Matcher m = unescapedAmpersands.matcher(xml);
          String xmlWithAmpersandsEscaped = m.replaceAll("&amp;");
          

          【讨论】:

            【解决方案7】:

            只需将您的&amp;amp; 替换为&amp;amp; 即可。

            【讨论】:

              【解决方案8】:

              如果您在发布前使用以下命令,它将起作用。

              请将您的 xml 文件名放在下面的命令中

              sed -i "s/&/;/g" *.xml
              

              【讨论】:

              • 感谢 Suraj 对字体进行格式化。例如它 --> 它
              【解决方案9】:

              作为@PSpeed 答案的补充,这里有一个完整的解决方案(SAX 解析器):

                  try {
              
                      InputStream xmlStreamToParse = blob.getBinaryStream();
              
                      // Clean
                      BufferedReader br = new BufferedReader(new InputStreamReader(xmlStreamToParse));
              
                      StringBuilder sb = new StringBuilder();
              
                      String line;
                      while ((line = br.readLine()) != null) {
                          sb.append(line.replaceAll("&([^;]+(?!(?:\\w|;)))", "&amp;$1")); // or whatever you want to clean
                      }
              
                      InputStream stream = org.apache.commons.io.IOUtils.toInputStream(sb.toString(), "UTF-8");
              
                      // Parsing
                      SAXParserFactory saxFactory = SAXParserFactory.newInstance();
                      saxFactory.setNamespaceAware(true);
                      SAXParser theParser = saxFactory.newSAXParser();
                      XMLReader xmlReader = theParser.getXMLReader();
                      LicenceXMLHandler licence = new LicenceXMLHandler();
                      xmlReader.setContentHandler(licence);
                      xmlReader.parse(new InputSource(stream));
              
                  } catch (SQLException | SAXException | IOException | ParserConfigurationException e) {
                      log.error("Error: " + e);
                  }
              

              解释:

              • 将 Blob 转换为 InputStream
              • 清理 Blob
              • 解析文件(LicenceXMLHandler就是解析器类)

              【讨论】:

                猜你喜欢
                • 2022-07-12
                • 2011-07-05
                • 2011-09-22
                • 2014-05-26
                • 2020-07-14
                • 1970-01-01
                • 2012-12-16
                • 2019-10-04
                相关资源
                最近更新 更多