Domanda

Sto cercando il metodo migliore per analizzare vari documenti XML utilizzando un'applicazione Java.Attualmente lo sto facendo con SAX e un gestore di contenuti personalizzato e funziona alla grande: scattante e stabile.

Ho deciso di esplorare l'opzione di far sì che lo stesso programma, che attualmente riceve un documento XML in un unico formato, riceva due formati di documento XML aggiuntivi, con varie modifiche agli elementi XML.Speravo semplicemente di sostituire ContentHandler con uno appropriato basato sul primo "startElement" nel documento...ma, uh-duh, ContentHandler è impostato e Poi il documento è analizzato!

... constructor ...
{
SAXParserFactory spf = SAXParserFactory.newInstance();

try {
SAXParser sp = spf.newSAXParser();
parser = sp.getXMLReader();
parser.setErrorHandler(new MyErrorHandler());
} catch (Exception e) {} 

... parse StringBuffer ...
try {
parser.setContentHandler(pP);
parser.parse(new InputSource(new StringReader(xml.toString())));
return true;
} catch (IOException e) {
    e.printStackTrace();
} catch (SAXException e) {
    e.printStackTrace();
}
...

Quindi, non sembra che io possa farlo nel modo in cui inizialmente pensavo di poterlo fare.

Detto questo, sto guardando la cosa in modo del tutto sbagliato?Qual è il metodo migliore per analizzare più documenti XML discreti con lo stesso codice di gestione XML? Ho provato a chiedere in un post più generale prima...ma penso di essere stato troppo vago.Per motivi di velocità ed efficienza non ho mai veramente guardato il DOM perché questi documenti XML sono abbastanza grandi e il sistema ne riceve circa 1200 ogni pochi minuti.È solo un invio di informazioni a senso unico

Per rendere questa domanda troppo lunga e aumentare la mia confusione;di seguito è riportato un modello di alcuni vari documenti XML che vorrei avere un singolo SAX, StAX o ??il parser gestisce in modo pulito.

prodotti.xml:

<products>
<product>
  <id>1</id>
  <name>Foo</name>
<product>
  <id>2</id>
  <name>bar</name>
</product>
</products>

negozi.xml:

<stores>
<store>
  <id>1</id>
  <name>S1A</name>
  <location>CA</location>
</store>
<store>
  <id>2</id>
  <name>A1S</name>
  <location>NY</location>
</store>
</stores>

manager.xml:

<managers>
<manager>
  <id>1</id>
  <name>Fen</name>
  <store>1</store>
</manager>
<manager>
  <id>2</id>
  <name>Diz</name>
  <store>2</store>
</manager>
</managers>
È stato utile?

Soluzione

A quanto ho capito, il problema è che non sai quale formato è il documento prima dell'analisi.Potresti usare un modello delegato.Presumo che tu non stia convalidando rispetto a DTD/XSD/eccetera e che sia OK che DefaultHandler abbia state.

public class DelegatingHandler extends DefaultHandler {

    private Map<String, DefaultHandler> saxHandlers;
    private DefaultHandler delegate = null;

    public DelegatingHandler(Map<String, DefaultHandler> delegates) {
        saxHandlers = delegates;
    }

    @Override
    public void startElement(String uri, String localName, String name,
            Attributes attributes) throws SAXException {
       if(delegate == null) {
           delegate = saxHandlers.get(name);
       }
       delegate.startElement(uri, localName, name, attributes);
    }

    @Override
    public void endElement(String uri, String localName, String name)
            throws SAXException {
        delegate.endElement(uri, localName, name);
    }

//etcetera...

Altri suggerimenti

Hai fatto bene a spiegare cosa vuoi fare ma non perché.Esistono diversi framework XML che semplificano il marshalling e l'annullamento del marshalling di oggetti Java in/da XML.

Il più semplice è Digestore dei beni comuni che in genere utilizzo per analizzare i file di configurazione.Ma se vuoi avere a che fare con oggetti Java, allora dovresti guardare Castore, JiBX, JAXB, XMLBeans, XStream, o qualcosa di simile.Castor o JiBX sono i miei due preferiti.

Ho provato SAXParser una volta, ma una volta ho trovato XStream Non ci sono mai tornato.Con XStream puoi creare oggetti Java e convertirli in XML.Inviateli e utilizza XStream per ricreare l'oggetto.Molto facile da usare, veloce e crea XML pulito.

In ogni caso devi sapere quali dati riceverai dal file XML.Puoi inviarli in diversi modi per sapere quale parser utilizzare.Oppure avere un oggetto dati che può contenere tutto ma è popolata solo una struttura (prodotto/negozio/manager).Forse qualcosa del tipo:

public class DataStructure {

    List<ProductStructure> products;

    List<StoreStructure> stors;

    List<ManagerStructure> managers;

    ...

    public int getProductCount() {
        return products.lenght();
    }

    ...
}

E con XStream converti in XML, invia e quindi ricrea l'oggetto.Allora fai quello che vuoi con esso.

Consulta la documentazione per XMLReader.setContentHandler(), dice:

Le applicazioni possono registrare un gestore nuovo o diverso nel corso di un'analisi e il parser SAX deve iniziare immediatamente a utilizzare il nuovo gestore.

Pertanto, dovresti essere in grado di creare un file SelectorContentHandler che consuma eventi fino al primo startElement evento, in base a ciò cambia il ContentHandler sul lettore XML e passa il primo evento dell'elemento start al nuovo gestore del contenuto.Devi solo superare il XMLReader al SelectorContentHandler nel costruttore.Se avete bisogno Tutto gli eventi da passare al gestore del contenuto specifico del vocabolario, SelectorContentHandler deve memorizzare nella cache gli eventi e poi trasmetterli, ma nella maggior parte dei casi ciò non è necessario.

Nota a margine: l'ho usato ultimamente XOM in quasi tutti i miei progetti per gestire XML ja finora le prestazioni non sono state il problema.

JAXB.L'architettura Java per l'associazione XML.Fondamentalmente crei un xsd che definisce il tuo layout XML (credo che potresti anche usare un DTD).Quindi passi l'XSD al compilatore JAXB e il compilatore crea classi Java per eseguire il marshalling e annullare il marshalling del tuo documento XML in oggetti Java.È davvero semplice.

A proposito, ci sono opzioni da riga di comando su jaxb per specificare il nome del pacchetto in cui desideri inserire le classi risultanti, ecc.

Se desideri una gestione più dinamica, l'approccio Stax probabilmente funzionerebbe meglio di Sax.È comunque un livello piuttosto basso;se vuoi un approccio più semplice, XStream e JAXB sono i miei preferiti.Ma richiedono oggetti piuttosto rigidi su cui mappare.

Concordo con StaxMan, che, cosa abbastanza interessante, vuole che tu usi Stax.È un parser basato su pull invece del push che stai attualmente utilizzando.Ciò richiederebbe tuttavia alcune modifiche significative al codice.

:-)

Sì, ho qualche pregiudizio nei confronti della Stax.Ma come ho detto, spesso l'associazione dei dati è più conveniente della soluzione di streaming.Ma se desideri lo streaming e non hai bisogno di pipeline (di più fasi di filtraggio), Stax è più semplice di SAX.

Un'altra cosa:per quanto buono sia XOM (rispetto alle alternative), spesso Tree Model non è la cosa giusta da usare se non si ha a che fare con xml "incentrato sui documenti" (~= pagine xhtml, docbook, documenti open office).Per lo scambio di dati, i file di configurazione, ecc., l'associazione dei dati è più conveniente, più efficiente, più naturale.Basta dire no ai modelli ad albero come DOM per questi casi d'uso.Quindi, JAXB, XStream, JibX sono buoni.Oppure, per un gusto più acquisito, digester, castor, xmlbeans.

VTD-XML è nota per essere la migliore tecnologia di elaborazione XML per l'elaborazione XML pesante.Vedi il riferimento qui sotto per una prova

http://sdiwc.us/digitlib/journal_paper.php?paper=00000582.pdf

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top