dom4j를 사용하여 스트림에서 단일 XML 문서 읽기
문제
나는 dom4j를 사용하여 한 번에 스트림에서 단일 XML 문서를 읽고, 그것을 처리 한 다음 스트림의 다음 문서로 진행하려고합니다. 불행히도, DOM4J의 색소폰서 (표지 아래에서 JAXP 사용)는 다음 문서 요소를 계속 읽고 질식시킵니다.
문서 요소의 끝을 찾으면 SaxReader가 스트림 읽기를 중단하는 방법이 있습니까? 이것을 달성하는 더 좋은 방법이 있습니까?
해결책
나는 이것을 일부 내부 JAXP 수업을 사용하여 일부 체조와 협력 할 수있었습니다.
- xmlnsdocumentscannerimpl의 서브 클래스 인 사용자 정의 스캐너를 만듭니다
- 명확한 드라이버, xmlnsdocumentscannerimpl.driver의 구현, 명확한 스캐너 내부에서 선언이나 요소가 표시 될 때 END_DOCUMENT를 반환합니다. FelementsCanner.getCurrentity ()에서 스캔을 받으십시오. 엔티티에 푸시 백 리더가있는 경우 엔티티 버퍼의 나머지 읽지 않은 문자를 리더로 밀어 넣으십시오.
- 생성자에서 ftrailingmiscdriver를이 사용자 정의 드라이버의 인스턴스로 대체하십시오.
- xincludeawareparserconfiguration의 서브 클래스 인 사용자 정의 구성 클래스를 만듭니다. STOCK_SCANNER를 생성자 의이 사용자 정의 스캐너 인스턴스로 대체합니다.
- 이 사용자 정의 구성 클래스의 인스턴스를 "com.sun.org.apache.xerces.internal.xni.parser.xmlparserconfiguration"속성으로 설치하여 Dom4J의 SaxReader 클래스가 JAXP XMLREDER를 만들려고 할 때 인스턴스화됩니다.
- 독자를 Dom4J의 SaxReader.Read () 메소드로 전달할 때는 1 차 차이터 기본값보다 훨씬 큰 버퍼 크기의 푸시 백 리더를 제공하십시오. JAXP의 APACHE2 사본 내부의 XmlentityManager의 기본 버퍼 크기를 지원하기에 최소 8192가 충분해야합니다.
내부 jaxp 클래스를 서브 클래스하는 것이 포함되어 있기 때문에 가장 깨끗한 솔루션은 아니지만 작동합니다.
다른 팁
아마도 같은 스트림에 동시에 둘 이상의 문서를 갖고 싶지 않을 것입니다. SaxReader가 첫 번째 문서의 끝에 도착할 때 멈출만큼 똑똑하다고 생각하지 않습니다. 이와 같은 스트림에 여러 문서가 필요한 이유는 무엇입니까?
스트림을 감싸고 다음 문서의 시작을 볼 때 파일의 끝을 반환 할 수있는 어댑터를 추가해야한다고 생각합니다. 내가 아는 한, 쓰여진 파서는 파일 끝이나 오류가 발생할 때까지 진행됩니다 ... <?xml version="1.0"?>
확실히 오류 일 것입니다.
처음에 문서를 스트림에 배치 할 책임이 있다고 가정하면 문서를 어떤 방식으로 쉽게 구분할 수 있어야합니다. 예를 들어:
// Any value that is invalid for an XML character will do. static final char DOC_TERMINATOR=4; BOOL addDocumentToStream(BufferedWriter streamOut, char xmlData[]) { streamOut.write(xmlData); streamOut.write(DOC_TERMINATOR); }
그런 다음 스트림에서 읽을 때 Doc_terminator가 발생할 때까지 배열로 읽습니다.
char *getNextDocuument(BufferedReader streamIn) { StringBuffer buffer = new StringBuffer(); int character; while (true) { character = streamIn.read(); if (character == DOC_TERMINATOR) break; buffer.append(character); } return buffer.toString().toCharArray(); }
4는 유효하지 않은 문자 값이므로 명시 적으로 추가하는 곳을 제외하고는 발생하지 않습니다. 따라서 문서를 분할 할 수 있습니다. 이제 SAX에 입력 할 수있는 결과 숯 배열을 감싸십시오.
... XMLReader xmlReader = XMLReaderFactory.createXMLReader(); ... while (true) { char xmlDoc = getNextDocument(streamIn); if (xmlDoc.length == 0) break; InputSource saxInputSource = new InputSource(new CharArrayReader(xmlDoc)); xmlReader.parse(saxInputSource); } ...
루프는 길이 0의 문서를 얻을 때 종료됩니다. 이는 GetNextDocument ()에서 스트림의 끝을 감지하기 위해 무언가를 추가 해야하는 마지막 문서를 추가 한 후 두 번째 doc_terminator를 추가해야 함을 의미합니다.
나는 매우 간단한 구문 분석 기능을 가진 내 자신의 창조물을 다른 독자로 기본 독자에게 래퍼함으로써 이것을하기 전에 이것을 해냈습니다. 문서의 닫는 태그를 알고 있다고 가정하면 래퍼는 단순히 일치를 위해 구문 분석합니다.u003C/MyDocument> ". EOF를 반환하는 것을 감지 할 때. 첫 번째 오프닝 태그를 구문 분석하고 일치하는 마감 태그에서 EOF를 반환하여 래퍼를 적응시킬 수 있습니다. 문서가 없기 때문에 마감 태그의 레벨을 실제로 감지 할 필요가 없다는 것을 알았습니다. 문서 태그 자체를 사용 했으므로 결산 태그의 첫 번째 발생이 문서를 종료했음을 보장했습니다.
내가 기억 하듯이, 트릭 중 하나는 DOM 리더가 입력 소스를 닫으므로 래퍼 블록을 Close ()하도록하는 것이 었습니다.
따라서 독자 입력이 주어지면 코드가 있습니다 ~할 것 같다 모양 :
SubdocReader sdr=new SubdocReader(input);
while(!sdr.eof()) {
sdr.next();
// read doc here using DOM
// then process document
}
input.close();
eof가 발생하면 eof () 메소드가 true를 반환합니다. 다음 () 메소드는 독자가 read ()에 대해 -1 리턴을 중지하도록 표시합니다.
바라건대 이것은 유용한 방향으로 당신을 가리 킵니다.
-- 키위.
입력 스트림을 내부 버퍼로 읽었습니다. 예상되는 총 스트림 크기에 따라 전체 스트림을 읽은 다음 하나의 XML과 다음 사이의 경계를 감지합니다 (찾아보십시오.
그런 다음 하나의 XML로 스트림을 처리하고 여러 XML이있는 스트림의 유일한 차이점은 버퍼 및 분할 로직입니다.