poniedziałek, 12 kwietnia 2010

Proste parsowanie XML w Javie

Co to jest XML?
XML (Extensible Markup Language) czyli niezależny od platformy sposób przechowywania, przekazywania pewnej porcji informacji.
Poniżej bardzo prosty przykład pliku XML zawierającego informacje o osobach (imię, nazwisko, płeć):
<?xml version="1.0"?>
<osoby>
  <osoba plec="mężczyzna">
   <imie>Jan</imie>
   <nazwisko>Kowalski</nazwisko>
  </osoba>
  <osoba plec="kobieta">
   <imie>Anna</imie>
   <nazwisko>Nowak</nazwisko>
  </osoba>
</osoby>


Jak skutecznie przetworzyć XML wykorzystując język Java?
Jest wiele API których można użyć do parsowania XML'i, ja pokaże dwa z nich:


  • DOM
  • SAX
DOM
Pierwszy sposób przetwarzania plików XML to Document Object Model, w skrócie DOM. Prosty API dzięki któremu możemy w łatwy sposób przeszukać plik XML i wyciągnąć z niego interesujące nas informacje. Plik XML jest wczytywane w całości do pamięci i odpowiednimi metodami możemy wyciągać z niego informacje nas interesujące. Metoda ta jest oczywiście niezalecana w przypadku dużych plików XML. Zaletą tego rozwiązania jest to, że w każdej chwili mamy dostęp do całego drzewa dokumentu, czyli do wszystkich elementów, atrybutów, wartości, itd.
Poniżej prosty kawałek kodu który czyta plik XML podany we wstępie artykułu.
package com.blogspot.xml.dom;

import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * 
 * @author Mateusz Korwel
 *
 */
public class SampleDOM {

  public static void main(String argv[]) {

   try {
   File file = new File("myFile.xml");
   DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
   DocumentBuilder db = dbf.newDocumentBuilder();
   Document doc = db.parse(file);
   doc.getDocumentElement().normalize();

    System.out.println("Element główny: "
     + doc.getDocumentElement().getNodeName());
   
   NodeList nodeLst = doc.getElementsByTagName("osoba");

    for (int s = 0; s < nodeLst.getLength(); s++) {

     Node fstNode = nodeLst.item(s);

     if (fstNode.getNodeType() == Node.ELEMENT_NODE) {

      Element fstElmnt = (Element) fstNode;

      NodeList fstNmElmntLst = fstElmnt
       .getElementsByTagName("imie");
     Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
     NodeList fstNm = fstNmElmnt.getChildNodes();

      NodeList lstNmElmntLst = fstElmnt
       .getElementsByTagName("nazwisko");
     Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
     NodeList lstNm = lstNmElmnt.getChildNodes();

      System.out.println("\n***");
     System.out.println("Atrybut plec: "
       + fstElmnt.getAttribute("plec"));
     System.out.println("Element Imię : "
       + ((Node) fstNm.item(0)).getNodeValue());
     System.out.println("Element Nazwisko : "
       + ((Node) lstNm.item(0)).getNodeValue());
    }

    }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}
SAX
Poznaliśmy już bardzo prostą metodę parsowania XML'i łającą pliki do pamięci operacyjnej komputera. Ale co jeśli mamy bardzo duży plik XML którego nie chcieli byśmy w całości wczytywać? W takim wypadku możemy użyć z SAX'a, czyli Simple API for XML. Określamy szereg metod, które wywołują się podczas parsowania pliku XML. Przetwarzanie metodą SAX jest jednokierunkowe.
Poniżej proste dwie klasy korzystające z SAX:
package com.blogspot.xml.sax;

import org.xml.sax.*;
import org.xml.sax.helpers.*;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
public class Handler extends DefaultHandler {

  @Override
 public void startElement(String namespaceURI, String localName,
   String qualifiedName, Attributes att) throws SAXException {
  System.out.println("Znalezione element: " + qualifiedName);
  if (qualifiedName.equals("employee")) {
   System.out.println("Znalezione atrybut: " + att.getValue("name"));
  }
 }

  @Override
 public void characters(char ch[], int start, int length)
   throws SAXException {

   System.out.println("Treść elementu: " + start + " to "
    + (start + length - 1) + ": " + new String(ch, start, length));
 }

}
package com.blogspot.xml.sax;

import javax.xml.parsers.*;
import org.xml.sax.XMLReader;

/**
 * 
 * @author Mateusz Korwel
 * 
 */
public class Sample {

  public static void main(String args[]) throws Exception {

   // Tworzenie parsera
  SAXParserFactory spf = SAXParserFactory.newInstance();
  spf.setNamespaceAware(true);
  SAXParser saxParser = spf.newSAXParser();
  XMLReader parser = saxParser.getXMLReader();

   // Tworzenie klasy Handler
  Handler handler = new Handler();
  parser.setContentHandler(handler);

   // Zaczęćie parsowania dokumentu
  parser.parse("myFile.xml");
 }
}

3 komentarze:

  1. dzięki wielki za jasny przykład!:)

