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!!
Annonceindlæg fra SoftwareOne
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; } }
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.
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 + "]"); } }
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..
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.
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).
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..
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.
Nej, det har du da faktisk ret i.. Jeg skulle forstå det.. Hvilke andre metoder kan man implmentere fra det interface DefaultHandler?
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!!
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.
Kurser inden for grundlæggende programmering