WN

WN (https://www.wn.se/forum/index.php)
-   Serversidans teknologier (https://www.wn.se/forum/forumdisplay.php?f=4)
-   -   Loopa genom DomDocument och samtidigt manipulera den (https://www.wn.se/forum/showthread.php?t=1041055)

qson 2010-03-19 19:52

Loopa genom DomDocument och samtidigt manipulera den
 
Hej,
Försöker traversera ett XML-dokument med hjälp av DOMDocument. Jag går igenom dokumentet och om en viss sträng finns i ett element skall detta element klonas ett antal gånger.

Säg att jag har följande XML:
Kod:

<dokument>
  <rad>
    <klona>5</klona>
    <data>
      <info>information</info>
    </data>
  </rad>
</dokument>

Den traverserar dokumentet och hittar <klona>5</klona>, då skall raden klonas 5 gånger så resultatet blir som följer:
Kod:

<dokument>
  <rad>
    <klona>1</klona>
    <data>
      <info>information</info>
    </data>
  </rad>
  <rad>
    <klona>1</klona>
    <data>
      <info>information</info>
    </data>
  </rad>
  <rad>
    <klona>1</klona>
    <data>
      <info>information</info>
    </data>
  </rad>
  <rad>
    <klona>1</klona>
    <data>
      <info>information</info>
    </data>
  </rad>
  <rad>
    <klona>1</klona>
    <data>
      <info>information</info>
    </data>
  </rad>
</dokument>

Just nu har jag använt foreach($node->childNodes...) men det funkar ju inte. Funderat på att använda while, men vet inte villkor jag skall ställa.

En annan tanke var att ha ett dokument som traverseras och ett annat där man bygger resultatet.

Använder för övrigt $node->cloneNode() och ->parentNode->insertBefore() för att skapa klonerna.

jonny 2010-03-20 10:00

Du kanske skulle visa upp lite av koden, så blir det lättare att se var det går snett...

qson 2010-03-20 11:47

PHP-kod:

$data = array(/* En associativ array med arrays av massa stdclass-objekt */);
$firstCol false;
$firstRow true;
function 
handleNode(&$node,$data=null) {

    global 
$firstRow,$firstCol,$data;
    
    switch(
$node->nodeType) {
        case 
XML_ELEMENT_NODE
            {
            
                switch(
$node->tagName) {
                    case 
'table:table-row':
                    
                        
$formula $node->firstChild;
                        
$m = array();
                            if (
preg_match('/^for\s?each\s*\(\s*\$([a-z0-9_]+)\s+as\s+\$([a-z0-9_]+)\s*\)\s*(\{)?/i',$formula->textContent,$m))
                            {
                                
$array $m[1];
                                
$iterator $m[2];
                                
                                if (
array_key_exists($array,$data)) {
                                    
                                    foreach (
$data[$array] as $row) {
                                    
                                        
$newNode $node->cloneNode();
                                    
                                        foreach (
$newNode->childNodes as $childNode)
                                            
handleNode($childNode,$row);
                                    
                                        
$node->insertBefore($newNode,$node->nextSibling);
                                        
                                    }
                                    
                                    
$node->parentNode->removeChild($node);
                                }
                                else {
                                    
$node->parentNode->removeChild($node);
                                    return;
                                }
                            }
                        
                        
$firstCol true;
                        break;
                    case 
'table:table-cell':
                        if (!
$firstCol) {
                            
$m = array();
                            if (
preg_match('/^\$([a-z0-9_]+)\s*->\s*\$([a-z0-9_]+)/i',$node->textContent,$m))
                            {
                                
$node->textContent preg_replace('/^\$([a-z0-9_]+)\s*->\s*\$([a-z0-9_]+)/ie','@$data->\\2');
                            }
                        }
                        break;
                }
                echo 
$node->tagName."\n";
                foreach (
$node->childNodes as $childNode)
                    
handleNode($childNode);
                    
                    
                    
                    
                switch(
$node->tagName) {
                    case 
'table:table-row':
                        
$firstRow false;
                        break;
                    case 
'table:table-cell':
                        
$firstCol=false;
                        break;
                }
            }
            break;
        case 
XML_TEXT_NODE:
            echo 
"\"$node->textContent\"\n";
            break;
    }



Min XML ser egentligen ut så här (bara det viktigaste):
Kod:

...
        <table:table-row>
          <table:table-cell>
            <text:p>foreach ($receipts as $receipt) {</text:p>
          </table:table-cell>
          <table:table-cell>
            <text:p>$receipt-&gt;id</text:p>
          </table:table-cell>
          <table:table-cell>
            <text:p>$receipt-&gt;name</text:p>
          </table:table-cell>
          <table:table-cell>
            <text:p>$receipt-&gt;amount</text:p>
          </table:table-cell>
          <table:table-cell>
            <text:p>$receipt-&gt;vat1</text:p>
          </table:table-cell>
          <table:table-cell>
            <text:p>$receipt-&gt;vat2</text:p>
          </table:table-cell>
          <table:table-cell>
            <text:p>$receipt-&gt;vat3</text:p>
          </table:table-cell>
          <table:table-cell>
            <text:p>$receipt-&gt;net</text:p>
          </table:table-cell>
          <table:table-cell>
            <text:p>$receipt-&gt;date</text:p>
          </table:table-cell>
          <table:table-cell/>
        </table:table-row>
...mer XML...

Notera foreach som står i första cellen, den matchas i en preg_match, och sedan klonas raden lika många gånger som det finns värden i arrayen.
Jag tror att problemet ligger i foreach ($node->childNodes) eftersom den tar en ögonblicksbild av barnen och loopar dem, och tar inte hänsyn till ändringar.

Hur kan man tänka på annat sätt?


Alla tider är GMT +2. Klockan är nu 01:44.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson