Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/388.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用dom4j从流中读取单个XML文档_Java_Xml_Stream_Sax_Dom4j - Fatal编程技术网

Java 使用dom4j从流中读取单个XML文档

Java 使用dom4j从流中读取单个XML文档,java,xml,stream,sax,dom4j,Java,Xml,Stream,Sax,Dom4j,我试图使用dom4j一次从流中读取一个XML文档,对其进行处理,然后继续处理流中的下一个文档。不幸的是,dom4j的SAXReader(在封面下使用JAXP)一直在读取并阻塞以下文档元素 有没有办法让SAXReader在找到文档元素的结尾后停止读取流?有没有更好的方法来实现这一点?最有可能的情况是,您不希望在同一个流中同时有多个文档。我不认为SAXReader足够聪明,当它到达第一个文档的末尾时会停止。为什么必须在同一个流中有多个文档,就像这样?我认为您必须添加一个适配器,它可以包装流,并在看到

我试图使用dom4j一次从流中读取一个XML文档,对其进行处理,然后继续处理流中的下一个文档。不幸的是,dom4j的SAXReader(在封面下使用JAXP)一直在读取并阻塞以下文档元素


有没有办法让SAXReader在找到文档元素的结尾后停止读取流?有没有更好的方法来实现这一点?

最有可能的情况是,您不希望在同一个流中同时有多个文档。我不认为SAXReader足够聪明,当它到达第一个文档的末尾时会停止。为什么必须在同一个流中有多个文档,就像这样?

我认为您必须添加一个适配器,它可以包装流,并在看到下一个文档的开头时让它返回文件的结尾。据我所知,编写的解析器将一直运行到文件结束或出现错误。。。看到另一个
肯定是一个错误。

我能够使用一些内部JAXP类将其用于一些体操:

  • 创建自定义扫描程序,它是XMLNSDocumentScannerImpl的子类
    • 在自定义扫描程序中创建一个自定义驱动程序,它是XMLNSDocumentScannerImpl.driver的一个实现,当它看到一个声明或一个元素时,会返回END_文档。从fElementScanner.getCurrentEntity()获取ScannedEntity。如果实体具有回推读取器,则将实体缓冲区中剩余的未读字符回推到读取器上
    • 在构造函数中,使用此自定义驱动程序的实例替换fTrailingMiscDriver
  • 创建一个自定义配置类,xincludeawarseparserconfiguration的子类,该类在其构造函数中用此自定义扫描程序的实例替换库存文档\u扫描程序
  • 将此自定义配置类的实例安装为“com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration”属性,以便在dom4j的SAXReader类尝试创建JAXP XMLReader时对其进行实例化
  • 将读取器传递给dom4j的SAXReader.read()方法时,提供一个缓冲区大小大大大于一个字符默认值的PushbackReader。至少8192应该足以支持JAXP的Apache2副本中XMLEntityManager的默认缓冲区大小

这并不是最干净的解决方案,因为它涉及到内部JAXP类的子类化,但它确实起作用。

假设您首先负责将文档放入流中,那么以某种方式对文档进行划分应该很容易。例如:

// 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); } //任何对XML字符无效的值都可以。 静态最终字符DOC_终止符=4; BOOL addDocumentToStream(BufferedWriter streamOut,char xmlData[]) { streamOut.write(xmlData); streamOut.write(文件终止符); } 然后,在从流中读取数据时,将其读入数组,直到遇到DOC_终止符为止

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(); } char*GetNextDocument(BufferedReader streamIn) { StringBuffer=新的StringBuffer(); 整数字符; while(true) { character=streamIn.read(); if(字符==文档终止符) 打破 buffer.append(字符); } 返回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); } ... ... XMLReader=XMLReaderFactory.createXMLReader(); ... while(true) { char xmlDoc=getNextDocument(streamIn); 如果(xmlDoc.length==0) 打破 InputSource saxInputSource=新的InputSource(新的CharArrayReader(xmlDoc)); parse(saxInputSource); } ...
请注意,循环在获取长度为0的文档时终止。这意味着您应该在getNextDocument()中的最后一个文档之后添加第二个DOC_终止符,您需要在getNextDocument()中添加一些东西来检测流的结尾。

我以前已经这样做了,用我自己创建的另一个具有非常简单解析功能的读取器包装基本读取器。假设您知道文档的结束标记,包装器只解析匹配项,例如“”。当它检测到返回EOF时。通过解析出第一个开始标记并在匹配的结束标记上返回EOF,可以使包装器具有自适应性。我发现实际上没有必要检测结束标记的级别,因为我没有在文档本身中使用文档标记,所以可以保证第一次出现结束标记时文档就结束了

我记得,其中一个技巧是让包装器块close(),因为DOM读取器会关闭输入源

因此,给定读取器输入,您的代码可能如下所示:

SubdocReader sdr=new SubdocReader(input);
while(!sdr.eof()) {
    sdr.next();
    // read doc here using DOM
    // then process document
    }
input.close();
如果遇到eof,则eof()方法返回true。next()方法标记读取器停止为read()返回-1

希望这能为您指明一个有用的方向

--
奇异果。

我会将输入流读入一个内部缓冲区。根据预期的总流大小,我要么读取整个流,然后解析它,要么检测一个xml和下一个xml之间的边界(查找
处理一个xml流和处理多个xml流之间唯一的真正区别是缓冲区和拆分逻辑。

xml规范将xml文档描述为序言、文档元素、尾随注释、处理指令和空白。没有任何东西表明像文件或ream只能保存一个文档。为什么每个流不能有多个文档?这似乎是绕过解析器限制的一种手段。但问题是,确定何时插入此EOF标记需要解析XML。“假设您负责将文档放入流中…”遗憾的是,这样的问题