• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

XML mit Unterelementen

.holger

Borowitzky
Registriert
13.09.04
Beiträge
8.970
Moin moin,

ich quäle mich mal wieder mit dem XMLParser.
Ich habe eine XML Datei, die ich einlese… das klappt auch alles. Jedoch habe ich jetzt Unterelemente, die die gleichen Namen haben, wie die Oberelemente - man kann sich das wie Ordner vorstellen, die weitere Ordner beinhalten, die die selben Eigenschaften haben können wie die Oberordner.

Also:


Code:
<element>
    <name>Hauptelement</name>
    <unterelement>
          <name>Unterelement</name>
    </unterelement>
</element>


Jetzt gehe ich die XML-Datei durch, lese die Elemente ein, lege für jedes Element ein neues Objekt in das Hauptarray, das u.a. "name" als String beinhaltet. Nun soll dazu ein weiteres Unterarray mit den Unterelementen angelegt werden, das dann in ebenfalls mit Objekten gefüllt und in das Hauptarray gelegt wird.

Um die Elemente einzutragen mache ich das mit

Code:
if	([elementName isEqualToString:@"name"]){
[einObjekt setValue:currentElementValue  forKey:elementName]; }

Leider ist "einObjekt" immer das Hauptobjekt aus dem Hauptarray und somit bekommt dann das Objekt "Hauptelement" in diesem Zug den Namen "Unterelement" zugewiesen, obwohl das natürlich quatsch ist.

Wie kann ich dies am verhindern, ohne die XML Datei zu verändern - ich möchte die Möglichkeit haben die Elemente unendlich weit zu untergliedern… Ich muss doch irgendwie herausbekommen können, ob ich in der zweiten Ebene von Elementen bin oder so…
 

hillepille

Melrose
Registriert
19.07.09
Beiträge
2.508
hi, ich habe zwar keine ahnung von os - entwicklung, aber könnte es daran liegen, dass dein unterelement auf der gleichen ebene wie das eigentlich übergeordnete element name steht und nicht unterlhalb con name? also

<name>
<unterelement>
<name></name>
</unterelement>
</name>

a, mea culpa, ich hatte überlesen, dass das xml-file unberührt bleiben soll. wenn nach einem hauptelement immer das unterelement kommt bzw. kommen kann, dann könntest du ggf. dem gerade erstellten objekt einobjekt doch das unterlement zuweisen.

if ([elementName isEqualToString:mad:"unterelement"]){
[einObjekt setValue:currentElementValue forKey:unterelement]; }

wie gesagt, sprachentechnisch kann ich nicht mitreden, aber so in der art würde ich das angehen.
 
Zuletzt bearbeitet:

.holger

Borowitzky
Registriert
13.09.04
Beiträge
8.970
das mache ich, ich gehe die XML durch, wenn ich ein Unterelement Start finde, dann erstelle ich ein neues Objekt, und möchte anfangen dies zu füllen, wenn dann das End-Tag vom Unterelement gefunden wird, dann wird dieses neue Objekt als Element vom ersten Objekt gespeichert… nur der Parser versteht halt nicht, dass wenn er "name" findet, dies zum Unterelement gehört und nicht zu Hauptelement…
 

.holger

Borowitzky
Registriert
13.09.04
Beiträge
8.970
hmmm… zur Not lass ich nen Counter mitlaufen, der zählt wie tief ich in der Verschachtelung bin, aber das kann doch auch nicht die elegante Lösung sein, oder?
 

MacApple

Schöner von Bath
Registriert
05.01.04
Beiträge
3.652
Wie kann ich dies am verhindern, ohne die XML Datei zu verändern - ich möchte die Möglichkeit haben die Elemente unendlich weit zu untergliedern… Ich muss doch irgendwie herausbekommen können, ob ich in der zweiten Ebene von Elementen bin oder so…
Du könntest das über einen Stack lösen. Immer wenn ein neues Element anfängt, schiebst Du das auf Deinen "Bearbeitungsstack" und arbeitest dann halt immer mit dem obersten Element. Kommt dann das Ende des Elements, nimmst Du es wieder vom "Bearbeitungsstack" runter. Durch das auf den Stack legen und wieder runter nehmen, wechselst Du dann quasi automatisch zwischen den Ebenen hin und her.

MacApple
 

Poljpocket

Salvatico di Campascio
Registriert
07.01.07
Beiträge
432
So wie sich das anhört, benutzt du die "Event-driven XML parsing" Methode von Cocoa. Es gibt aber noch eine zweite, nämlich "Tree-based XML parsing". Ich verwende für meine Datenbanken fast nur die, weil du den Baum der Objekte schön mit einer Baumstruktur von 'NSXMLNode'-Instanzen erhälst. Diese enthalten immer automatisch child-nodes, also genau die Unterelemente, die du suchst. Jede node enthält auch automatisch alle Attribute (also damit deinen 'name'-Tag). Das mühsame Einlesen von allen Elementen und dessen Attribute wird dir damit erspart.

Programming Guide: Tree-Based XML Programming Guide

Gruss ppocket
 
  • Like
Reaktionen: .holger

denio

