Etwas komplexere xml-Datei mit XML-Serializer schreiben - wie Wiederholungen kontrollieren?

  • Antworten:6
  • OffenNicht stickyBentwortet
  • Forum-Beiträge: 675

17.10.2016 21:08:58 via Website

Hallo,
meine Daten aus meiner App (die Heizungssteuerung) möchte ich in einer XML-Datei speichern, unter Verwendung des XMLSerializers.
Nach ein wenig Herumprobieren und unter Zuhilfenahme eines anderen XML-Editors habe ich folgende Struktur der XML-Datei festgelegt:

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<Network>
<Cubes>
<Cube CubeName="null" CubeRF="0cd86d" CubeSN="EQ0837268" />
</Cubes>
<Raeume>
<Raum RaumName="Wohnzimmer" RaumID="1" RaumRF="b715a" />
<Raum RaumName="Schlafzimmer" RaumID="2" RaumRF="b7a40" />
<Raum RaumName="Bᅢᄐro" RaumID="3" RaumRF="b7128" />
<Raum RaumName="Badezimmer" RaumID="4" RaumRF="b6e0b" />
<Raum RaumName="Gᅢᄂstezimmer" RaumID="5" RaumRF="b602f" />
</Raeume>
<Devices>
<Thermostat DevName="Schlafen" DevRF="b7a40" DevType="1" DevSer="KEQ0446747" DevRaumID="2" />
<Thermostat DevName="Bᅢᄐro" DevRF="b7128" DevType="1" DevSer="KEQ0449549" DevRaumID="3" />
<Thermostat DevName="Bad" DevRF="b6e0b" DevType="1" DevSer="KEQ0446180" DevRaumID="4" />
<Thermostat DevName="Wohnzimmer" DevRF="b715a" DevType="1" DevSer="KEQ0449570" DevRaumID="1" />
<Thermostat DevName="Gᅢᄂstezimmer" DevRF="b602f" DevType="1" DevSer="KEQ0450567" DevRaumID="5" />
</Devices>
</Network>

Dabei sind die Anzahl von Cube's, Räumen und Devices (wobei hier nur ein Thermostat als Device vorhanden ist) nicht festgelegt.

Meine Routine zum Schreiben der XML-Datei hat bisher folgenden Inhalt:

xmlser.startDocument("UTF-8",true);
xmlser.startTag("","Network");
// Anhand des jeweils ausgelesenen DeviceTypeSelectors wird über das dazugehörige XML-Tag
// entschieden. Da die Daten vom Cube sortiert ausgegeben werden, bleiben sie auch
// in dieser Reihenfolge
xmlser.startTag("","Cube");
for (int devCount = 0; devCount < CubeNetz.size(); devCount++) {
    cDevice4 elvMaxDevice = CubeNetz.get(devCount);
                switch (elvMaxDevice.getDeviceTypeSelector()) {
                    case 0 :  {     // Cube
                            String aktCubeName = String.valueOf(elvMaxDevice.CubeCubeName);
                            xmlser.attribute("","CubeName",aktCubeName);
                            xmlser.attribute("","CubeRF",String.valueOf(elvMaxDevice.getCubeCubeRFAddress()));
                      xmlser.attribute("","CubeSN",String.valueOf(elvMaxDevice.getCubeCubeSerialNumber()));
                           xmlser.endTag("","Cube");
                           break;
                    }
                    case 1 : {      // Raum
                            xmlser.startTag("","Raum");
                            String aktRaumName = String.valueOf(elvMaxDevice.getRaumName());
                            xmlser.attribute("","RaumName",aktRaumName);
                            xmlser.attribute("","RaumID",String.valueOf(elvMaxDevice.getRaumID()));
                            xmlser.attribute("","RaumRF",String.valueOf(elvMaxDevice.getRaumRFAdresse()));
                            xmlser.endTag("","Raum");
                        break;
                    }
                    case 2 : {      // Thermostat an Heizung
                        xmlser.endTag("","Raeume");
                        xmlser.startTag("","Devices");
                        xmlser.startTag("","Thermostat");
                            String aktThermostatName = String.valueOf(elvMaxDevice.getDeviceName());
                            xmlser.attribute("","DevName",String.valueOf(elvMaxDevice.getDeviceName()));
                                  xmlser.attribute("","DevRF",String.valueOf(elvMaxDevice.getDeviceRFAddress()));
                                  xmlser.attribute("","DevType",String.valueOf(elvMaxDevice.getDeviceType()));
                   xmlser.attribute("","DevSer",String.valueOf(elvMaxDevice.getDeviceSeriennummer()));
                            xmlser.attribute("","DevRaumID",String.valueOf(elvMaxDevice.DeviceRoomID));
                            xmlser.endTag("","Thermostat");
                           break;
                    }
                }
            }
            xmlser.endTag("","Devices");
            xmlser.endTag("","Network");
            xmlser.endDocument();

