02. marts 2003 - 19:40Der er
46 kommentarer og 1 løsning
XML - helt fra bunden
Hejsa, Jeg har nogle objekter som jeg indtil videre har gemt ved hjælp af serialized, men da jeg hele tiden ændre i mine klasser holder det ikke helt. Jeg er derfor blevet rådt til at bruge XML. Jeg har kigget rundt på exp efter noget omkring XML men jeg synes ikke rigtig jeg har fået noget ud af det. Jeg er altså med andre ord helt blank omkring XML.
1) Hvad er XML? 2) Ligner databasen en txt fil eller er det bare mig? 3) Kan nogen lave et eksempel på hvordan jeg gemmer objekter af understående klasse i en XML database? 4) Kan noget lave et eksempel hvor på hvordan man henter data ind igen fra punkt 3 til fx en arrayliste? 5) Bør man arbejde direkte i en XML database eller er det fint at hente dataene fx ind i en arrayliste og arbejde med dem derfra? Det er vel svært at smide de objekter, der ligger i en XML-database i en JComboBox hvis ikke de ligger i fx en arraylist?
Jeg håbe på at få gode forklaringer (også på kode eksemplerne) og ligger derfor 100 points i puljen, hvis I ikke mener det er nok finder vi nok ud af noget :o)
Håber nogen har tid og lyst til at belære mig lidt omkring XML. Mvh. Torben
Her er en simpel klasse: import java.io.*; import java.util.*; import java.text.*;//Til DateFormat
public class Firma implements Serializable { private String navn; private String land;
public Firma(String navn,String land) { this.navn=navn; this.land=land; }
public String getNavn(){return navn; } public String getLand(){return land; }
public void setNavn(String navn){this.navn=navn; } public void setLand(String land){this.land=land; }
I dette særtema om aspekter af AI ser vi på skiftet fra sprogmodeller til AI-agenter, og hvordan virksomheder kan navigere i spændet mellem teknologisk hastighed og behovet for menneskelig kontrol.
Til dit specifikke formål er den såkaldte JAXB 1.0 standard faktisk en oplagt mulighed, men fordi den er flunkende ny og ikke supporteret af ret meget endnu, så vil jeg klart anbefale gammeldags XML write & read.
class MySaxParser extends DefaultHandler { private StringBuffer element = new StringBuffer(); ; private ArrayList result; public MySaxParser(ArrayList data) { result = data; } 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; } }
Det ser jo rigtig godt ud Arne :o) Jeg vil lige lege lidt med det i løbet af aftenen. Lige et par spg.: nu skriver du at du vil anbefale gammeldags XML write & read. Er det DOM eller SAX? Går ud fra det er en af dem, da det er dem du er kommet med eksempler på. Kan se på koden du har postet at man sagtens kan gemme arraylister i XML, er det anbefalsværdigt(eller hvordan man nu udtrykker det)? Min kode består selvfølgelig af langt mere end det jeg har postet, og derfor har jeg også objekter, som består af objekter i arraylister. Det er alså heller ikke noget problem at gemme en sådan struktur?
Kan jeg få dig til at forklare, sådan i hverdags sprog, forskellen på dom og sax og hvad du vil foreslå jeg skal bruge? Hvad vil det iøvrigt sige at sax er event baseret?
En DOM parser læser hele XML dokumentet ind i memory i en træ-struktur. Dette træ består af noder og man kan så navnigere op (parent), ned (child), sidelæns (sibling) i det træ. Det er meget fleksibelt. Men kræver altså en del memory. Regn med 2-4 gange størrelsen af XML filen.
I mit eksempel bruger jeg Document getElementsByTagName til at få en liste med alle noderne svarende til element taggene. Og så bruger jeg getFirstChild til at komme ned og hente tekst-værdien (tekst-værdier er en separat node under en element node).
En SAX parser læser en linie ad gangen og kalder nogle metoder i din kode, når den støder på forskellige ting (kaldet events).
I mit eksempel er der MySaxParser klasse hvor: startElement bliver kaldt når man møder start tag endElement bliver kaldt når man møder end tag characters bliver kaldt når man møder tekst mellem start og end tag
Her er et udpluk fra Firma klassen: public Firma(String navn,String land,String adresse,String husNr,String postNr,String by,String tlf,String fax,String noter,String email,String date) { this.navn=navn; this.land=land; this.adresse=adresse; this.husNr=husNr; this.postNr=postNr; this.by=by; this.tlf=tlf; this.fax=fax; this.email=email; this.noter=noter; try {oprettelseDate = df.parse(date);} catch (ParseException e) {} }
public String getNavn(){return this.navn; } public String getLand(){return this.land; } public String getAdresse(){return this.adresse; } public String getHusNr(){return this.husNr; } public String getPostNr(){return this.postNr; } public String getBy(){return this.by; } public String getTlf(){return this.tlf; } public String getFax(){return this.fax; } public String getEmail(){return this.email; } public String getNoter(){return this.noter; } public Date getTid(){return this.oprettelseDate;}; public String getTidspunkt(){return df.format(this.oprettelseDate); }
Arh det er smart med replaceAll :o) Det er jo slet ikke så svært at finde ud XML som jeg troede - men det skyldes nu i højgrad dine forklaringer - Det er helt forrygende!
Er det muligt at lave en form for toString() således at elementnavnet er fx firmanavnet?
UPS der var jeg vist lige lidt for hurtig... kan ikke lige helt gennemskue hvordan jeg læser firma objekterne ind igen :o( Du har vel ikke lige et hint?
Du må sige til hvis du mener der skal flere point på bordet.
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(); } 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; public Element() { nbr = 0; name = null; } public Element(int nbr, String name) { this.nbr = nbr; this.name = name; } public int getNbr() { return nbr; } public String getName() { return name; } public void setNbr(int nbr) { this.nbr = nbr; } public void setName(String name) { this.name = name; } public String toString() { return ("[" + nbr + "," + name + "]"); } }
Det er sådan at jeg har nogle Person objekter. Et Person objekt består af en række variabler og et Firma objekt. Er det muligt fra en xml at henvise til et element i en anden xml database? Der vil jo blive en masse redundant data, hvis der fx er 100 person der er knyttet til samme firma (hvis det er gjort i stil med understående pseudo eks).
Du kunne jo lave en person.xml og en firma.xml og så i person.xml kun have <firma>firmanavn</firma>.
Når du så læser ind processer du firma.xml først og gemmer i en data-struktur. Nå du så læser person.xml og kommer til firmanavn, så gemmer du ikke en String navn, men bruger kun navnet til at slå firma objektet op den anden data-struktur og gemmer den referance.
Når du skriver ud skal du så sikre dig, at du ikke får det samme firma skrevet ud flere gange.
Okay jeg tror vil benytte mig af søgningen. Tænkte bare man kunne flette dem på en måde, så når man åbner person.xml filen med en browser at man så kunne finde info om firmaet personen er tilknyttet. Altså at firma blev et subelement fra var tilknyttet fra en anden fil. Hvis du kan følge min tanke gang? Anyway det er fint med søgning da det er mening af filerne skal bruges som en bagved liggende database og altså ikke noget brugeren skal sidde og hente informationer fra.
* du kan sikkert se at det ikke er noget problem at tilføje et felt - der er bare ikke noget tag i XML og så får feltet default værdien fra constructor * du kan sikkert også se at det ikke er noget problem at fjerne et felt - det pågældende tag bliver bare ignoreret ved indlæsning
Det var jo ligesom hele begrundelsen for den lille øvelse.
Der er imidlertid også andre små positive side-effects: * du kan nemt checke indholdet da filen kan åbnes i Internet Explorer og Notepad * du kan lave en søg og erstat med en editor i filerne, hvis du skulle få lyst til det * du kan læse filerne fra et program skrevet i et andet sprog, hvis du skulle få lyst til det
Hej igen... Jeg har lidt problemer omkring tilbage "den specielle treatment" af < > &
Jeg har ingen problemer med at konvertering når jeg skriver til databasen men når jeg læser med:
public void endElement( String namespaceURI, String localName, String rawName) throws SAXException { if (rawName.equals("element")) { result.add(firmaObj); } if (rawName.equals("navn")) { firmaObj.setNavn(xmlConvertBack(element.toString())); } if (rawName.equals("land")) { firmaObj.setLand(xmlConvertBack(element.toString())); } if (rawName.equals("adresse")) { firmaObj.setAdresse(xmlConvertBack(element.toString())); } if (rawName.equals("husnr")) { firmaObj.setHusNr(xmlConvertBack(element.toString())); } if (rawName.equals("postnr")) { firmaObj.setPostNr(xmlConvertBack(element.toString())); } if (rawName.equals("by")) { firmaObj.setBy(xmlConvertBack(element.toString())); } if (rawName.equals("tlf")) { firmaObj.setTlf(xmlConvertBack(element.toString())); } if (rawName.equals("fax")) { firmaObj.setFax(xmlConvertBack(element.toString())); } if (rawName.equals("email")) { firmaObj.setEmail(xmlConvertBack(element.toString())); } if (rawName.equals("noter")) { firmaObj.setNoter(xmlConvertBack(element.toString())); } if (rawName.equals("oprettet")) { firmaObj.setOprettet(xmlConvertBack(element.toString())); } return; }
public static String xmlConvertBack(String tmp) { String s = tmp.replaceAll("&","&"); tmp = s.replaceAll("<","<"); s = tmp.replaceAll(">",">"); return s; }
Så vil det ikke helt som jeg vil. Hvis man bruger vis() som ligger i firmaklassen udskriver den rigtigt. Men hvis man bruger get metoderne virker det ikke. Hvordan kan det være? min firmaklasse ser således ud:
public String getNavn(){return this.navn;} public String getLand(){return this.land; } public String getAdresse(){return this.adresse; } public String getHusNr(){return this.husNr; } public String getPostNr(){return this.postNr; } public String getBy(){return this.by; } public String getTlf(){return this.tlf; } public String getFax(){return this.fax; } public String getEmail(){return this.email; } public String getNoter(){return this.noter; } public String getOprettet(){return this.oprettet; }
public void setNavn(String navn){this.navn=navn; } public void setLand(String land){this.land=land; } public void setAdresse(String adresse){this.adresse=adresse; } public void setHusNr(String husNr){this.husNr=husNr; } public void setPostNr(String postNr){this.postNr=postNr; } public void setBy(String by){this.by=by; } public void setTlf(String tlf){this.tlf=tlf; } public void setFax(String fax){this.fax=fax; } public void setEmail(String email){this.email=email; } public void setNoter(String noter){this.noter=noter; } public void setOprettet(String oprettet){this.oprettet=oprettet; }
public String toString() { StringBuffer toString = new StringBuffer(); toString.append(navn); return new String(toString); }
Du er efterhånden ved at have hjulpet mig en del udover hvad mit spørgsmål gik ud på. Vil det ikke være rimligt hvis jeg oprretter et nyt spørgsmål med point til dig (fx 50)?
1)(19:16:37) så er det derfor der er det samme resultat der komme hvad enten jeg bruger xmlConvertBack eller ej!
Okey når jeg bruger denne søge metode:
public Firma findFirma(ArrayList firmaListe, String navn) { Firma current = null; for(int i=0; i<firmaListe.size(); i++) { current=(Firma)firmaListe.get(i); System.out.println(current.getNavn()); if(current.getNavn().equals(navn)) current.vis(); //TEST Til udskrivning else System.out.println("ikke fundet"); } return current; } og kalder den med m.findFirma(firmaListe,"3B&O"); (m er et objekt af klassen hvor søgemetoden ligger i) Så finder den ikke noget og der hvor System.out.println(current.getNavn()); bliver kaldt udskriver den firmanavnene 1B&O 2B&O 3B&O 4B&O Mine firmaer hedder 1B&O,2B&O,3B&O,4B&O
Men det total underlige ligger så i at når jeg inde fra den klasse hvor arraylisten firmaListe ligger udskriver firmalisten med :
Firma ccurrent = null; for(int i=0; i<firmaListe.size(); i++) { ccurrent=(Firma)firmaListe.get(i); ccurrent.vis(); System.out.println(ccurrent.getNavn()); } Så står navnene rigtigt nok! Jeg fatter ikke en bjælde af det :o(
Den eneste ide jeg kan komme på er om du når du kalder findFirma allerede har lavet replaceAll("&", "&") på alle navne så de er klar til udskrivning.
Altså at findFirma bliver kaldt senere end den sidste udskrivning.
Jeg kalder således fra klassen hvori min main metode ligger:
public static void main(String[] arguments) { List kPListe = new ArrayList(); ArrayList firmaListe = new ArrayList(); List omsListe = new ArrayList(); List soegRes = new ArrayList();
Metoder m = new Metoder(); FirmaXml firmDb = new FirmaXml();
Date date; DateFormat df = new SimpleDateFormat("dd-MMM-yyyy HH:mm");
Min XML klasse kan du se her: import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList;
public static String xmlConvert(String tmp) { String s = tmp.replaceAll("&", "&"); tmp = s.replaceAll("<", "<"); s = tmp.replaceAll(">", ">"); return s; } }
class MySaxParser2 extends DefaultHandler { private StringBuffer element = new StringBuffer(); private Firma firmaObj; 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")) { firmaObj = new Firma(); } if (rawName.equals("navn")) { element = new StringBuffer(); } if (rawName.equals("land")) { element = new StringBuffer(); } if (rawName.equals("adresse")) { element = new StringBuffer(); } if (rawName.equals("husnr")) { element = new StringBuffer(); } if (rawName.equals("postnr")) { element = new StringBuffer(); } if (rawName.equals("by")) { element = new StringBuffer(); } if (rawName.equals("tlf")) { element = new StringBuffer(); } if (rawName.equals("fax")) { element = new StringBuffer(); } if (rawName.equals("email")) { element = new StringBuffer(); } if (rawName.equals("noter")) { element = new StringBuffer(); } if (rawName.equals("oprettet")) { element = new StringBuffer(); } return; }
public void endElement( String namespaceURI, String localName, String rawName) throws SAXException { if (rawName.equals("element")) { result.add(firmaObj); } if (rawName.equals("navn")) { firmaObj.setNavn(element.toString()); } if (rawName.equals("land")) { firmaObj.setLand(element.toString()); } if (rawName.equals("adresse")) { firmaObj.setAdresse(element.toString()); } if (rawName.equals("husnr")) { firmaObj.setHusNr(element.toString()); } if (rawName.equals("postnr")) { firmaObj.setPostNr(element.toString()); } if (rawName.equals("by")) { firmaObj.setBy(element.toString()); } if (rawName.equals("tlf")) { firmaObj.setTlf(element.toString()); } if (rawName.equals("fax")) { firmaObj.setFax(element.toString()); } if (rawName.equals("email")) { firmaObj.setEmail(element.toString()); } if (rawName.equals("noter")) { firmaObj.setNoter(element.toString()); } if (rawName.equals("oprettet")) { firmaObj.setOprettet(element.toString()); } return; }
public static String xmlConvertBack(String tmp) { String s = tmp.replaceAll("&","&"); tmp = s.replaceAll("<","<"); s = tmp.replaceAll(">",">"); return s; }
}
Jeg gør bruger altså kun xmlConvert metoden når jeg skriver de enkelte linier i filen og gør slet ikke brug af xmlConvertBack metoden. Da det er udfra getMetoder jeg skriver linierne i filen kan jeg jo ikke ændre indholdet af det den aflæser. Jeg er helt lost :o(
Til oplysning for interesserede, så sendte jeg arne denne mail:
Det må du virkelig undskylde :o(
Det er selvfølgelig xmlConvert i getMetoderne der udgør min fejl. Jeg er virkelig ked af at jeg har spildt så meget af din tid. Og hvordan xmlConvert metoden er kommet derind i Firma.java, det er mig en gåde. Jeg vil tro at det er i et af mine utallige forsøg på at få løst problematikken at jeg har blandet xmlConvert og Firma.java sammen. Det er virkeligt pinligt det her, ikke mindst fordi jeg ikke havde fordi du selvfølgelig har fuldstændig ret hvad angår at den Firma.java jeg mailede og den jeg postede 03/03-2003 19:04:36 ikke stemmer overens. Jeg vil lige prøve at gennemgå det jeg postede 19.04.36 og se hvad det der er, som er sket.
Jeg undskylder mange gange. Mvh Torben
Det der var sket var at jeg havde en Firma.java der så ud som følge: import java.io.*; import java.util.*; import java.text.*;//Til DateFormat
public String xmlConvert(String tmp) { String s = tmp.replaceAll("&", "&"); tmp = s.replaceAll("<", "<"); s = tmp.replaceAll(">", ">"); return s; } public String xmlConvertBack(String tmp) { String s = tmp.replaceAll("&","&"); tmp = s.replaceAll("<","<"); s = tmp.replaceAll(">",">"); return s; }
public String getNavn(){return xmlConvertBack(this.navn);} public String getLand(){return xmlConvertBack(this.land); } public String getAdresse(){return xmlConvertBack(this.adresse); } public String getHusNr(){return xmlConvertBack(this.husNr); } public String getPostNr(){return xmlConvertBack(this.postNr); } public String getBy(){return xmlConvertBack(this.by); } public String getTlf(){return xmlConvertBack(this.tlf); } public String getFax(){return xmlConvertBack(this.fax); } public String getEmail(){return xmlConvertBack(this.email); } public String getNoter(){return xmlConvertBack(this.noter); } public String getOprettet(){return xmlConvertBack(this.oprettet); }
public void setNavn(String navn){this.navn=navn; this.navn=xmlConvertBack(this.navn); } public void setLand(String land){this.land=land; } public void setAdresse(String adresse){this.adresse=adresse; } public void setHusNr(String husNr){this.husNr=husNr; } public void setPostNr(String postNr){this.postNr=postNr; } public void setBy(String by){this.by=by; } public void setTlf(String tlf){this.tlf=tlf; } public void setFax(String fax){this.fax=fax; } public void setEmail(String email){this.email=email; } public void setNoter(String noter){this.noter=noter; } public void setOprettet(String oprettet){this.oprettet=oprettet; }
public String toString() { StringBuffer toString = new StringBuffer(); toString.append(navn); return new String(toString); }
Metoderne xmlConvert og xmlConvertBack skal selvfølgelig ikke ligge i denne klasse og SLET IKKE bruges i getMetoderne. Deri ligger fejlen.
Det er virkeligt pinligt at jeg har postet en udgave af koden her på exp og selv arbejdet i en anden :o(
Point kan jo nærmest ikke gøre det her godt igen.
Det er virkelig noget jeg må lære noget af det her, jeg beklager dybt at det er gået ud over dig arne og at du har brugt så meget tid på at hjælpe mig.
19:04:36 skriver jeg "Hvis man bruger vis() som ligger i firmaklassen udskriver den rigtigt. Men hvis man bruger get metoderne virker det ikke. Hvordan kan det være?" Herefter smed jeg så min firmaklasse ind. Men det har været en modificeret udgave. Det fremgår jo meget tydligt af det jeg skrev, at det er getMetoderne, der er noget galt med.
Jeg fik heldigvis en mail fra arne hvor i han gjorde mig opmærksom på at jeg havde arbejdet med forskellige udgaver af Firma.java.
Desuden fik jeg en mail hvori han skrev at jeg ikke skulle ærge mig over fejlen men blot glæde mig over at jeg nu kan komme videre... så det vil jeg gøre...
Synes godt om
Ny brugerNybegynder
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.