flobee: rukursion, datenstuktur in xml baum wandeln

hallo
ich sitze mal wieder vor dem gleichen problem wie alle paar monate.
ich möchte rekursiv durch ein mehrdimensionales array laufen und nun die datenstrucktur in ein xml zurückgeben.
insbesondere wenn es in die tiefe geht blicke ich nicht mehr durch welche "schalter" ich in einer klasse benötige um den zu öffneden tag bzw den schliessenden tag nach dem durchlauf von N children einzu setzen.
vielleich habe ich auch zu wenig methoden oder vergesse gewisse dinge bis ich mich dann dabei erwische wie ich die rekursion gar nicht verwende da ich fast für jede ebene eine neu schleife schreibe :-(

mein array sieht wie folgt aus:
<code>$data;</code>
$data = array(
    array('nodeName'=>'music',
     'nodeAttr'=>array('id'=>199,'name'=>'FirstName'),
     'nodeValues'=>false,
     'children'=>array(
         array(
         'nodeName'=>'album',
         'nodeValues'=>false,
         'nodeAttr'=>array('albumid'=>'1234',
               'albumname'=>'The King'),
         'children'=>array(
             array(
               'nodeName'=>'tracks',
               'nodeValues'=>false,
               'nodeAttr'=>array('albumid'=>'1234'),
               'children'=>array(
                   'nodeName'=>'track',
                   'nodeValues'=>array(array('VALUE1',$attributes),
                         array('VALUE2',$attributes)
                        ),
                   'nodeAttr'=>$attributes,
                   'children'=>false
                   ),
               ),
             array(
               'nodeName'=>'information',
               'nodeValues'=>array(array('artist',$attributes),
                     array('autor',$attributes),
                     array('lenght',$attributes),
                     array('size',$attributes)
                    ),
               'nodeAttr'=>array('albumid'=>'1234'),
               'children'=>false
               ),
            ),

)
        )
    )
   );
ich habe hier insgesammt 3 grund methoden

  1. den grundbaum und den ersten zweig bauen
  2. die methode die rekursiv durch das array laufen soll und einen node zurück gibt (hier ist mein problem wenn kinder elemente da sind wie ich kinder und kindes kinder zusammen setzte)
  3. eine methode die mir die arttibute als string zurück gibt.

vielleicht kann mir ja jemend schritt weise erkläre was ich beachten muss.

lieben gruß
florian

  1. hallo florian

    zur Grundstruktur:

    function mach_xml($a)
       {

    Definition von benötigkten Variablen

    $br="\n";
       $S =' ';

    Aufbau des Elements

    $element.=$br.'<'.$a['nodeName'];

    Aufbau der Attribute

    if(isset($a['nodeAttr']))
          {
          foreach($a['nodeAttr'] as $k=>$v)
             {
             $element.=$S.$k.'="'.$v.'"';
             }
          }

    Bestimmung des Inhalts

    if($a['nodeValues'])
          {

    # Bestimmung Welche Art Inhalt vorliegt

    if(is_array($a['nodeValues']))
             {

    # Aufbau der Kindelemente

    foreach($a['nodeValues'] as $v)
                {

    # Rekursion auf die Kindelemente

    $element.='>'.mach_xml($v);
                $element.='</'.$a['nodeName'].'>'.$br;
                }
             }
          elseif($a['nodeValues'])
             {

    # Kindelement ist ein Textnode

    $element.='>'.$a['nodeValues'];
             $element.='</'.$a['nodeName'].'>'.$br;
             }
          else
             {

    # Element ist leer

    $element.=$S.'/>'.$br;
             }
          }
       }

    Mit obiger nicht geprüfter Funktion müßte Dein Datenfeld durchlaufen werden können. Allerdings bin ich anders, als Du, davon ausgegangen nodeValues beinhaltet Kindelemente!

    nodeValues=children

    Der Wert FALSE für nodeValues drückt ein leeres Element aus

    Gruß aus Berlin!
    eddi

    1. hallo florian

      habe mir meinen Müll nochmals zur Brust genommen und folgendes ist nun funktionstüchtig herausgekommen:

      <?php
      function mach_xml($a,$b=array('',TRUE))
         {

      Definition von benötigkten Variablen

      $br="\n";
         $S =' ';

      Aufbau des Elements

      $element= $b[1] ? '<?xml version="1.0" ?>' : '';
         $element.=$br.$b[0].'<'.$a['nodeName'];

      Aufbau der Attribute

      if(is_array($a['nodeAttr']))
            {
            foreach($a['nodeAttr'] as $k=>$v)
               {
               $element.=$S.$k.'="'.$v.'"';
               }
            }

      Bestimmung des Inhalts

      if($a['nodeValues']!==FALSE)
            {

      # Bestimmung Welche Art Inhalt vorliegt

      if(is_array($a['nodeValues']))
               {
               $element.='>';

      # Aufbau der Kindelemente

      foreach($a['nodeValues'] as $v)
                  {

      # Rekursion auf die Kindelemente

      $element.=mach_xml($v,array($b[0]."\t",FALSE));
                  }
               $element.=$br.$b[0].'</'.$a['nodeName'].'>';
               }
            else
               {

      # Kindelement ist ein Textnode

      $element.='>'.$a['nodeValues'];
               $element.=$br.$b[0].'</'.$a['nodeName'].'>';
               }
            }
         else
            {

      # Element ist leer

      $element.=$S.'/>';
            }

      return($element);

      #unset($element,$k,$v);

      }

      Das Datenfeld muß anders aufgebeut werden!

      $a=array(
       'nodeName' =>'music',
       'nodeAttr' =>array(
        'id' =>199,
        'name' =>'FirstName'),
       'nodeValues' =>array(
          array(
          'nodeName' =>'album',
                  'nodeAttr' =>array(
           'albumid' =>'1234',
           'albumname' =>'The King'),
                  'nodeValues' =>array(
             array(
             'nodeName' =>'tracks',
             'nodeAttr' =>array(
              'albumid'=>'1234'),
             'nodeValues' =>array(
                array(
                'nodeName' =>'track',
                'nodeAttr' =>array('albumid'=>'1234'),
                'nodeValues' =>false),
                array(
                'nodeName' =>'information',
                'nodeAttr' =>array('albumid'=>'1234'),
                'nodeValues'=>false),
                ),
              )
             )
           )
          )
       );

      echo mach_xml($a);
      ?>

      Gruß aus Berlin!
      eddi

      1. hallo florian

        Hallo eddi
        vielen dank für deine mühe!
        ja, ich habe absichtlich children und nodeValues von einander getrennt da ich anfänglich die übersicht verlohren habe!
        auf der anderen seite hatte ich es mit der prüfung der eingehenden daten leichter: values sind immer "string" oder "empty" und children sind immer "array" oder "empty"

        ich arbeite deine funktion mal ab/aus und melde mich definitiv noch mal!

        Gruß aus Berlin!
        eddi

        gruß florian

        --
        -----------------------
        .-´-:: flobee :: -´-.
        1. Hallo eddi

          leichter: values sind immer "string" oder "empty" und children sind immer "array" oder "empty"

          da habe ich sogar quatsch geschrieben! es sind immer arrays oder empty

          getrennt habe ich es da sie ja anders aufgebaut werden! vielleicht ist ´mein einleitendes array auch falsch!?

          -----------------------
          .-´-:: flobee :: -´-.

      2. eddi

        hallo eddi!
        deine funktion geht nicht so ganz!
        ziel ausgabe soll werden: ("root" gab es bei mir schon. mein array in der vorgabe war falsch! ich muss natürlich mit einem "root" beginnen.):
        <?xml version="1.0" ?>
        <root>
         <music id="199" name="FirstName">
          <album albumid="1234" albumname="The King">
           <tracks albumid="1234">
            <track albumid="1234">VALUE1</track>
            <track albumid="1234">VALUE2</track>
           </tracks>
           <information albumid="1234">
            <artist ... >Artist (fehlt in meinem array auch!!!</artist>
            <autor ... ></autor>
            <lenght ... ></lenght>
           </information>
          </album>
         </music>
        </root>

        mit deinem array kommt folgendes raus (wobei du ein paar values vergessen hast):
        <?xml version="1.0" ?>
        <music id="199" name="FirstName">
         <album albumid="1234" albumname="The King">
          <tracks albumid="1234">
           <track albumid="1234" />
           <information albumid="1234" />
          </tracks>
         </album>
        </music>

        fügst du jetzt die fehlen daten hinzu wird es "wild" und ich glaube es ist die stelle wo die recursion ggf probleme bekommen wird und weshalb ich in meinem daten array 'children' eingeführt habe:
        <tracks albumid="1234">
           <t>t
           </t>
           <>
           </>
           <>
           </>
        </tracks>

        gruß florian

        --
        -----------------------
        .-´-:: flobee :: -´-.
        1. hallo Florian!

          Für mich persönlich wäre es einfacher Kindknoten/Strings/Empty als Value anzunehmen, aber das steht Dir natürlich frei. Habe nochmal ein wenig rumgemurchst und nun scheint mach_xml() aus einem anderen Datenfeld folgendes zu machen:

          <?xml version="1.0" ?>
          <root>
           <music id="199" name="FirstName">
            <album albumid="1234" albumname="The King">
             <tracks albumid="1234">
              <track albumid="1234">VALUE1</track>
              <track albumid="1234">VALUE2</track>
             </tracks>
             <information albumid="1234">
              <artist attr="0">Artist (fehlt in meinem array auch!!!</artist>
              <author attr="0">Artist (fehlt in meinem array auch!!!</author>
              <lenght attr="0">Läge würde ich als Attribut vergeben</lenght>
             </information>
            </album>
           </music>
          </root>

          <?php
          function mach_xml($a,$b=array('',TRUE))
           {
           # Definition von benötigkten Variablen
           $br="\n";
           $S =' ';

          # Aufbau des Elements
           $element= $b[1] ? '<?xml version="1.0" ?>' : '';
           $element.=$br.$b[0].'<'.$a['nodeName'];

          # Aufbau der Attribute
           if(is_array($a['nodeAttr']))
            {
            foreach($a['nodeAttr'] as $k=>$v)
             {
             $element.=$S.$k.'="'.$v.'"';
             }
            }

          # Bestimmung des Inhalts
           if($a['nodeValues']!==FALSE)
            {
            # Bestimmung Welche Art Inhalt vorliegt
            if(is_array($a['nodeValues']))
             {
             $element.='>';

          # Aufbau der Kindelemente
             foreach($a['nodeValues'] as $v)
              {
              # Rekursion auf die Kindelemente
              $element.=mach_xml($v,array($b[0]."\t",FALSE));
              }
             $element.=$br.$b[0].'</'.$a['nodeName'].'>';
             }
            else
             {
             # Kindelement ist ein Textnode
             $element.='>'.$a['nodeValues'];
             $element.='</'.$a['nodeName'].'>';
             }
            }
           else
            {
            # Element ist leer
            $element.=$S.'/>';
            }
           return($element);
           #unset($element,$k,$v);
           }

          $a=array(
           'nodeName' =>'root',
           'nodeValues' =>array(
             array(
             'nodeName' =>'music',
             'nodeAttr' =>array(
              'id' =>199,
              'name' =>'FirstName'),
             'nodeValues' =>array(
                array(
                'nodeName' =>'album',
                        'nodeAttr' =>array(
                 'albumid' =>'1234',
                 'albumname' =>'The King'),
                        'nodeValues' =>array(
                   array(
                   'nodeName' =>'tracks',
                   'nodeAttr' =>array(
                    'albumid'=>'1234'),
                   'nodeValues' =>array(
                      array(
                      'nodeName' =>'track',
                      'nodeAttr' =>array('albumid'=>'1234'),
                      'nodeValues' =>'VALUE1'),
                      array(
                      'nodeName' =>'track',
                      'nodeAttr' =>array('albumid'=>'1234'),
                      'nodeValues' =>'VALUE2')
                      )
                    ),
                   array(
                   'nodeName' =>'information',
                   'nodeAttr' =>array(
                    'albumid'=>'1234'),
                   'nodeValues'=>array(
                     array(
                     'nodeName' =>'artist',
                     'nodeAttr' =>array(
                       'attr'=>0),
                     'nodeValues'=>'Artist (fehlt in meinem array auch!!!'),
                     array(
                     'nodeName' =>'author',
                     'nodeAttr' =>array(
                       'attr'=>0),
                     'nodeValues'=>'Artist (fehlt in meinem array auch!!!'),
                     array(
                     'nodeName' =>'lenght',
                     'nodeAttr' =>array(
                       'attr'=>0),
                     'nodeValues'=>'Länge würde ich als Attribut vergeben')
                      )
                     )
                    )
                   )
                 )
                )
              )
           );

          echo mach_xml($a);
          ?>

          Gruß aus Berlin!
          eddi

          1. hallo Florian!

            hallo!
            bei deiner rekursion ist manchmal $v kein array
            sehe (ungetestet) das gleiche problem!

            was ist bei der funktion jetzt anders?

            gruß flobee

            1. Re:

              bei deiner rekursion ist manchmal $v kein array

              Das beruht darauf, daß ich das Datenfeld gänzlich anders aufgebaut habe. Ich habe es Dir angehangen, damit Du Dir die Veränderungen zu Deinem Datenfeld verdeutlichen kannst. Letztendlich basiert auch die Funktionsweise auf der veränderten Struktur des Datenfeldes.

              Es gibt also zwei Möglichkeiten: Entweder Du schreibst Dir die Funktion um, daß sie Dein Datenfeld parst, oder Du folgst meinem Beispiel und veränderst den Aufbau des Datenfelds. Vielleicht kann man Dir eingehender helfen, wenn Du en Steuerfluß zum erstellen des Datenfeldes postest, oder erklärst, welche Passagen Dir bei der Umstellung auf Deine Struktur in mach_xml() probeme bereiten.

              Gruß aus Berlin!
              eddi

              1. Vielleicht kann man Dir eingehender helfen, wenn Du en Steuerfluß zum erstellen des Datenfeldes postest, oder erklärst, welche Passagen Dir bei der Umstellung auf Deine Struktur in mach_xml() probeme bereiten.

                hallo,

                Steuerfluß zum erstellen des Datenfeldes

                wie ich das array erzeuge?:
                das ist ausgedacht!
                so wie ich es mir am besten vorstellen könnte um überhaupt eine lösung zu finden!
                Ich habe so einige scripte gefunden, aber die machen das entweder nur in 2D oder können keine extras wie attribute o.ä.
                Letzt endlich kommen die Daten aus einer Datenbank. In der regel als assoziatives array

                ich habe meine klasse gerade fertig aber das ist noch nicht komfortable genug und ggf nicht 100% sauber.
                insbesondere finde ich die datenstruktur zu "komplex"/"fett", viel speicher für nix :-) also nicht wirklich zufrieden.
                hier habe ich das script mal hin gestellt:
                http://www.cgix.de/dev/php/class.ArrayToXml.phps
                vielleicht hast du ja eine idee wie man das leichter lösen könnte!?

                gruß florian

                --
                -----------------------
                .-´-:: flobee :: -´-.