Leider kann ich damit die oben gezeigte Datei nicht erzeugen - ich seh' nur nicht, wie ich die Routine so ergänzen muss.
Erklärung noch: App-intern werden alle Teile (Cubes, Räume und Devices)m in einer ArrayList gespeichert - daher die For-Schleife. Die Unterscheidung erfolgt über eine Property "DeviceSelector".

Wichtig evtl.: Ich möchte die XML-Datei hinterher mit dem XmlPullParser einlesen können.
Vielleicht ist jemand so lieb und "stupst" mich auf den richrtigen Weg?
Danke und Gruss
G.-U.M.

N'y pas n'y
tu car tu
mal tu mal

  • Forum-Beiträge: 2.214

17.10.2016 21:36:30 via Website

Hallo Gerd,

vielleicht ist das der Schubser für dich

XmlSerializer xmlSerializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
File file = new File(h_Setupfile);
file.createNewFile();
FileOutputStream fileos = new FileOutputStream(file);
xmlSerializer.setOutput(writer);
xmlSerializer.startDocument("UTF-8", true);
....
.....
....
xmlSerializer.endDocument();
String dataWrite = writer.toString();
fileos.write(dataWrite.getBytes());
fileos.close();

— geändert am 17.10.2016 21:39:30

Liebe Grüße - Stefan
[ App - Entwicklung ]

  • Forum-Beiträge: 675

18.10.2016 06:06:34 via Website

swa00

Hallo Gerd,

vielleicht ist das der Schubser für dich

XmlSerializer xmlSerializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
File file = new File(h_Setupfile);
file.createNewFile();
FileOutputStream fileos = new FileOutputStream(file);
xmlSerializer.setOutput(writer);
xmlSerializer.startDocument("UTF-8", true);
....
.....
....
xmlSerializer.endDocument();
String dataWrite = writer.toString();
fileos.write(dataWrite.getBytes());
fileos.close();

Danke, das ist schon mal gut. Damit kriege ich das eigentliche Schreiben hin.
Gruss
G.-U.M.

N'y pas n'y
tu car tu
mal tu mal

  • Forum-Beiträge: 675

18.10.2016 06:11:54 via Website

Pascal P.

Genau zum schreiben so, aber solltest du deine Daten in einer sauberen Objekt Struktur haben

Das sollte ich. Über die Struktur habe ich länger nachgedacht.

Pascal P.

kannst du diese auch mit einem Befehl in XML serialisieren:
http://simple.sourceforge.net/home.php

Das sieht sehr schön aus. Und für Android scheint es das auch zu geben. Gibts da, abgesehen von den "Feedback"-Einträgen auch noch weitere Erfahrungen? Und, sehe ich das richtig, dass ich die erzeugte XML-Datei auch gleich damit wieder einlesen kann? Dann würde ich mir den Umweg über den xmlPullParser sparen.

Danke und Gruss
G.-U.M.

— geändert am 18.10.2016 10:17:00

N'y pas n'y
tu car tu
mal tu mal

  • Forum-Beiträge: 675

18.10.2016 21:25:48 via Website

So,

