解析含&的XML遇SAXParseException,求无需修改XML的解决方法
解决未转义&的XML解析问题
遇到外部返回的XML包含未转义的&导致SAX解析报错时,无需修改原XML,可通过以下几种方式处理:
方法1:自定义输入流预处理XML
实现一个InputStream包装类,在读取数据时自动将未转义的&(非实体引用的&)替换为&,让JAXB拿到合法的XML再解析。
import java.io.*; public class UnescapedAmpInputStream extends FilterInputStream { private StringBuilder buffer = new StringBuilder(); private int pos = 0; protected UnescapedAmpInputStream(InputStream in) { super(in); } @Override public int read() throws IOException { if (pos < buffer.length()) { return buffer.charAt(pos++); } int c = super.read(); if (c == '&') { StringBuilder temp = new StringBuilder(); temp.append((char)c); int next; // 检查后续字符是否是合法实体引用(比如&) while ((next = super.read()) != -1 && temp.length() < 5) { temp.append((char)next); if (temp.toString().startsWith("&")) { buffer.append(temp); pos = 0; return buffer.charAt(pos++); } } // 不是合法实体,替换为&并保留后续字符 buffer.append("&").append(temp.substring(1)); pos = 0; return buffer.charAt(pos++); } else { return c; } } }
使用方式:
// 外部XML的输入流 InputStream originalStream = new FileInputStream("savedsearch.xml"); InputStream processedStream = new UnescapedAmpInputStream(originalStream); JAXBContext jaxbContext = JAXBContext.newInstance(MailSavedSearchRO.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); MailSavedSearchRO result = (MailSavedSearchRO) unmarshaller.unmarshal(processedStream);
方法2:用SAX过滤器拦截并转义字符
通过SAX的XMLFilter拦截字符事件,直接替换内容中的未转义&,再交给JAXB解析。
import org.xml.sax.*; import org.xml.sax.helpers.XMLFilterImpl; public class AmpEscapeFilter extends XMLFilterImpl { @Override public void characters(char[] ch, int start, int length) throws SAXException { String content = new String(ch, start, length); // 只替换非标准实体的& String escapedContent = content.replaceAll("&(?!amp;|lt;|gt;|quot;|apos;)", "&"); super.characters(escapedContent.toCharArray(), 0, escapedContent.length()); } }
结合JAXB使用:
SAXParserFactory saxFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxFactory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); AmpEscapeFilter filter = new AmpEscapeFilter(); filter.setParent(xmlReader); JAXBContext jaxbContext = JAXBContext.newInstance(MailSavedSearchRO.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller.setProperty("org.xml.sax.XMLReader", filter); InputStream inputStream = new FileInputStream("savedsearch.xml"); MailSavedSearchRO result = (MailSavedSearchRO) unmarshaller.unmarshal(inputStream);
方法3:用非严格XML解析器转换格式
使用JTidy这类工具将格式不良的XML转换为合法XML,再进行JAXB解析。
先添加Maven依赖:
<dependency> <groupId>net.sf.jtidy</groupId> <artifactId>jtidy</artifactId> <version>r938</version> </dependency>
代码实现:
import org.w3c.dom.Document; import org.w3c.tidy.Tidy; import java.io.FileInputStream; import java.io.InputStream; InputStream inputStream = new FileInputStream("savedsearch.xml"); Tidy tidy = new Tidy(); tidy.setXmlOut(true); // 指定输出XML格式 tidy.setShowWarnings(false); tidy.setQuiet(true); // 转换为合法的DOM文档 Document doc = tidy.parseDOM(inputStream, null); JAXBContext jaxbContext = JAXBContext.newInstance(MailSavedSearchRO.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); MailSavedSearchRO result = (MailSavedSearchRO) unmarshaller.unmarshal(doc);
内容的提问来源于stack exchange,提问作者Sachin HR
相关产品推荐
相关产品推荐

