2016-05-21 24 views
0

shorten Version meiner XML-Datei wie folgt aussehen:XML Parsing-Abschnitt für Abschnitt in SAX oder StAX

<?xml version="1.0" encoding="UTF-8"?> 
<MzIdentML id="MS-GF+"> 
    <SequenceCollection xmlns="http://psidev.info/psi/pi/mzIdentML/1.1"> 
     <DBSequence length="146" id="DBSeq143"> 
      <cvParam cvRef="PSI-MS" accession="MS:1001088"></cvParam> 
     </DBSequence> 
     <Peptide id="Pep7"> 
      <PeptideSequence>MFLSFPTTK</PeptideSequence> 
      <Modification location="1" monoisotopicMassDelta="15.994915"> 
       <cvParam cvRef="UNIMOD" accession="UNIMOD:35" name="Oxidation"></cvParam> 
      </Modification> 
     </Peptide> 
     <PeptideEvidence dBSequence_ref="DBSeq143" id="PepEv_160_1_18"></PeptideEvidence> 
     <PeptideEvidence dBSequence_ref="DBSeq143" id="PepEv_275_8_133"></PeptideEvidence> 
    </SequenceCollection> 
</MzIdentML> 

Ich möchte DBSequence, Peptide und PeptideEvidence Details separately.but Attribute von Eltern und Kindern (oder verschachtelt erhalten children..if gibt es) .In anderen Worten, ich möchte alle attribues als Schlüssel-Wert-Paare in jedem Abschnitt I unten dargestellt:

---------------------------------------------------------------------- 
<DBSequence length="146" id="DBSeq143"> 
    <cvParam cvRef="PSI-MS" accession="MS:1001088"></cvParam> 
</DBSequence> 
---------------------------------------------------------------------- 
<Peptide id="Pep7"> 
    <PeptideSequence>MFLSFPTTK</PeptideSequence> 
    <Modification location="1" monoisotopicMassDelta="15.994915"> 
     <cvParam cvRef="UNIMOD" accession="UNIMOD:35" name="Oxidation"></cvParam> 
    </Modification> 
</Peptide> 
---------------------------------------------------------------------- 
<PeptideEvidence dBSequence_ref="DBSeq143" id="PepEv_160_1_18"></PeptideEvidence> 
<PeptideEvidence dBSequence_ref="DBSeq143" id="PepEv_275_8_133"></PeptideEvidence> 
---------------------------------------------------------------------- 

Zum Beispiel, wenn wir <DBSequence> Abschnitt betrachten:

<DBSequence length="146" id="DBSeq143"> 
    <cvParam cvRef="PSI-MS" accession="MS:1001088"></cvParam> 
</DBSequence> 

sollte ausgegeben werden als:

DBSequence=>length=146;id=DBSeq143;cvRef=PSI-MS;accession=MS:1001088; 

Dies ist der Code, den ich in SAX schrieb:

package lucene.parse; 

import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.parsers.SAXParser; 
import javax.xml.parsers.SAXParserFactory; 
import org.xml.sax.Attributes; 
import org.xml.sax.SAXException; 
import org.xml.sax.helpers.DefaultHandler; 

public class MzIdentMLSAXParser extends DefaultHandler { 

    private boolean isDBsequence = false; 

    String DBSequenceSection; 
    String PeptideEvidenceDocument; 

    public static void main(String[] argv) throws SAXException, ParserConfigurationException, IOException { 
     MzIdentMLSAXParser ps = new MzIdentMLSAXParser("file_path_here/sample.xml"); 
    } 

    public MzIdentMLSAXParser(String dataDir) throws FileNotFoundException, SAXException, ParserConfigurationException, IOException { 

     FileInputStream fis = new FileInputStream(dataDir); 
     SAXParserFactory spf = SAXParserFactory.newInstance(); 
     SAXParser parser = spf.newSAXParser(); 
     parser.parse(fis, this); 
    } 

    @Override 
    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { 

     if (qName.equals("DBSequence")) { 
      // each time we found a new DBSequence, we re-initialize DBSequenceSection 
      DBSequenceSection = ""; 

      // get attributes of DBSequence 
      for (int i = 0; i < atts.getLength(); i++) { 
       DBSequenceSection += atts.getQName(i) + "=" + atts.getValue(i) + ";"; 
      } 
      isDBsequence = true; 
     } else if ((qName.equals("cvParam")) && (isDBsequence)) { 
      // get attributes of cvParam which are belongs to DBSequence 
      // there can be cvParam that are not belongs to DBSequence. 
      for (int i = 0; i < atts.getLength(); i++) { 
       DBSequenceSection += atts.getQName(i) + "=" + atts.getValue(i) + ";"; 
      } 
     } else if (qName.equals("PeptideEvidence")) { 
      // each time we found a new PeptideEvidence, we re-initialize docuDBSequenceSectionment 
      PeptideEvidenceDocument = ""; 

      for (int i = 0; i < atts.getLength(); i++) { 
       PeptideEvidenceDocument += atts.getQName(i) + "=" + atts.getValue(i) + ";"; 
      } 
     } 
    } 

    @Override 
    public void endElement(String uri, String localName, String qName) throws SAXException { 
     if (qName.equals("DBSequence")) { 
      System.out.println(qName +"=>"+DBSequenceSection); 
      isDBsequence = false; 
     } else if (qName.equals("PeptideEvidence")) { 
      System.out.println(qName +"=>"+PeptideEvidenceDocument); 
     } 
    } 
} 