nach ein wenig Experimentieren (und der Feststellung, dass das hier

Pascal P.

Genau zum schreiben so, aber solltest du deine Daten in einer sauberen Objekt Struktur haben kannst du diese auch mit einem Befehl in XML serialisieren:
http://simple.sourceforge.net/home.php

aufgrund der Kenntnis und Anwendung von Annotations noch ein wenig meinen Wissenhorizont übersteigt, hab ich einen Weg gefunden. Der Kern sieht so aus:

 try {
            xmlser.setOutput(writer);
            xmlser.startDocument("UTF-8",true);
            xmlser.startTag("","Network");

            Boolean schreibeCube = false;
            Boolean schreibeRaum = false;
            Boolean schreibeDevices = false;
            for (int devCount = 0; devCount < CubeNetz.size(); devCount++) {
                cDevice4 elvMaxDevice = CubeNetz.get(devCount);
                switch (elvMaxDevice.getDeviceTypeSelector()) {
                    case 0 :  {     // Cube
                            if (!schreibeCube) {
                                schreibeCube = true;
                                xmlser.startTag("","Cubes");
                            }
                            xmlser.startTag("","Cube");
                            String aktCubeName = String.valueOf(elvMaxDevice.CubeCubeName);
                            xmlser.attribute("","CubeName",aktCubeName);
                            xmlser.attribute("","CubeRF",String.valueOf(elvMaxDevice.getCubeCubeRFAddress()));
                            xmlser.attribute("","CubeSN",String.valueOf(elvMaxDevice.getCubeCubeSerialNumber()));
                            xmlser.endTag("","Cube");
                            break;
                    }
                    case 1 : {      // Raum
                            if (!schreibeRaum) {
                                xmlser.endTag("","Cubes");  // es wird davon ausgegangen, dass
                                                                                  // immer erst ein Cube geschrieben wird
                                schreibeRaum = true;
                                schreibeCube = false;
                                xmlser.startTag("","Raeume");
                            }
                            xmlser.startTag("","Raum");
                            String aktRaumName = String.valueOf(elvMaxDevice.getRaumName());
                            xmlser.attribute("","RaumName",aktRaumName);
                            xmlser.attribute("","RaumID",String.valueOf(elvMaxDevice.getRaumID()));
                            xmlser.attribute("","RaumRF",String.valueOf(elvMaxDevice.getRaumRFAdresse()));
                            xmlser.endTag("","Raum");
                            break;
                    }
                    case 2 : {      // Thermostat an Heizung
                            if (!schreibeDevices) {
                                xmlser.endTag("","Raeume"); 
                                schreibeDevices = true;
                                schreibeRaum = false;
                                xmlser.startTag("","Devices");
                            }
                            xmlser.startTag("","Thermostat");
                            String aktThermostatName = String.valueOf(elvMaxDevice.getDeviceName());
                            xmlser.attribute("","DevName",String.valueOf(elvMaxDevice.getDeviceName()));
                            xmlser.attribute("","DevRF",String.valueOf(elvMaxDevice.getDeviceRFAddress()));
                            xmlser.attribute("","DevType",String.valueOf(elvMaxDevice.getDeviceType()));
                            xmlser.attribute("","DevSer",String.valueOf(elvMaxDevice.getDeviceSeriennummer()));
                            xmlser.attribute("","DevRaumID",String.valueOf(elvMaxDevice.DeviceRoomID));
                            xmlser.endTag("","Thermostat");
                            break;
                    }
                }
            }
            xmlser.endTag("","Devices");
            xmlser.endTag("","Network");
            xmlser.endDocument();
        } catch (IOException e) {
            e.printStackTrace();
        }

Das eigentliche Schreiben funktioniert auch.

Danke dafür!

Jetzt steh ich nur vor dem Problem, dass der xmlPullParser diese erzeugte Datei nicht einlesen kann. Ich habe mich beim Aufbau der Lese-Routine so eng wie möglich an das Beispiel aus der Android Developper-Dokumentation gehalten.

Allerdings erkennen diese 3 Zeilen (kopiert aus der Dokumentation) kein Start-Tag in der XML-Datei :'(

int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_DOCUMENT) {

Wo ist das Brett, dass ich zum Verstehen und Funktionieren wegnehmen muss?

Danke und Gruss
G.-U.M.

PS: Hier noch die relevante XML-Datei (so wie sie der XmlSerializer "ausspuckt"):

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><Network><Cubes><Cube CubeName="null" CubeRF="0cd86d" CubeSN="EQ0837268" /></Cubes><Raeume><Raum RaumName="Wohnzimmer" RaumID="1" RaumRF="b715a" /><Raum RaumName="Schlafzimmer" RaumID="2" RaumRF="b7a40" /><Raum RaumName="Bᅢᄐro" RaumID="3" RaumRF="b7128" /><Raum RaumName="Badezimmer" RaumID="4" RaumRF="b6e0b" /><Raum RaumName="Gᅢᄂstezimmer" RaumID="5" RaumRF="b602f" /></Raeume><Devices><Thermostat DevName="Schlafen" DevRF="b7a40" DevType="1" DevSer="KEQ0446747" DevRaumID="2" /><Thermostat DevName="Bᅢᄐro" DevRF="b7128" DevType="1" DevSer="KEQ0449549" DevRaumID="3" /><Thermostat DevName="Bad" DevRF="b6e0b" DevType="1" DevSer="KEQ0446180" DevRaumID="4" /><Thermostat DevName="Wohnzimmer" DevRF="b715a" DevType="1" DevSer="KEQ0449570" DevRaumID="1" /><Thermostat DevName="Gᅢᄂstezimmer" DevRF="b602f" DevType="1" DevSer="KEQ0450567" DevRaumID="5" /></Devices></Network>

PPS: Zum Ausprobieren hier die komplette Lese-Routine

public void ladeXmlDatenInCubeNetz(String xmlDatenDateiName) {
        // Zuerst die Datei in einen String laden
        String xmlDatenString = null;
        try {

getActivity().openFileInput(Environment.getExternalStorageDirectory().getPath() + "/ccdat.xml");
FileInputStream xmlDateiInput = new FileInputStream(new File(Environment.getExternalStorageDirectory().getPath()+"/ccdat.xml"));
InputStreamReader xmlInputStreamReader = new InputStreamReader(xmlDateiInput);
char[] EingabePuffer = new char[xmlDateiInput.available()];
xmlInputStreamReader.read(EingabePuffer);
xmlDatenString = new String(EingabePuffer);
// Jetzt den String über den XmlPullParser zerlegen...
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();

        factory.setNamespaceAware(true);
        XmlPullParser xpp = factory.newPullParser();
        xpp.setInput(new StringReader(xmlDatenString));

        int eventType = xpp.getEventType();

        cDevice4 cd = new cDevice4();
        CubeNetz.clear();   // Es gelten nur noch die Einträge aus der XML-Datei
        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG) {     // ein neuer Eintrag in der XML
                if (xpp.getName().equals("Cube")) {
                    cd.setDeviceTypeSelector(0);    // damit ist bekannt, dass es sich um einen
                    // Cube handeln muss
                    // Jetzt die anderen Werte auslesen und temporär speichern
                    cd.setCubeCubeName( xpp.getAttributeValue("", "CubeName"));
                    cd.setCubeCubeRFAddress(xpp.getAttributeValue("", "CubeRF"));
                    cd.setCubeCubeSerialNumber( xpp.getAttributeValue("", "CubeSN"));
                } else if (xpp.getName().equals("Raum")) {
                    cd.setDeviceTypeSelector(1);;       // Es handelt sich nun um einen Raum
                    cd.setRaumName( xpp.getAttributeValue("","RaumName"));
                    String rid = xpp.getAttributeValue("","RaumID");
                    cd.setRaumID(Byte.valueOf(rid));
                    String aktRaumRF    = xpp.getAttributeValue("","RaumRF");
                } else if (xpp.getName().equals("Thermostat")) {
                    cd.setDeviceTypeSelector(2);
                    cd.setDeviceName(xpp.getAttributeValue("","DevName"));
                    cd.setDeviceRFAddress(xpp.getAttributeValue("","DevRF"));
                    cd.setDeviceSeriennummer(xpp.getAttributeValue("","DevSer"));
                    cd.setDeviceRoomID(Integer.valueOf(xpp.getAttributeValue("","DevRaumID")));
                }
            }

            else if (eventType == XmlPullParser.END_TAG) {
                CubeNetz.add(cd);
            }
            xmlInputStreamReader.close();
            xmlDateiInput.close();
        }
        try {
            xpp.next();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

N'y pas n'y
tu car tu
mal tu mal

  • Forum-Beiträge: 675

20.10.2016 20:38:51 via Website

Gelöst!
Ich verstehe zwar den Unterschied zu meiner eigentlichen Version nicht, aber wenn ich die folgende Version fürs Lesen verwende, geht's.

public void ladeXmlDatenInCubeNetz(String xmlDatenDateiName) {
        // Zuerst die Datei in einen String laden
        String xmlDatenString = null;
        CubeNetz.clear();   // Es gelten nur noch die Einträge aus der XML-Datei
        try {
            //FileInputStream xmlDateiInput = getActivity().openFileInput(Environment.getExternalStorageDirectory().getPath() + "/ccdat.xml");
            FileInputStream xmlDateiInput =  new FileInputStream(new File(Environment.getExternalStorageDirectory().getPath()+"/ccdat.xml"));
            //FileInputStream xmlDateiInput = getActivity().openFileInput(new File(Environment.getExternalStorageDirectory().getName()+"/ccdat.xml").toString());
            InputStreamReader xmlInputStreamReader = new InputStreamReader(xmlDateiInput,"UTF-8");
            char[] EingabePuffer = new char[xmlDateiInput.available()];
            xmlInputStreamReader.read(EingabePuffer);
            xmlDatenString = new String(EingabePuffer);
        // Jetzt den String über den XmlPullParser zerlegen...
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(true);
        XmlPullParser xpp = factory.newPullParser();
        xpp.setInput(new StringReader(xmlDatenString));
        int eventType = xpp.getEventType();
        cDevice4 cd = new cDevice4();

        while (eventType != XmlPullParser.END_DOCUMENT) {
            switch (eventType) {
                case XmlPullParser.START_TAG :
                    if (xpp.getName().equals("Cube")) {
                        cd.setDeviceTypeSelector(0);    // damit ist bekannt, dass es sich um einen
                        // Cube handeln muss
                        // Jetzt die anderen Werte auslesen und temporär speichern
                        cd.setCubeCubeName(xpp.getAttributeValue("", "CubeName"));
                        cd.setCubeCubeRFAddress(xpp.getAttributeValue("", "CubeRF"));
                        cd.setCubeCubeSerialNumber(xpp.getAttributeValue("", "CubeSN"));
                        CubeNetz.add(cd);
                    } else if (xpp.getName().equals("Raum")) {
                        cd.setDeviceTypeSelector(1);
                        // Es handelt sich nun um einen Raum
                        cd.setRaumName(xpp.getAttributeValue("", "RaumName"));
                        String rid = xpp.getAttributeValue("", "RaumID");
                        cd.setRaumID(Byte.valueOf(rid));
                        String aktRaumRF = xpp.getAttributeValue("", "RaumRF");
                        CubeNetz.add(cd);
                    } else if (xpp.getName().equals("Thermostat")) {
                        cd.setDeviceTypeSelector(2);
                        cd.setDeviceName(xpp.getAttributeValue("", "DevName"));
                        cd.setDeviceRFAddress(xpp.getAttributeValue("", "DevRF"));
                        cd.setDeviceSeriennummer(xpp.getAttributeValue("", "DevSer"));
                        cd.setDeviceRoomID(Integer.valueOf(xpp.getAttributeValue("", "DevRaumID")));
                        CubeNetz.add(cd);
                    }
                    break;
            }
            eventType = xpp.next();
        }
        xmlInputStreamReader.close();
        xmlDateiInput.close();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Jetzt muss ich zwar die nächsten Ungereimtheiten lösen, aber die liegen noch an meinem Verständnis über Zusammenhänge im Hinblick auf den App-Lifecycle und damit verbunden der Zustand und Inhalt von div. Variablen.

Auf jeden Fall erstmal Danke hier.
Gruss
G.-U.M.

N'y pas n'y
tu car tu
mal tu mal