XML Datei parsen -> Daten verschwinden

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • XML Datei parsen -> Daten verschwinden

    So Hallo erst mal...
    ich habe wieder einmal ein Problem...

    Ich möchte eine XML Datei mit 1 Artikel parsen...
    Der Aufbau dieser Datei ist wie folgt: (sorry für die darstellung aber ich kann die nicht wirklich so formatieren, dass die verschachtelung stimmt)

    Quellcode

    1. <Root>
    2. <Items>
    3. <ItemRec>
    4. <v2_No>80001</v2_No>
    5. ...
    6. <ar_ItemVariants>
    7. <ItemVariantRec>
    8. <v2_ItemVariantNo>VAR1</v2_ItemVariantNo>
    9. <v5_Description>Variantenbeschreibung</v5_Description>
    10. </ItemVariantRec>
    11. <ItemVariantRec>
    12. <v2_ItemVariantNo>VAR2</v2_ItemVariantNo>
    13. <v5_Description>Variantenbeschreibung2</v5_Description>
    14. </ItemVariantRec>
    15. </ar_ItemVariants>
    16. <ar_Locations>
    17. <LocationRec>
    18. <v1_Location>GELB</v1_Location>
    19. <de_Quantity>0</de_Quantity>
    20. </LocationRec>
    21. <LocationRec>
    22. <v1_Location>GRÜN</v1_Location>
    23. <de_Quantity>0</de_Quantity>
    24. </LocationRec>
    25. </ar_Locations>
    26. </ItemRec>
    27. </Items>
    28. </Root>
    Alles anzeigen



    Also es gibt für diesen Artikel 2 Artikelvarianten und 2 verschiedene Lagerorte.
    Wenn ich die Datei mit dem XML Parser parse bekomme ich ja einen Array zurück.
    dieser Array beinhaltet dann aber leider immer nur eine Artikelvariante und einen Lagerort (jeweils den letzten).

    WIESO?
    Der jeweils erste wird immer wieder durch den darauffolgenden überschrieben... Aber wie kanne ich das verhindern, ohne dass ich die Tags im XML verschieden benennen muss?

    Hatte jemand schonmal so ein Problem oder weiß jemand die Lösung dazu?
    greetz,
    seitz
  • hier mein Code vom Parser:

    Quellcode

    1. ´ function ts_xmlparse($filePath, $newTagTranslateIntoCounters=array())
    2. {
    3. $this->curElement = array();
    4. $this->tagTranslateIntoCounters = array();
    5. foreach ($newTagTranslateIntoCounters as $newTagTranslateEntry)
    6. $this->tagTranslateIntoCounters[$newTagTranslateEntry] = 0;
    7. $this->hierarchyTree = array();
    8. $parser = xml_parser_create();
    9. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
    10. xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
    11. xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "iso-8859-1");
    12. xml_set_element_handler($parser, array(&$this,'ts_xmlparse_startElement'), array(&$this,'ts_xmlparse_endElement'));
    13. xml_set_default_handler($parser, array(&$this,'ts_xmlparse_defaultHandler'));
    14. if (($file = fopen($filePath, "rb")) === FALSE)
    15. return -1;
    16. do
    17. {
    18. if (!xml_parse($parser, fread($file, 0xffff), 0))
    19. return -1;
    20. }
    21. while (!feof($file));
    22. fclose($file);
    23. xml_parser_free($parser);
    24. }
    25. function ts_xmlparse_startElement($parser, $name, $attrs)
    26. {
    27. if (array_key_exists($name, $this->tagTranslateIntoCounters))
    28. $name .= ($this->tagTranslateIntoCounters[$name] + 1);
    29. $this->curElement[$name] = array();
    30. $this->stack[$this->depth++] = $this->curElement;
    31. $this->curElement = array();
    32. }
    33. function ts_xmlparse_endElement($parser, $name)
    34. {
    35. if (array_key_exists($name, $this->tagTranslateIntoCounters))
    36. $name .= (++$this->tagTranslateIntoCounters[$name]);
    37. $oldCur = $this->curElement;
    38. $this->curElement = $this->stack[--$this->depth];
    39. $this->curElement[$name] = $oldCur;
    40. if (!count($this->curElement[$name]))
    41. $this->curElement[$name] = $this->curElemVal;
    42. unset($this->curElemVal);
    43. switch ($name)
    44. {
    45. case "ItemRec": $this->updateItem($this->curElement[$name]);
    46. break;
    47. }
    48. }
    49. function ts_xmlparse_defaultHandler($parser, $data)
    50. {
    51. if (trim($data) != "")
    52. $this->curElemVal .= $data;
    53. }
    Alles anzeigen


    und hier noch mein Aufruf: (in "$itemFileArr[$i]" befindet sich ein ein Dateipfad)

    Quellcode

    1. $this->zk_xmlparse($itemFileArr[$i], array("Items"));
    greetz,
    seitz
  • ok, dann probier ich das einfach mal...

    muss ich für simplexml irgendwas machen, importieren o.ä.?
    ich habe jetzt folgende funktion:

    Quellcode

    1. function XMLToArray($xml)
    2. {
    3. if ($xml instanceof SimpleXMLElement)
    4. {
    5. $children = $xml->children();
    6. $return = null;
    7. }
    8. else
    9. $children = $xml->children();
    10. foreach ($children as $element => $value)
    11. {
    12. if ($value instanceof SimpleXMLElement)
    13. {
    14. $values = (array)$value->children();
    15. if (count($values) > 0)
    16. {
    17. $return[$element] = XMLToArray($value);
    18. }
    19. else
    20. {
    21. if (!isset($return[$element]))
    22. {
    23. $return[$element] = (string)$value;
    24. }
    25. else
    26. {
    27. if (!is_array($return[$element]))
    28. {
    29. $return[$element] = array($return[$element], (string)$value);
    30. }
    31. else
    32. {
    33. $return[$element][] = (string)$value;
    34. }
    35. }
    36. }
    37. }
    38. }
    39. if (is_array($return))
    40. {
    41. return $return;
    42. }
    43. else
    44. {
    45. return $false;
    46. }
    47. }
    Alles anzeigen


    funktionieren tuts aber gar nicht...
    ich bekomme eine fehlermeldung, dass in der foreach ein argument falsch ist (kein array).
    und wenn ich vorher

    Quellcode

    1. $children = $xml->children();

    mache dann bekomme ich folgende fehlermeldung
    "Call to a member function children() on a non-object"
    greetz,
    seitz
  • Das ist aber eine komplizierte Lösung. simplexml gibt dir das XML File als Object zurück.
    Wenn du den Umgang mit Objekten nicht gewohnt bist, könntest du auch einfach die Funktion [phpdoc]get_object_vars[/phpdoc] verwenden.

    Ich würde mich aber nicht so gegen Objektorientierung streuben und nur mit dem simplexml Objekt arbeiten.
    Beispiele findest du im Manual: de.php.net/manual/de/function.simplexml-element-children.php

    UPDATE: "Call to a member function children() on a non-object"
    du hast die XMLToArray Methode nicht selber geschrieben, oder? lass sie einfach weg

    Das Beispiel aus dem Link:

    Quellcode

    1. $xml = simplexml_load_file('filename.xml');
    2. foreach ($xml->children() as $second_gen) {
    3. echo ' Die Person zeugte eine/n ' . $second_gen['role'];
    4. ...
    5. }
  • ich raffs nicht... echt..
    ich hab mir eine eigene funktion "XMLToArray" geschrieben, als Parameter wird der Pfad zur Datei übergeben und als optionales Parameter das XML Element ab dem ich ein Array benötige...

    Aufrufen tu ich das ganze so:

    Quellcode

    1. if(is_file($xmlFilePath_customer))
    2. $xml = simplexml_load_file($xmlFilePath_customer);
    3. else
    4. $xml = new SimpleXMLElement($xmlFilePath_customer);
    5. $xmlCustomer = $this->XMLToArray($xml, "Customers");
    6. print_r($xmlCustomer);


    und hier meine Funktion, die rekursiv laufen sollte:

    Quellcode

    1. function XMLToArray($xml, $xmlTag = NULL)
    2. {
    3. foreach ($xml as $key => $val)
    4. {
    5. if(is_array($val)||is_object($val))
    6. {
    7. if ($xmlTag == $key)
    8. {
    9. if(count($val) > 1)
    10. $xmlArray[$key] = $this->XMLToArray($val);
    11. else
    12. $xmlArray[$key] = $this->XMLToArray($val);
    13. }
    14. else
    15. {
    16. if(count($val) > 1)
    17. $xmlArray[$key][] = $this->XMLToArray($val);
    18. else
    19. $xmlArray[$key] = $this->XMLToArray($val);
    20. }
    21. }
    22. else
    23. {
    24. $xmlArray[$key] = $val;
    25. }
    26. }
    27. if (is_array($xmlArray))
    28. return $xmlArray;
    29. else
    30. return false;
    31. }
    Alles anzeigen


    und hier meine Beispiel XML Datei:

    Quellcode

    1. <Root>
    2. <Customers>
    3. <CustomerRec>
    4. <v2_No>10000</v2_No>
    5. <v3_Name>Möbel-Meller KG</v3_Name>
    6. <v3_Name2/>
    7. <v3_Address>Tischlerstr. 4-10</v3_Address>
    8. <v3_Address2/>
    9. <v2_PostCode>48436</v2_PostCode>
    10. <v3_City>Düsseldorf</v3_City>
    11. <v1_Country/>
    12. <ti_InclVAT>Nein</ti_InclVAT>
    13. <v5_Username>moebelmeller</v5_Username>
    14. <v5_Password>test</v5_Password>
    15. <v2_Telephone/>
    16. <v2_Fax/>
    17. <v5_Email>mobel-meller.kg@cronuscorp.net</v5_Email>
    18. <v2_VATRegistrationNo>789456278</v2_VATRegistrationNo>
    19. <ar_InvoiceDiscs>
    20. <InvoiceDiscRec>
    21. <de_MinimumAmount>0</de_MinimumAmount>
    22. <de_DiscountPercent>5</de_DiscountPercent>
    23. <de_ServiceCharge>0</de_ServiceCharge>
    24. </InvoiceDiscRec>
    25. </ar_InvoiceDiscs>
    26. <ar_ItemCrossReferences/>
    27. </CustomerRec>
    28. <CustomerRec>
    29. <v2_No>01121212</v2_No>
    30. <v3_Name>Spotsmeyer's Furnishings</v3_Name>
    31. <v3_Name2/>
    32. <v3_Address>612 South Sunset Drive</v3_Address>
    33. <v3_Address2>Adresse 2</v3_Address2>
    34. <v2_PostCode>FL 37125</v2_PostCode>
    35. <v3_City>Miami</v3_City>
    36. <v1_Country>US</v1_Country>
    37. <ti_InclVAT>Nein</ti_InclVAT>
    38. <v5_Username>user</v5_Username>
    39. <v5_Password>pass</v5_Password>
    40. <v2_Telephone>01234/567890</v2_Telephone>
    41. <v2_Fax>09876/543210</v2_Fax>
    42. <v5_Email>spotsmeyer's.furnishings@cronuscorp.net</v5_Email>
    43. <v2_VATRegistrationNo>ustid1234556678</v2_VATRegistrationNo>
    44. <ar_InvoiceDiscs>
    45. <InvoiceDiscRec>
    46. <de_MinimumAmount>10</de_MinimumAmount>
    47. <de_DiscountPercent>30</de_DiscountPercent>
    48. <de_ServiceCharge>5</de_ServiceCharge>
    49. </InvoiceDiscRec>
    50. <InvoiceDiscRec>
    51. <de_MinimumAmount>5</de_MinimumAmount>
    52. <de_DiscountPercent>30</de_DiscountPercent>
    53. <de_ServiceCharge>2</de_ServiceCharge>
    54. </InvoiceDiscRec>
    55. </ar_InvoiceDiscs>
    56. <ar_ItemCrossReferences>
    57. <ItemCrossReferenceRec>
    58. <v2_ItemNo>1000</v2_ItemNo>
    59. <in_ItemVariantNo/>
    60. <v3_CrossReferenceNo>000001</v3_CrossReferenceNo>
    61. </ItemCrossReferenceRec>
    62. <ItemCrossReferenceRec>
    63. <v2_ItemNo>1001</v2_ItemNo>
    64. <in_ItemVariantNo/>
    65. <v3_CrossReferenceNo>000002</v3_CrossReferenceNo>
    66. </ItemCrossReferenceRec>
    67. </ar_ItemCrossReferences>
    68. </CustomerRec>
    69. </Customers>
    70. </Root>
    Alles anzeigen


    den array den ich aus dieser funktion bekomme der ist einfach unbrauchbar... total unbrauchbar und total falsch...
    ich möchte einfach einen array der so aussieht:

    Quellcode

    1. CustomerRec = array(
    2. "v2_No" = "10000"
    3. ...
    4. "ar_InvoiceDisc" = array(
    5. "InvoiceDiscRec" = array(
    6. "de_minimumaccount" = "0"
    7. )
    8. "invoiceDiscRec" = array(
    9. "de_minimumaccount" = "10"
    10. )
    11. )
    12. )
    Alles anzeigen
    greetz,
    seitz
  • Ich finde es löblich, dass man sich nicht alles aus dem Internet kopiert. Aber für viele Bereiche (vor allem für XML) gibt es standardisierte Lösungen.
    Das Schlüsselwört heißt hier XPATH.

    Hier die Lösung ohne die XMLToArray Methode.

    Quellcode

    1. $xml = simplexml_load_file($filename);
    2. $result = $xml->xpath('/Root/Customers/CustomerRec');
    3. foreach($result as $CustomerRec) {
    4. echo $CustomerRec->v3_Name." ";
    5. }
  • Vielen Dank!
    und das mit dem XPATH muss ich morgen gleich testen (geht heut leider nicht mehr...)

    Zum Thema "aus dem Internet kopieren":
    Danke! Ich persönlich finde, dass der lern-effekt total verloren geht, wenn man sich alles aus dem Internet kopiert.
    Schreibt man seinen Code selber ist der AHA Effekt vorhanden und man lernt einiges dazu, ich zumindest, da ich erst an meinen Anfängen bin...

    Allerdings schon mal vielen Dank für die kompetenten Antworten. In einem anderen und vor allen Dingen größeren Forum habe ich den selben Post und zwar viele viele Antworten bekommen, allerdings fast keine hilfreiche...
    greetz,
    seitz
  • So, das mit dem XPath ist ja an und für sich gar nicht mal schlecht, danke ;)
    jetzt habe ich aber immer noch ein Problem...
    ist in der geparsten XML ein leeres Element dabei (was leider öfter der Fall ist), wird das als "SimpleXMLElement Object" abgestempelt...

    hier ein print_r:

    Quellcode

    1. Array
    2. (
    3. [Customers] => SimpleXMLElement Object
    4. (
    5. [CustomerRec] => Array
    6. (
    7. [0] => SimpleXMLElement Object
    8. (
    9. [v2_No] => 10000
    10. [v3_Name] => Möbel-Meller KG
    11. [v3_Name2] => SimpleXMLElement Object
    12. (
    13. )
    14. [v3_Address] => Tischlerstr. 4-10
    15. [v3_Address2] => SimpleXMLElement Object
    16. (
    17. )
    Alles anzeigen


    gibts dazu auch noch etwas oder muss ich das irgendwie mit ner if abfangen?
    greetz,
    seitz
  • jetz hab ichs =)
    vielen vielen dank, dass du mir damit geholfen hast!

    und hier meine bestimmt letzte frage (hoffe ich zumindest)...
    Weißt du wie SimpleXML arbeitet? Das andere was ich hatte um die XML Datei zu parsen hat ja mit Callback-Funktionen gearbeitet...
    Wird also bei SimpleXML zuerst die komplette Datei an sich angesehen oder wird gleich wenn ein End-Tag erreicht ist das bisherige ausgelesen?

    Ich hoffe ich konnte das irgendwie verständlich erklären ;)

    Danke nochmals!
    greetz,
    seitz
  • bei DOM wird immer die gesamte Datei geladen.
    Das vorgehen bei dem man durch Dokumente iteriert benötigt einen SAX Parser

    Hier findest du Implementierung und Vergleich: professionelle-softwareentwick…gramming-php.xml.sax.html
    Vor- und Nachteile
    + Standard, wenn auch nicht vom World Wide Web Consortium.
    + Geringer Speicherverbrauch, da immer nur das aktuelle XML-Element verfügbar ist.
    + Schnell.
    - Lineare Verabeitung, kein beliebiger Zugriff auf Elemente möglich.
    - Kein Schreibzugriff möglich.
    - Programmierer muss sich um Buchhaltung kümmern.