    OdpowiedzUsuń
  2. Mała pomoc, gdyby ktoś miał podobny problem.

    Przy pierwszej metodzie wyskakiwały mi błędy, trzeba było zmienić formatowanie pliku na Unicode.

    Może warto byłoby dodać to do artykułu?

    OdpowiedzUsuń
  3. przykladowe wczytywanie

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.util.Collections;

    import javax.swing.JOptionPane;

    import com.thoughtworks.xstream.XStream;


    public class Main {

    public static void main(String[] args) throws FileNotFoundException {

    XStream xstream = new XStream();
    int x[];
    /*Plane plane1 = new Plane();
    Part engine = new Part("silnik", 1 );
    Part kadlub = new Part("kadlub", 1);
    Part skrzydla = new Part("skrzydla", 2);
    engine.getSkladCzesci().add(new SubPart("srubki", 500));
    engine.getSkladCzesci().add(new SubPart("nakretki", 100));
    kadlub.getSkladCzesci().add(new SubPart("krzesla", 2));
    plane1.getSkladSamolotu().add(engine);
    plane1.getSkladSamolotu().add(kadlub);
    plane1.getSkladSamolotu().add(skrzydla);


    File out = new File("xml.xml");
    PrintWriter pOut = new PrintWriter(out);
    String xml = xstream.toXML(plane1);
    pOut.println(xml);
    for(int i=0; i<plane1.getSkladSamolotu().size();i++){
    xml += xstream.toXML(plane1.getSkladSamolotu().get(i));
    //System.out.println(xml);
    pOut.println(xml);
    }
    pOut.close();
    }*/
    File xmlFile = new File("xml2.xml");

    Plane plane2 = (Plane) xstream.fromXML(new FileInputStream(xmlFile));
    System.out.println(Plane.class.getName());
    //Collections.sort(plane2.getSkladSamolotu()); // opcja po nazwie
    Collections.sort(plane2.getSkladSamolotu(), new ComparatorPart());

    for(int i=0;i<plane2.getSkladSamolotu().size();i++){
    //Collections.sort(plane2.getSkladSamolotu().get(i).getSkladCzesci()); //opcja po nazwie
    Collections.sort(plane2.getSkladSamolotu().get(i).getSkladCzesci(), new CompatorSubPart());
    }


    for(int i=0;i<plane2.getSkladSamolotu().size();i++){
    System.out.println("\t"+ plane2.getSkladSamolotu().get(i).getName() + " " + plane2.getSkladSamolotu().get(i).getQuantity());
    for(int j=0;j<plane2.getSkladSamolotu().get(i).getSkladCzesci().size();j++){
    System.out.println("\t\t"+ plane2.getSkladSamolotu().get(i).getSkladCzesci().get(j).getName() + " " + plane2.getSkladSamolotu().get(i).getSkladCzesci().get(j).getQuantity());
    }
    }
    String wiadomosc="Mozliwe czesci do usuniecia\n";
    for (int i=0;i<plane2.getSkladSamolotu().size();i++){
    wiadomosc+= i + " " + plane2.getSkladSamolotu().get(i).getName()+ " ";
    }
    JOptionPane.showMessageDialog(null, wiadomosc);
    String znak = JOptionPane.showInputDialog("Podaj nr czesci do usuniecia!");
    int wybranaDoUsuniecia = Integer.valueOf(znak);
    plane2.getSkladSamolotu().remove(wybranaDoUsuniecia);
    for(int i=0;i<plane2.getSkladSamolotu().size();i++){
    System.out.println("\t"+ plane2.getSkladSamolotu().get(i).getName() + " " + plane2.getSkladSamolotu().get(i).getQuantity());
    for(int j=0;j<plane2.getSkladSamolotu().get(i).getSkladCzesci().size();j++){
    System.out.println("\t\t"+ plane2.getSkladSamolotu().get(i).getSkladCzesci().get(j).getName() + " " + plane2.getSkladSamolotu().get(i).getSkladCzesci().get(j).getQuantity());
    }
    }

    for(int i=0;i<plane2.getSkladSamolotu().size();i++){
    for(int j=0;j<plane2.getSkladSamolotu().get(i).getSkladCzesci().size();j++){
    System.out.println("Podczesc samolotu " +plane2.getSkladSamolotu().get(i).getSkladCzesci().get(j).getName() + " jest czescia " + plane2.getSkladSamolotu().get(i).getName());
    }
    }

    }

    }

    OdpowiedzUsuń