Empire
Registriert
23.01.10
Beiträge
88
Hab neulich das selbe Problem gehabt, hab es durch ein kleinen "Workaround" gelöst, ist zwar nicht ganz so schön, aber da es bei mir maximal einen Unterbaum gibt, ist es ok. So kommt z.B. Type zweimal vor jeweils im "Haupt"- und "Unter"-Baum

Code:
if ([elementName isEqualToString:kName_Type])
{
// emptyCheck ist ein kleine Hilfsmethode die guckt ob "currentData.typeDataMain/Sub" leer ist, wenn ja handelt es
// sich um typeDataMain aus dem Hauptbaum
	if (emptyCheck(currentData.typeDataMain))
	{
// Für den Fall ausgelesene XML-Wert (currentString) der typeDataMain leer ist wird ein emptyString 
// eingefügt somit typeDataMain beim nächsten durchlauf nicht mehr empty und emptyCheck geht in
// den else-Zweig
		if ([@"" isEqualToString:currentString])
		{
			currentData.typeDataMain = emptyString;
		}
		else
		{
// wenn currentString nicht leer ist wird dieser XML-Wert nun typeDataMain zugewiesen und
// und typeDataMain ist beim nächsten durchlauf nicht mehr empty -> emptyCheck geht in den
// else-Zweig
			currentData.typeDataMain = currentString;
		}
	}
	else if (emptyCheck(currentData.typeDataSub))
	{
// selbes Prinzip wie oben, aber nun wird typeDataSub mit nem emptyString oder currentString gefüllt
		if ([@"" isEqualToString:currentString])
		{
			currentData.typeDataSub = emptyString;
		}
		else
		{
			currentData.typeDataSub = currentString;
		}
	}
}

Ich weis ist nicht wirklich schick, aber momentan reicht es, ohne alles für den Tree-Based XML-Parser umzuschreiben :)
 

Oxy

Antonowka
Registriert
15.03.07
Beiträge
363
Ich würde es mit einem Switch und einem Boolwert lösen.
String tag="";
bool isSub=False;
<Main>
tag="Main";
<name>
tag="name";
<unterelement>
isSub=True;
tag="unterelement"
<name>
tag="name";
</name>
</unterelement>
</name>
<Main>


Switch(tag)
case "name":
if(isSub)
{...}else{...}
 
  • Like
Reaktionen: .holger

.holger

Borowitzky
Registriert
13.09.04
Beiträge
8.970
Hey,

danke. Hab das jetzt erstmal über nen Booleanwert gelöst. Das reicht vorerst, da ich bisher nur in eine Unterebene gehe und das Programm schnell fertig werden muss.

Werde mir aber die Treebased-Sache mal angucken und dann in einem Update das ganze wohl umstricken… klingt sauberer…

Gruß Holger
 

.holger

Borowitzky
Registriert
13.09.04
Beiträge
8.970
Hmm…*ich versuch die Unterelemente gerade wieder auszugeben…*ist aber noch etwas komplizierter als bisher gesagt.

Also ich habe jetzt ein Objekt. In dem Objekt ist u.a. ein Array aus anderen Objekten. Und nun brauche ich ein bestimmtes Element aus diesen letzten Objekten.

for (id obj in MeinArray.DieObjekte)
{
NSLog(@"obj: %@", obj.Name);
}

das funktioniert jedoch nicht, da "Name" innerhalb der Schleife nicht definiert ist, obwohl es ein Element von "DieObjekte" ist.
Irgendwie steh ich auf dem Schlauch… vielleicht sollte ich morgen weitermachen…
 

MacApple

Schöner von Bath
Registriert
05.01.04
Beiträge
3.652
Laut Deinem Code oben muss das auch
Code:
obj.name
heißen. Du solltest Dich auch an die Namens-Konventionen von Cocoa halten. Macht das Programiererleben leichter.

MacApple
 

.holger

Borowitzky
Registriert
13.09.04
Beiträge
8.970
Hey, meine Variable heißt schon nicht 'name' - das hab ich hier nur so reingeschrieben um es einfach zu halten.

Ich hab grad festgestellt, dass ich mit

Code:
	for (id obj in meinArray.DieObjekte)
		
	{
		NSString *test = [obj name];
		NSLog(@"%@",test);
}

korrekt an das Ergebnis komme…
 

MacApple

Schöner von Bath
Registriert
05.01.04
Beiträge
3.652
Hey, meine Variable heißt schon nicht 'name' - das hab ich hier nur so reingeschrieben um es einfach zu halten.
Das hilft natürlich ungemein beim Helfen, wenn Du hier anderen Code rein schreibst, als Du in Deinem Projekt hast.

Ich hab grad festgestellt, dass ich mit

Code:
	for (id obj in meinArray.DieObjekte)
		
	{
		NSString *test = [obj name];
		NSLog(@"%@",test);
}

korrekt an das Ergebnis komme…
Ach, da schau her. Dir ist bekannt, dass der Compiler aus
Code:
[obj name]
und
Code:
obj.name
den gleichen Code generiert?

Code:
obj.name
und
Code:
obj.Name
hingegen sind für den Compiler zwei verschiedene Dinge.

MacApple
 

.holger

Borowitzky
Registriert
13.09.04
Beiträge
8.970
ja, das ist mir bekannt und deswegen wundert es mich…
Ich kann leider den echten Code hier nicht reinschreiben… sorry