问题 - 1:我必须在Java中解析一堆XML文件,这些文件有时 - 并且无效 - 包含HTML实体,例如—
XML 只有五个预定义的实体。的 不在其中。它仅在纯HTML或旧版JSP中使用时才有效。因此,SAX将无济于事。它可以使用具有基于高级迭代器的API来完成。(收集自此链接—
StaX
)
问题 - 2:我发现我可以在 org.xml.sax.helpers.DefaultHandler 中覆盖 resolveEntity,但是如何将其与更高级别的 API 一起使用?
用于 XML 的流式 API,称为 StaX,是 用于 的 API。reading and writing XML Documents
StaX
是拉取解析模型。应用程序可以通过从解析器中提取(获取)事件来控制 XML 文档的分析。
核心 StaX API 属于,它们在下面列出。他们是two categories
STaX API has support for the notion of not replacing character entity references
,通过IS_REPLACING_ENTITY_REFERENCES属性:
要求分析器将内部实体引用替换为其替换文本,并将其报告为字符
这可以设置为 一个 ,然后又用于构造 一个 或 。XmlInputFactory
XmlEventReader
XmlStreamReader
但是,API 谨慎地说,此属性仅用于强制实现执行替换,而不是强制它不替换它们。
你可以试试。希望它能解决您的问题。对于您的情况,
主要.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.EntityReference;
import javax.xml.stream.events.XMLEvent;
public class Main {
public static void main(String[] args) {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(
XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
XMLEventReader reader;
try {
reader = inputFactory
.createXMLEventReader(new FileInputStream("F://test.xml"));
while (reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if (event.isEntityReference()) {
EntityReference ref = (EntityReference) event;
System.out.println("Entity Reference: " + ref.getName());
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
}
}
测试.xml:
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>Some text — invalid!</bar>
</foo>
输出:
实体参考: nbsp
实体参考:mdash
功劳归于 .@skaffman
相关链接:
- http://www.journaldev.com/1191/how-to-read-xml-file-in-java-using-java-stax-api
- http://www.journaldev.com/1226/java-stax-cursor-based-api-read-xml-example
- http://www.vogella.com/tutorials/JavaXML/article.html
- 是否有 Java XML API 可以在不解析字符实体的情况下解析文档?
更新:
问题 - 3:有没有办法使用StaX来“过滤”实体(例如,用其他东西替换它们),并在流程结束时仍然生成文档?
要使用 StAX API 创建新文档,需要创建一个提供生成 XML 开始和结束标记、属性和字符内容的方法的 API。XMLStreamWriter
有 5 种方法用于文档。XMLStreamWriter
-
xmlsw.writeStartDocument();
- 初始化可以添加元素的空文档
-
xmlsw.writeStartElement(String s)
-创建一个名为 s 的新元素
-
xmlsw.writeAttribute(String name, String value)
- 将具有相应值的属性名称添加到由调用 writeStartElement 生成的最后一个元素。只要没有对 writeElementStart、writeCharacters 或 writeEndElement 的调用完成,就可以添加属性。
-
xmlsw.writeEndElement
- 关闭最后一个启动的元素
-
xmlsw.writeCharacters(String s)
- 创建一个新的文本节点,其内容 s 作为最后一个启动元素的内容。
随之附上了一个示例:
StAXExpand.java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.util.Arrays;
public class StAXExpand {
static XMLStreamWriter xmlsw = null;
public static void main(String[] argv) {
try {
xmlsw = XMLOutputFactory.newInstance()
.createXMLStreamWriter(System.out);
CompactTokenizer tok = new CompactTokenizer(
new FileReader(argv[0]));
String rootName = "dummyRoot";
// ignore everything preceding the word before the first "["
while(!tok.nextToken().equals("[")){
rootName=tok.getToken();
}
// start creating new document
xmlsw.writeStartDocument();
ignorableSpacing(0);
xmlsw.writeStartElement(rootName);
expand(tok,3);
ignorableSpacing(0);
xmlsw.writeEndDocument();
xmlsw.flush();
xmlsw.close();
} catch (XMLStreamException e){
System.out.println(e.getMessage());
} catch (IOException ex) {
System.out.println("IOException"+ex);
ex.printStackTrace();
}
}
public static void expand(CompactTokenizer tok, int indent)
throws IOException,XMLStreamException {
tok.skip("[");
while(tok.getToken().equals("@")) {// add attributes
String attName = tok.nextToken();
tok.nextToken();
xmlsw.writeAttribute(attName,tok.skip("["));
tok.nextToken();
tok.skip("]");
}
boolean lastWasElement=true; // for controlling the output of newlines
while(!tok.getToken().equals("]")){ // process content
String s = tok.getToken().trim();
tok.nextToken();
if(tok.getToken().equals("[")){
if(lastWasElement)ignorableSpacing(indent);
xmlsw.writeStartElement(s);
expand(tok,indent+3);
lastWasElement=true;
} else {
xmlsw.writeCharacters(s);
lastWasElement=false;
}
}
tok.skip("]");
if(lastWasElement)ignorableSpacing(indent-3);
xmlsw.writeEndElement();
}
private static char[] blanks = "\n".toCharArray();
private static void ignorableSpacing(int nb)
throws XMLStreamException {
if(nb>blanks.length){// extend the length of space array
blanks = new char[nb+1];
blanks[0]='\n';
Arrays.fill(blanks,1,blanks.length,' ');
}
xmlsw.writeCharacters(blanks, 0, nb+1);
}
}
紧凑型刻度.java
import java.io.Reader;
import java.io.IOException;
import java.io.StreamTokenizer;
public class CompactTokenizer {
private StreamTokenizer st;
CompactTokenizer(Reader r){
st = new StreamTokenizer(r);
st.resetSyntax(); // remove parsing of numbers...
st.wordChars('\u0000','\u00FF'); // everything is part of a word
// except the following...
st.ordinaryChar('\n');
st.ordinaryChar('[');
st.ordinaryChar(']');
st.ordinaryChar('@');
}
public String nextToken() throws IOException{
st.nextToken();
while(st.ttype=='\n'||
(st.ttype==StreamTokenizer.TT_WORD &&
st.sval.trim().length()==0))
st.nextToken();
return getToken();
}
public String getToken(){
return (st.ttype == StreamTokenizer.TT_WORD) ? st.sval : (""+(char)st.ttype);
}
public String skip(String sym) throws IOException {
if(getToken().equals(sym))
return nextToken();
else
throw new IllegalArgumentException("skip: "+sym+" expected but"+
sym +" found ");
}
}
有关详细信息,您可以按照教程进行操作
- https://docs.oracle.com/javase/tutorial/jaxp/stax/example.html
- http://www.ibm.com/developerworks/library/x-tipstx2/index.html
- http://www.iro.umontreal.ca/~lapalme/ForestInsteadOfTheTrees/HTML/ch09s03.html
- http://staf.sourceforge.net/current/STAXDoc.pdf