私はJavaの一連のXMLファイルを解析する必要があります。これには、—
、>
などのHTMLエンティティが含まれていることがあります。これを処理する正しい方法は、適切なエンティティ宣言を解析前にXMLファイルに追加することですが、これらのXMLファイルを制御できないため、これを行うことはできません。
Java XMLパーサーがこのようなエンティティに遭遇するたびに呼び出される、オーバーライドできるある種のコールバックはありますか?APIでそれを見つけることができませんでした。
使用したい:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = dbf.newDocumentBuilder();
Document doc = parser.parse( stream );
org.xml.sax.helpers.DefaultHandler
のresolveEntity
をオーバーライドできることがわかりましたが、これをより高レベルのAPIで使用するにはどうすればよいですか?
ここに完全な例があります:
public class Main {
public static void main( String [] args ) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = dbf.newDocumentBuilder();
Document doc = parser.parse( new FileInputStream( "test.xml" ));
}
}
test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>Some text — invalid!</bar>
</foo>
生成する:
[Fatal Error] :3:20: The entity "nbsp" was referenced, but not declared.
Exception in thread "main" org.xml.sax.SAXParseException; lineNumber: 3; columnNumber: 20; The entity "nbsp" was referenced, but not declared.
更新:私はJDKソースコードをデバッガーといじくり回していました。デザインが何であるか、またはデザインがあるかどうかはわかりません。タマネギの層を何層重ねることができますか?
主要なクラスはcom.Sun.org.Apache.xerces.internal.impl.XMLEntityManager
のようですが、使用前に要素を追加できるコードや、そのクラスを経由せずにエンティティを解決しようとするコードは見つかりません。
この目的のために、Jsoupのようなライブラリを使用します。私は以下をテストしましたが、うまくいきます。これが役立つかどうかはわかりません。ここにあります: http://jsoup.org/download
public static void main(String args[]){
String html = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><foo>" +
"<bar>Some text — invalid!</bar></foo>";
Document doc = Jsoup.parse(html, "", Parser.xmlParser());
for (Element e : doc.select("bar")) {
System.out.println(e);
}
}
結果:
<bar>
Some text — invalid!
</bar>
ファイルからの読み込みはここにあります:
問題-1:私はXMLファイルの束を解析する必要があります Javaそれは時々-そして無効に-_
—
_などのHTMLエンティティを含む
XMLには 5つの定義済みエンティティ のみがあります。 _—
_、_
_はそれらの中にありません。プレーンHTMLまたはレガシーJSPで使用する場合にのみ機能します。したがって、SAXは役に立ちません。これはStaX
を使用して行うことができます高レベルのイテレータベースのAPIを持っています。 (これから収集 リンク )
問題-2:org.xml.sax.helpers.DefaultHandlerのresolveEntityをオーバーライドできることがわかりましたが、これを高レベルAPI?
StaXと呼ばれるXML用のストリーミングAPIは、_reading and writing XML Documents
_のAPIです。
StaX
は、プル解析モデルです。アプリケーションは、パーサーからイベントをプル(取得)することにより、XMLドキュメントの解析を制御できます。
コアStaX APIは_two categories
_に分類され、以下にリストされています。彼らです
カーソルベースのAPI:_low-level API
_です。カーソルベースのAPIを使用すると、アプリケーションはXMLをトークン(イベント)のストリームとして処理できます
イテレータベースのAPI:_higher-level
_イテレータベースのAPIを使用すると、アプリケーションはXMLを一連のイベントオブジェクトとして処理できます。アプリケーションへのXML構造の一部。
_STaX API has support for the notion of not replacing character entity references
_、 IS_REPLACING_ENTITY_REFERENCES プロパティを使用:
内部エンティティ参照を置換テキストで置き換え、文字として報告することをパーサーに要求します
これはXmlInputFactory
に設定できます。次に、これを使用してXmlEventReader
またはXmlStreamReader
を構築します。
ただし、APIは、このプロパティが実装を強制的に置き換えることを意図しているのではなく、強制的に置き換えることを意図したものではないと慎重に言っています。
試してみてください。それがあなたの問題を解決することを願っています。あなたの場合、
_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 version="1.0" encoding="UTF-8"?>
<foo>
<bar>Some text — invalid!</bar>
</foo>
_
出力:
エンティティリファレンス:nbsp
エンティティリファレンス:mdash
クレジットは_@skaffman
_に送られます。
関連リンク:
UPDATE:
問題-3:StaXを使用してエンティティを「フィルタリング」し(たとえば、エンティティを別のものに置き換える)、それでもドキュメントを生成する方法はありますかプロセスの最後に?
StAX APIを使用して新しいドキュメントを作成するには、XMLの開始タグと終了タグ、属性、文字コンテンツを生成するメソッドを提供するXMLStreamWriter
を作成する必要があります。
ドキュメントにはXMLStreamWriter
の5つのメソッドがあります。
xmlsw.writeStartDocument();
-要素を追加できる空のドキュメントを初期化しますxmlsw.writeStartElement(String s)
-sという名前の新しい要素を作成しますxmlsw.writeAttribute(String name, String value)
- writeStartElementの呼び出しによって生成された最後の要素に、対応する値を持つ属性名を追加します。 writeElementStart、writeCharactersまたはwriteEndElementの呼び出しが行われていない限り、属性を追加できます。xmlsw.writeEndElement
_-最後に開始された要素を閉じるxmlsw.writeCharacters(String s)
-最後に開始された要素のコンテンツとしてコンテンツsを持つ新しいテキストノードを作成します。サンプルが添付されています。
_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);
}
}
_
_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 ");
}
}
_
詳細については、チュートリアルに従うことができます
とにかく厳格なOXMアプローチを使用していないため、別のアプローチ。 JSoupなどの厳格でないパーサーを使用してみませんか?これにより、無効なXMLスキーマなどの問題がすぐになくなりますが、問題がコードに展開されるだけです。
ソリューションへの異なるアプローチを投入するだけです。
入力ストリームを、エンティティを正当なもので置き換えるストリーム補完で包むことができます。
これは確かにハックですが、迅速かつ簡単な解決策である必要があります(またはより適切に言うと、回避策)。
ただし、xmlフレームワークの内部ソリューションほどエレガントでクリーンではありません。
私は昨日、ストリーム内の解凍されたXMLからデータベースに値を追加する必要がある同様の何かを作りました。
//import I'm not sure if all are necessary :)
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
//I didnt checked this code now because i'm in work for sure its work maybe
you will need to do little changes
InputSource is = new InputSource(new FileInputStream("test.xml"));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
String words= xpath.evaluate("/foo/bar", doc.getDocumentElement());
ParsingHexToChar.parseToChar(words);
// lib which i use common-lang3.jar
//metod to parse
public static String parseToChar( String words){
String decode= org.Apache.commons.lang3.StringEscapeUtils.unescapeHtml4(words);
return decode;
}
Org.Apache.commonsパッケージを使用してこれを試してください:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = dbf.newDocumentBuilder();
InputStream in = new FileInputStream(xmlfile);
String unescapeHtml4 = IOUtils.toString(in);
CharSequenceTranslator obj = new AggregateTranslator(new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE()),
new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE())
);
unescapeHtml4 = obj.translate(unescapeHtml4);
StringReader readerInput= new StringReader(unescapeHtml4);
InputSource is = new InputSource(readerInput);
Document doc = parser.parse(is);