Pergunta

Eu estou tentando ler um único documento XML de fluxo em um tempo usando dom4j, processá-lo, em seguida, avançar para o próximo documento no fluxo. Infelizmente, SAXReader do dom4j (usando JAXP debaixo das cobertas) mantém a leitura e engasga com o seguinte elemento do documento.

Existe uma maneira de obter o SAXReader parar de ler o fluxo uma vez que encontra o final do elemento do documento? Existe uma maneira melhor de fazer isso?

Foi útil?

Solução

Eu era capaz de chegar a este trabalho com alguma ginástica usando algumas classes JAXP interna:

  • Criar um scanner de costume, uma subclasse de XMLNSDocumentScannerImpl
    • Criar um driver personalizado, uma implementação de XMLNSDocumentScannerImpl.Driver, dentro do scanner personalizado que retorna END_DOCUMENT quando vê uma declaração ou um elemento. Obter o ScannedEntity de fElementScanner.getCurrentEntity (). Se a entidade tem uma PushbackReader, empurrar para trás os restantes caracteres não lidos no buffer de entidade para o leitor.
    • No construtor, substitui o fTrailingMiscDriver com uma instância desse driver personalizado.
  • Crie uma classe de configuração personalizada, uma subclasse de XIncludeAwareParserConfiguration, que substitui o DOCUMENT_SCANNER estoque com uma instância de este scanner personalizada em seu construtor.
  • Instale uma instância desta classe de configuração personalizada como a propriedade "com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration" por isso vai ser instanciado quando tenta classe SAXReader de DOM4J para criar uma JAXP XMLReader.
  • Ao passar um leitor com o método de dom4j SAXReader.read (), forneça um PushbackReader com um tamanho de buffer consideravelmente maior do que o padrão de um personagem. Pelo menos 8192 deve ser suficiente para suportar o tamanho do buffer padrão do XMLEntityManager dentro cópia do JAXP de Apache2.

Esta não é a solução mais limpa, uma vez que envolve subclassificação aulas JAXP internos, mas ela não funciona.

Outras dicas

Provavelmente, você não quer ter mais de um documento na mesma corrente, ao mesmo tempo. Eu não acho que o SAXReader é inteligente o suficiente para parar quando se chega ao fim do primeiro documento. Por que é necessário ter vários documentos na mesma corrente como este?

Eu acho que você tem que adicionar um adaptador, algo para quebrar o fluxo e ter esse efeito coisa retorno de arquivo quando ele vê o início do próximo documento. Tanto quanto eu sei, os analisadores como está escrito, vai até o fim do arquivo ou um erro ... e vendo outra <?xml version="1.0"?> certamente seria um erro.

Supondo que você é responsável pela colocação de documentos na corrente, em primeiro lugar deve ser fácil de delimitar os documentos de alguma forma. Por exemplo:

// 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);
}

Em seguida, quando a leitura do fluxo de ler em uma matriz até DOC_TERMINATOR é encontrado.

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();
}

Desde 4 é um valor de caractere inválido você não vai encontrar, excepto quando você adicioná-lo explicitamente. Assim, o que lhe permite dividir os documentos. Agora é só embrulhar a matriz de char resuling para entrada em SAX e seu bom para ir.

...
  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);
  }
...

Note que os termina loop quando ele recebe um documento de comprimento 0. Isso significa que você deve ou adicionar um segundo DOC_TERMINATOR após o último documento de você precisa adicionar algo para detectar o fim do fluxo em getNextDocument ().

Eu tenho feito isso antes por wrappering o leitor base com um outro leitor de minha própria criação que tinha capacidade de análise muito simples. Supondo que você sabe a marca de fechamento para o documento, o invólucro simplesmente analisa para um jogo, por exemplo, para "". Quando ele detecta que ele retorna EOF. O invólucro pode ser feito adaptável ao analisar a primeira marca de abertura e retornando EOF na tag de fechamento correspondente. Achei que não era necessário para detectar realmente o nível para a marca de fechamento desde nenhum documento que eu tinha usado o tag documento dentro de si, por isso foi garantido que a primeira ocorrência da tag de fechamento terminou o documento.

Se bem me lembro, um dos truques era ter o bloco invólucro close (), uma vez que o leitor DOM fecha a fonte de entrada.

Assim, dada entrada Reader, seu código pode olhar como:

SubdocReader sdr=new SubdocReader(input);
while(!sdr.eof()) {
    sdr.next();
    // read doc here using DOM
    // then process document
    }
input.close();

O método EOF () retorna true se EOF é encontrado. Os próximos () bandeiras método o leitor a parar de retornar -1 para read ().

Esperemos que este lhe pontos em uma direção útil.

- Kiwi.

lia o fluxo de entrada para uma memória intermédia interna. Dependendo do tamanho total do fluxo esperado GOSTARIA ou ler todo o fluxo e, em seguida, analisá-lo ou detectar a fronteira entre um xml ea próxima (procure

A única diferença real, em seguida, entre a manipulação de um riacho com um xml e um riacho com vários xmls é a lógica de buffer e dividida.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top