2011-12-19 5 views
7

Ho bisogno di restituire un oggetto SimpleXML convertito come oggetto JSON per lavorare con esso in JavaScript. Il problema è che non ci sono attributi su alcun oggetto con un valore.Disappearing attributi in PHP SimpleXML Object?

Ad esempio:

<customer editable="true" maxChars="9" valueType="numeric">69236</customer> 

diventa nell'oggetto SimpleXML:

"customer":"69236" 

Dove è l'oggetto @attributes?

risposta

-1

Ecco un codice per scorrere gli attributi e costruire JSON. Se supporta, uno o più clienti.

Se siete XML assomiglia a questo (o un solo cliente)

<xml> 
<customer editable="true" maxChars="9" valueType="numeric">69236</customer> 
<customer editable="true" maxChars="9" valueType="numeric">12345</customer> 
<customer editable="true" maxChars="9" valueType="numeric">67890</customer> 
</xml> 

Scorrere in questo modo.

try { 
    $xml = simplexml_load_file("customer.xml"); 

    // Find the customer 
    $result = $xml->xpath('/xml/customer'); 

    $bFirstElement = true; 
    echo  "var customers = {\r\n"; 
    while(list(, $node) = each($result)) { 
     if($bFirstElement) { 
      echo "'". $node."':{\r\n"; 
      $bFirstElement = false; 
     } else { 
      echo ",\r\n'". $node."':{\r\n"; 
     } 

     $bFirstAtt = true; 
     foreach($node->attributes() as $a => $b) { 
      if($bFirstAtt) { 
       echo "\t".$a.":'".$b."'"; 
       $bFirstAtt = false; 
      } else { 
       echo ",\r\n\t".$a.":'".$b."'"; 
      } 
     } 
     echo "}"; 
    } 
    echo "\r\n};\r\n"; 
} catch(Exception $e) { 
    echo "Exception on line ".$e->getLine()." of file ".$e->getFile()." : ".$e->getMessage()."<br/>"; 
} 

per produrre una struttura JSON come questo

var customers = { 
'69236':{ 
    editable:'true', 
    maxChars:'9', 
    valueType:'numeric'}, 
'12345':{ 
    editable:'true', 
    maxChars:'9', 
    valueType:'numeric'}, 
'67890':{ 
    editable:'true', 
    maxChars:'9', 
    valueType:'numeric'} 
}; 

Infine, nello script, accedere all'attributo come questo

WScript.Echo(customers["12345"].editable); 

Buona fortuna

7

Questo ha spinto me crazy in diverse occasioni. Quando SimpleXML incontra un nodo che ha solo un valore di testo, elimina tutti gli attributi. La mia soluzione è stata quella di modificare l'XML prima di analizzare con SimpleXML. Con un po 'di espressioni regolari, puoi creare un nodo figlio che contiene il valore di testo attuale. Ad esempio, nella vostra situazione è possibile modificare il codice XML per:

<customer editable="true" maxChars="9" valueType="numeric"><value>69236<value></customer> 

qualche esempio di codice supponendo che la stringa di XML era in $ str:

$str = preg_replace('/<customer ([^>]*)>([^<>]*)<\/customer>/i', '<customer $1><value>$2</value></customer>', $str); 
$xml = @simplexml_load_string($str); 

che preservasse gli attributi e nido il valore del testo in un nodo figlio.

+1

Questo non riesce se non v'è per esempio un blocco CDATA nell'elemento, in questo modo:

+0

Per me, la soluzione era chiamare esplicitamente '-> children()' durante il loop dell'oggetto xml. Se non l'avessi fatto, gli attributi erano spariti. –

3

Mi rendo conto che questo è un vecchio post, ma nel caso si rivelasse utile. Il sotto estende la soluzione di @ ryanmcdonnell per funzionare su qualsiasi tag invece che su un tag hard-coded. Spero che aiuti qualcuno.

$str = preg_replace('/<([^ ]+) ([^>]*)>([^<>]*)<\/\\1>/i', '<$1 $2><value>$3</value></$1>', $result); 

Il principale diversa è che sostituisce /<customer con /<([^ ]+), e poi </customer> con </\\1>

che racconta in modo che corrisponda quella parte della ricerca contro il primo elemento del modello.

Quindi regola solo i segnaposto ($1, $2, $3) per tenere conto del fatto che ora ci sono tre sottotitoli invece di due.

+1

Anche questo non funziona se esiste un blocco CDATA nell'elemento, ad esempio:

0

È una vecchia domanda, ma ho trovato qualcosa che funziona in ordine - analizzarlo in un oggetto DOMNode.

// $customer contains the SimpleXMLElement 
$customerDom = dom_import_simplexml($customer); 
var_dump($customerDom->getAttribute('numeric')); 

mostrerà:

string 'numeric'