Gibt es eine einfache Möglichkeit, dies zu tun? weil ich so viele Tags mit verschachtelten Knoten habe. Herausforderung ist hier <cvParam> erscheint nicht nur in <DBSequence> Tag, aber in anderen Tags wie <Modification> usw. Ich versuchte mit StAX auch. aber konnte es nicht schaffen.

+1

Warum es SAX oder Stax sein muss, warum nicht können Sie XPath oder XQuery verwenden? –

Antwort

0

Hier ist ein Arbeitsbeispiel für die Verwendung von StAX. StAX zeichnet sich durch die Analyse bekannter XML-Strukturen aus, kann aber auch für das dynamische Parsen verwendet werden.

Dieser Code beruht auf Wissen, z.B. zu wissen, dass wir den Inhalt von DBSequence, Peptide und PeptideEvidence wollen, und dass PeptideSequence Textinhalt hat, während die anderen nicht.

Die Methoden verwenden Rekursion, um der Struktur des XML zu folgen.

public static void main(String[] args) throws Exception { 
    String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
       "<MzIdentML id=\"MS-GF+\">\n" + 
       " <SequenceCollection xmlns=\"http://psidev.info/psi/pi/mzIdentML/1.1\">\n" + 
       "  <DBSequence length=\"146\" id=\"DBSeq143\">\n" + 
       "   <cvParam cvRef=\"PSI-MS\" accession=\"MS:1001088\"></cvParam>\n" + 
       "  </DBSequence>\n" + 
       "  <Peptide id=\"Pep7\">\n" + 
       "   <PeptideSequence>MFLSFPTTK</PeptideSequence>\n" + 
       "   <Modification location=\"1\" monoisotopicMassDelta=\"15.994915\">\n" + 
       "    <cvParam cvRef=\"UNIMOD\" accession=\"UNIMOD:35\" name=\"Oxidation\"></cvParam>\n" + 
       "   </Modification>\n" + 
       "  </Peptide>\n" + 
       "  <PeptideEvidence dBSequence_ref=\"DBSeq143\" id=\"PepEv_160_1_18\"></PeptideEvidence>\n" + 
       "  <PeptideEvidence dBSequence_ref=\"DBSeq143\" id=\"PepEv_275_8_133\"></PeptideEvidence>\n" + 
       " </SequenceCollection>\n" + 
       "</MzIdentML>"; 
    XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(new StringReader(xml)); 
    try { 
     reader.nextTag(); 
     search(reader); 
    } finally { 
     reader.close(); 
    } 
} 
private static void search(XMLStreamReader reader) throws XMLStreamException { 
    // reader must be on START_ELEMENT upon entry, and will be on matching END_ELEMENT on return 
    assert reader.getEventType() == XMLStreamConstants.START_ELEMENT; 
    while (reader.nextTag() == XMLStreamConstants.START_ELEMENT) { 
     String name = reader.getLocalName(); 
     switch (name) { 
      case "DBSequence": 
      case "Peptide": 
      case "PeptideEvidence": { 
       Map<String, String> props = new LinkedHashMap<>(); 
       collectProps(reader, props); 
       System.out.println(name + ": " + props); 
       break; } 
      default: 
       search(reader); 
     } 
    } 
} 
private static void collectProps(XMLStreamReader reader, Map<String, String> props) throws XMLStreamException { 
    // reader must be on START_ELEMENT upon entry, and will be on matching END_ELEMENT on return 
    assert reader.getEventType() == XMLStreamConstants.START_ELEMENT; 
    for (int i = 0; i < reader.getAttributeCount(); i++) 
     props.put(reader.getAttributeLocalName(i), reader.getAttributeValue(i)); 
    String name = reader.getLocalName(); 
    switch (name) { 
     case "PeptideSequence": 
      props.put(name, reader.getElementText()); 
      break; 
     default: 
      while (reader.nextTag() == XMLStreamConstants.START_ELEMENT) 
       collectProps(reader, props); 
    } 
} 

OUTPUT

DBSequence: {length=146, id=DBSeq143, cvRef=PSI-MS, accession=MS:1001088} 
Peptide: {id=Pep7, PeptideSequence=MFLSFPTTK, location=1, monoisotopicMassDelta=15.994915, cvRef=UNIMOD, accession=UNIMOD:35, name=Oxidation} 
PeptideEvidence: {dBSequence_ref=DBSeq143, id=PepEv_160_1_18} 
PeptideEvidence: {dBSequence_ref=DBSeq143, id=PepEv_275_8_133} 
+0

Intelligente Lösung! Ich habe es von SAX einfach durch die Einführung einer Flagge namens isCollecting zu arbeiten. Wenn ich meine interessanten Tags (DBSequence, Peptide, etc) in der START-Methode gefunden habe, schalte ich das Flag ein und beginne mit dem Kopieren von Attributen. Als ich meine interessanten Tags in der END-Methode gelesen habe, habe ich abgeschaltet. welches ist besser? – user2125889

+0

@ user2125889 Welches auch immer Sie am besten mögen. Für einfaches dynamisches Parsing ist SAX in Ordnung. Für strukturierteres Parsen ist StAX besser, da Sie eine Methode zum Parsen jedes Elements schreiben können, indem Sie den Aufruf-Stack verwenden, um der XML-Struktur zu folgen. Dadurch können Elemente mit demselben Namen an verschiedenen Positionen leicht als unterschiedlich identifiziert werden. Mit SAX wird eine solche Wiederverwendung von Elementnamen schwierig zu handhaben. – Andreas