Avatar billede bris Nybegynder
16. juni 2003 - 13:23 Der er 10 kommentarer og
1 løsning

Java, xml og xerces

Hejsa..

Jeg har et xml-dokument, som jeg gerne vil løbe igennem, uden at tage ret meget ind i memory. Der må derfor ikke benyttes nogen DOM typer..
Jeg har installeret xerces, men har ikke rigtig styr over hvordan man gennemløber dokumentet?
I må gerne give mig en anden løsning en xerces, men det er vigtigt, at der er en lille tutorial - eller bare noget kode, som lige får mig i gang!!
Avatar billede arne_v Ekspert
16. juni 2003 - 13:41 #1
Lidt memory => brug SAX !

Eksempel:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import javax.xml.parsers.FactoryConfigurationError;
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.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class SaxTest {
  private final static String XML_FILE = "C:\\saxtest.xml";
  public static void main(String[] args) {
      ArrayList data1 = new ArrayList();
      data1.add("a");
      data1.add("bb");
      data1.add("ccc");
      data1.add("dddd");
      writeXml(data1, XML_FILE);
      ArrayList data2 = readXml(XML_FILE);
      System.out.println(data2);
  }
  private static void writeXml(ArrayList data, String filename) {
      try {
        PrintWriter pw = new PrintWriter(new FileOutputStream(filename));
        pw.println("<?xml version='1.0' standalone='yes'?>");
        pw.println("<arraylist>");
        for (int i = 0; i < data.size(); i++) {
            pw.println(
              "  <element>" + (String) data.get(i) + "</element>");
        }
        pw.println("</arraylist>");
        pw.close();
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      }
  }
  private static ArrayList readXml(String filename) {
      ArrayList result = new ArrayList();
      try {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
        XMLReader xr = sp.getXMLReader();
        xr.setContentHandler(new MySaxParser(result));
        xr.parse(filename);
      } catch (FactoryConfigurationError e) {
        e.printStackTrace();
      } catch (ParserConfigurationException e) {
        e.printStackTrace();
      } catch (SAXException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
      return result;
  }
}

class MySaxParser extends DefaultHandler {
  private StringBuffer element = new StringBuffer();
  private ArrayList result;
  public MySaxParser(ArrayList result) {
      this.result = result;
  }
  public void characters(char buf[], int offset, int len)
      throws SAXException {
      element.append(new String(buf, offset, len));
      return;
  }
  public void startElement(
      String namespaceURI,
      String localName,
      String rawName,
      Attributes atts)
      throws SAXException {
      if (rawName.equals("element")) {
        element = new StringBuffer();
      }
      return;
  }
  public void endElement(
      String namespaceURI,
      String localName,
      String rawName)
      throws SAXException {
      if (rawName.equals("element")) {
        result.add(element.toString());
      }
      return;
  }
}
Avatar billede arne_v Ekspert
16. juni 2003 - 13:43 #2
Ovenstående bruger kun standard JAXP. Jeg har testet det med Xerces, men
det bør også virke med Crimson eller enhver anden JAXP compliant
parser - uden ændringer.
Avatar billede arne_v Ekspert
16. juni 2003 - 13:44 #3
Og et lidt mere avanceret eksempel:

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import javax.xml.parsers.FactoryConfigurationError;
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.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class SaxTest3 {
    private final static String XML_FILE = "C:\\saxtest.xml";
    public static void main(String[] args) {
        ArrayList data1 = new ArrayList();
        data1.add(new Element(1, "a", true));
        data1.add(new Element(2, "bb", false));
        data1.add(new Element(3, "ccc", true));
        writeXml(data1, XML_FILE);
        ArrayList data2 = readXml(XML_FILE);
        System.out.println(data2);
    }
    private static void writeXml(ArrayList data, String filename) {
        try {
            PrintWriter pw = new PrintWriter(new FileOutputStream(filename));
            pw.println("<?xml version='1.0' standalone='yes'?>");
            pw.println("<arraylist>");
            for (int i = 0; i < data.size(); i++) {
                Element e = (Element)data.get(i);
                pw.println("  <element include='" + e.isInclude() + "'>");
                pw.println("      <nbr>" + e.getNbr() + "</nbr>");
                pw.println("      <name>" + e.getName() + "</name>");
                pw.println("  </element>");
            }
            pw.println("</arraylist>");
            pw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    private static ArrayList readXml(String filename) {
        ArrayList result = new ArrayList();
        try {
            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser sp = spf.newSAXParser();
            XMLReader xr = sp.getXMLReader();
            xr.setContentHandler(new MySaxParser2(result));
            xr.parse(filename);
        } catch (FactoryConfigurationError e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}
class MySaxParser2 extends DefaultHandler {
    private StringBuffer element = new StringBuffer();
    private Element elmobj;
    private ArrayList result;
    public MySaxParser2(ArrayList result) {
        this.result = result;
    }
    public void characters(char buf[], int offset, int len)
        throws SAXException {
        element.append(new String(buf, offset, len));
        return;
    }
    public void startElement(
        String namespaceURI,
        String localName,
        String rawName,
        Attributes atts)
        throws SAXException {
        if (rawName.equals("element")) {
            elmobj = new Element();
            elmobj.setInclude(Boolean.valueOf(atts.getValue("include")).booleanValue());
        }
        if (rawName.equals("nbr")) {
            element = new StringBuffer();
        }
        if (rawName.equals("name")) {
            element = new StringBuffer();
        }
        return;
    }
    public void endElement(
        String namespaceURI,
        String localName,
        String rawName)
        throws SAXException {
        if (rawName.equals("element")) {
            result.add(elmobj);
        }
        if (rawName.equals("nbr")) {
            elmobj.setNbr(Integer.parseInt(element.toString()));
        }
        if (rawName.equals("name")) {
            elmobj.setName(element.toString());
        }
        return;
    }
}
class Element {
    private int nbr;
    private String name;
    private boolean include;
    public Element() {
        nbr = 0;
        name = null;
        include = false;
    }
    public Element(int nbr, String name, boolean include) {
        this.nbr = nbr;
        this.name = name;
        this.include = include;
    }
    public int getNbr() {
        return nbr;
    }
    public String getName() {
        return name;
    }
    public boolean isInclude() {
        return include;
    }
    public void setNbr(int nbr) {
        this.nbr = nbr;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setInclude(boolean b) {
        include = b;
    }
    public String toString() {
        return ("[" + nbr + "," + name + "," + include + "]");
    }
}
Avatar billede bris Nybegynder
16. juni 2003 - 13:46 #4
Nu er det sådan, at jeg har en monster stor xml-fil, og jeg kunne godt tænke mig at lave kontrol on the fly.. Altså hver gang den f.eks når til et element, så vil jeg gerne checke om nogle ting osv.. XML-filen er alt for stor til, at en ArrayList kan styre den..
Avatar billede arne_v Ekspert
16. juni 2003 - 13:51 #5
Nu ved jeg ikke hvad du skal gøre med den XML.

Du kan skrive hvert element ud til en fil i stedetfor at gemme
den i en ArrayList eller du kan bare tælle noget op for hvert element.

Du kan putte præcis den logik du ønsker ind i startElement og
endElement.

Det der er specielt ved SAX er at den læser en linie af gangen
og processer den.

Der er ikke nogle skjulte data strukturer kun dem man selv laver.
Avatar billede arne_v Ekspert
16. juni 2003 - 13:53 #6
Hvis du kun skal lave noget validering af data uden at gemme, så
kan du f.eks. bare lave objektet og lave en isValid metode i den
(og så lade være med at gemme i en ArrayList).
Avatar billede bris Nybegynder
16. juni 2003 - 13:54 #7
Hvad lige præcis gør startelement() og endElement() ?

Jeg har f.eks data fra en database (noget simplificeret:)

<Kunde>
  <navn>per</navn>
  <adr>jj</adr>
</Kunde>

----osv. nedad----

Så er jeg jo nødt til at checke for hver linie, om jeg er kommer til en ny 'række' kunde..
Avatar billede arne_v Ekspert
16. juni 2003 - 13:59 #8
startElement bliver kaldt hver gang SAX finder starten på et tag
altså ved <Kunde>, <navn> og <adr>.

endElement bliver kaldt hver gang SAX finder slutningen på et tag
altså ved  </Kunde>, </navn> og </adr>.

Og ja du skal selv holde styr på det.

Men ovenstående kode skulle gerne vise, at så svært er det ikke.
Avatar billede bris Nybegynder
16. juni 2003 - 14:07 #9
Nej, det har du da faktisk ret i.. Jeg skulle forstå det.. Hvilke andre metoder kan man implmentere fra det interface DefaultHandler?
Avatar billede bris Nybegynder
16. juni 2003 - 14:12 #10
Der er jo garanteret ikke andre, ellers ville det jo ikke virke, hvis man ikke implmenterede dem alle..

Tak for hjælpen.. Du styrer vist det her XML!!
Avatar billede arne_v Ekspert
16. juni 2003 - 14:14 #11
DefaultHandler er faktisk en klasse og ikke et interface, så det har nogle
metoder.

Men hvis du har Xerces doc (eller J2SE 1.4 doc) så kan du bare slå klassen op.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester