Foros del Web » Programando para Internet » PHP »

Parsear xml con DomDocument

Estas en el tema de Parsear xml con DomDocument en el foro de PHP en Foros del Web. Necesito parsear unos xml que me devuelve un webservice. Encontré ésta clase que parsea los xml y funciona bien. Código PHP: class  MyDOMDocument  extends  DOMDocument ...
  #1 (permalink)  
Antiguo 07/09/2011, 03:29
Avatar de cluster28  
Fecha de Ingreso: enero-2008
Ubicación: Donostia - San Sebastián
Mensajes: 756
Antigüedad: 16 años, 3 meses
Puntos: 32
Parsear xml con DomDocument

Necesito parsear unos xml que me devuelve un webservice.

Encontré ésta clase que parsea los xml y funciona bien.

Código PHP:
class MyDOMDocument extends DOMDocument
{
    public function 
toArray(DOMNode $oDomNode null)
    {
        
// return empty array if dom is blank
        
if (is_null($oDomNode) && !$this->hasChildNodes()) {
            return array();
        }
        
$oDomNode = (is_null($oDomNode)) ? $this->documentElement $oDomNode;
        if (!
$oDomNode->hasChildNodes()) {
            
$mResult $oDomNode->nodeValue;
        } else {
            
$mResult = array();
            foreach (
$oDomNode->childNodes as $oChildNode) {
                
// how many of these child nodes do we have?
                // this will give us a clue as to what the result structure should be
                
$oChildNodeList $oDomNode->getElementsByTagName($oChildNode->nodeName); 
                
$iChildCount 0;
                
// there are x number of childs in this node that have the same tag name
                // however, we are only interested in the # of siblings with the same tag name
                
foreach ($oChildNodeList as $oNode) {
                    if (
$oNode->parentNode->isSameNode($oChildNode->parentNode)) {
                        
$iChildCount++;
                    }
                }
                
$mValue $this->toArray($oChildNode);
                
$sKey   = ($oChildNode->nodeName{0} == '#') ? $oChildNode->nodeName;
                
$mValue is_array($mValue) ? $mValue[$oChildNode->nodeName] : $mValue;
                
// how many of thse child nodes do we have?
                
if ($iChildCount 1) {  // more than 1 child - make numeric array
                    
$mResult[$sKey][] = $mValue;
                } else {
                    
$mResult[$sKey] = $mValue;
                }
            }
            
// if the child is <foo>bar</foo>, the result will be array(bar)
            // make the result just 'bar'
            
if (count($mResult) == && isset($mResult[0]) && !is_array($mResult[0])) {
                
$mResult $mResult[0];
            }
        }
        
// get our attributes if we have any
        
$arAttributes = array();
        if (
$oDomNode->hasAttributes()) {
            foreach (
$oDomNode->attributes as $sAttrName=>$oAttrNode) {
                
// retain namespace prefixes
                
$arAttributes["@{$oAttrNode->nodeName}"] = $oAttrNode->nodeValue;
            }
        }
        
// check for namespace attribute - Namespaces will not show up in the attributes list
        
if ($oDomNode instanceof DOMElement && $oDomNode->getAttribute('xmlns')) {
            
$arAttributes["@xmlns"] = $oDomNode->getAttribute('xmlns');
        }
        if (
count($arAttributes)) {
            if (!
is_array($mResult)) {
                
$mResult = (trim($mResult)) ? array($mResult) : array();
            }
            
$mResult array_merge($mResult$arAttributes);
        }
        
$arResult = array($oDomNode->nodeName=>$mResult);
        return 
$arResult;
    }

El problema viene cuando hay etiquetas con el mismo nombre. Sólo me devuelve una.

He estado haciendo pruebas pero no consigo resolverlo.

Código XML:
Ver original
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <epp xmlns="http://www.eurid.eu/xml/epp/epp-1.0" xmlns:domain="http://www.eurid.eu/xml/epp/domain-1.0" xmlns:extendedInfo="http://www.eurid.eu/xml/epp/extendedInfo-1.0">
  3.   <response>
  4.     <result code="1000">
  5.       <msg>Command completed successfully</msg>
  6.     </result>
  7.     <resData>
  8.       <domain:infData>
  9.         <domain:name>pruebas.eu</domain:name>
  10.         <domain:roid>5767282-EURID</domain:roid>
  11.         <domain:status s="ok"/>
  12.         <domain:registrant>c10470138</domain:registrant>
  13.         <domain:contact type="billing">c887112</domain:contact>
  14.         <domain:contact type="onsite">c10470137</domain:contact>
  15.         <domain:ns>
  16.           <domain:hostAttr>
  17.             <domain:hostName>dns1.loquemedelagana.com</domain:hostName>
  18.           </domain:hostAttr>
  19.           <domain:hostAttr>
  20.             <domain:hostName>dns2.loquemedelagana.com</domain:hostName>
  21.           </domain:hostAttr>
  22.         </domain:ns>
  23.         <domain:clID>t000657</domain:clID>
  24.         <domain:crID>t000657</domain:crID>
  25.         <domain:crDate>2010-06-01T15:12:33.000Z</domain:crDate>
  26.         <domain:upID>t000657</domain:upID>
  27.         <domain:upDate>2010-06-01T15:12:33.000Z</domain:upDate>
  28.         <domain:exDate>2012-06-30T21:59:59.999Z</domain:exDate>
  29.       </domain:infData>
  30.     </resData>
  31.     <extension>
  32.       <extendedInfo:infData>
  33.         <extendedInfo:onhold>false</extendedInfo:onhold>
  34.         <extendedInfo:quarantined>false</extendedInfo:quarantined>
  35.       </extendedInfo:infData>
  36.     </extension>
  37.     <trID>
  38.       <svTRID>eurid-0</svTRID>
  39.     </trID>
  40.   </response>
  41. </epp>

Por ejemplo <domain:contact>

Resultado:

Código HTML:
Array
(
    [epp] => Array
        (
            [0] => 

            [response] => Array
                (
                    [0] => 
  
                    [result] => Array
                        (
                            [0] => 
    
                            [msg] => Command completed successfully
                            [@code] => 1000
                        )

                    [resData] => Array
                        (
                            [0] => 
    
                            [domain:infData] => Array
                                (
                                    [0] => 
      
                                    [domain:name] => pruebas.eu
                                    [domain:roid] => 5767282-EURID
                                    [domain:status] => Array
                                        (
                                            [@s] => ok
                                        )

                                    [domain:registrant] => c10470138
           ------------------>[domain:contact] => Array
                                        (
                                            [0] => c10470137
                                            [@type] => onsite
                                        )

                                    [domain:ns] => Array
                                        (
                                            [0] => 
        
                                            [domain:hostAttr] => Array
                                                (
                                                    [0] => 
          
                                                    [domain:hostName] => dns2.loquemedelagana.com
                                                )

                                        )

                                    [domain:clID] => t000657
                                    [domain:crID] => t000657
                                    [domain:crDate] => 2010-06-01T15:12:33.000Z
                                    [domain:upID] => t000657
                                    [domain:upDate] => 2010-06-01T15:12:33.000Z
                                    [domain:exDate] => 2012-06-30T21:59:59.999Z
                                )

                        )

                    [extension] => Array
                        (
                            [0] => 
    
                            [extendedInfo:infData] => Array
                                (
                                    [0] => 
      
                                    [extendedInfo:onhold] => false
                                    [extendedInfo:quarantined] => false
                                )

                        )

                    [trID] => Array
                        (
                            [0] => 
    
                            [svTRID] => eurid-0
                        )

                )

            [@xmlns] => http://www.eurid.eu/xml/epp/epp-1.0
        )

)
Gracias.

SOLUCIÓN: quitar los : de las etiquetas. Pasa lo mismo que con simplexml.

Yo uso este código:

Código PHP:
//Arreglo de xml
        
$xml=preg_replace('|<([/\w]+)(:)|m','<$1',$xml);
        
$xml=preg_replace('|(\w+)(:)(\w+=\&quot;)|m','$1$3',$xml); 

Última edición por cluster28; 07/09/2011 a las 04:35 Razón: SOLUCIONADO
  #2 (permalink)  
Antiguo 07/09/2011, 05:50
Avatar de abimaelrc
Colaborador
 
Fecha de Ingreso: mayo-2009
Ubicación: En el planeta de Puerto Rico
Mensajes: 14.734
Antigüedad: 14 años, 11 meses
Puntos: 1517
Respuesta: Parsear xml con DomDocument

A las que tiene por ejemplo foo:bar se le conoce como namespace, y puedes parsearlo usando los métodos de namespace que brinda DOM o SimpleXML.
__________________
Verifica antes de preguntar.
Los verdaderos amigos se hieren con la verdad, para no perderlos con la mentira. - Eugenio Maria de Hostos
  #3 (permalink)  
Antiguo 07/09/2011, 06:22
Avatar de cluster28  
Fecha de Ingreso: enero-2008
Ubicación: Donostia - San Sebastián
Mensajes: 756
Antigüedad: 16 años, 3 meses
Puntos: 32
Respuesta: Parsear xml con DomDocument

Cita:
Iniciado por abimaelrc Ver Mensaje
A las que tiene por ejemplo foo:bar se le conoce como namespace, y puedes parsearlo usando los métodos de namespace que brinda DOM o SimpleXML.
Sí, gracias, ya sabía que son namespaces. Pero lo que quería es algo sencillo para transformarlo en array. Quitando los : del tag con el "truquillo" que indico, me sirve.
  #4 (permalink)  
Antiguo 07/09/2011, 06:43
Avatar de abimaelrc
Colaborador
 
Fecha de Ingreso: mayo-2009
Ubicación: En el planeta de Puerto Rico
Mensajes: 14.734
Antigüedad: 14 años, 11 meses
Puntos: 1517
Respuesta: Parsear xml con DomDocument

La forma limpia es usando los métodos que trabajan con el namespace. "Podría" en un futuro darte problemas lo que estás haciendo. Te recomiendo que reconsideres y trates de trabajar con los namespace.
__________________
Verifica antes de preguntar.
Los verdaderos amigos se hieren con la verdad, para no perderlos con la mentira. - Eugenio Maria de Hostos
  #5 (permalink)  
Antiguo 07/09/2011, 10:59
Avatar de andresdzphp
Colaborador
 
Fecha de Ingreso: julio-2011
Ubicación: $this->Colombia;
Mensajes: 2.749
Antigüedad: 12 años, 9 meses
Puntos: 793
Respuesta: Parsear xml con DomDocument

Las expresiones regulares no creo que sean la mejor forma de hacerlo, teniendo métodos para esto. Un par de ejemplos "básicos".

DOMDocument

Código PHP:
Ver original
  1. <?php
  2. $xml = file_get_contents('prueba.xml');
  3. $doc = new DOMDocument();
  4. $doc->loadXML($xml);
  5. $dom_pa = new DOMXPath($doc);
  6. $dom_pa->registerNamespace('d', $doc->lookupNamespaceUri('domain'));
  7. $resultado = $dom_pa->query('//d:contact');
  8. echo $contacto1 = $resultado->item(0)->nodeValue . '<br />';
  9. echo $contacto2 = $resultado->item(1)->nodeValue;

SimpleXMLElement

Código PHP:
Ver original
  1. $xml = file_get_contents('prueba.xml');
  2. $sp = new SimpleXMLElement($xml);
  3. $ns = $sp->getNamespaces(true);
  4. $sp->registerXPathNamespace('d', $ns['domain']);
  5. $contacto = $sp->xpath('//d:contact');
  6. echo $contacto[0] . '<br />';
  7. echo $contacto[1];

En el caso de querer los atributos usas getAttribute con DOMDocument o attribute con SimpleXML. Saludos
__________________
Si sabemos como leer e interpretar el manual será mucho más fácil aprender PHP. En lugar de confiar en ejemplos o copiar y pegar - PHP
  #6 (permalink)  
Antiguo 07/09/2011, 12:06
Avatar de andresdzphp
Colaborador
 
Fecha de Ingreso: julio-2011
Ubicación: $this->Colombia;
Mensajes: 2.749
Antigüedad: 12 años, 9 meses
Puntos: 793
Respuesta: Parsear xml con DomDocument

Me parece muy interesante DOMDocument, dejo otro ejemplo recorriendo todo el namespace domain usando getElementsByTagNameNS, basado en el XML del post.

Código PHP:
Ver original
  1. <?php
  2. $xml = file_get_contents('prueba.xml');
  3. $doc = new DOMDocument();
  4. $doc->loadXML($xml);
  5. $nodos = $doc->getElementsByTagNameNS($doc->lookupNamespaceUri('domain'), '*');
  6.  
  7. for ($i=0; $i<$nodos->length; $i++) {
  8.     echo $nodos->item($i)->nodeName . '<br />';
  9.     echo $nodos->item($i)->nodeValue . '<hr />';
  10. }
__________________
Si sabemos como leer e interpretar el manual será mucho más fácil aprender PHP. En lugar de confiar en ejemplos o copiar y pegar - PHP
  #7 (permalink)  
Antiguo 08/09/2011, 00:31
Avatar de cluster28  
Fecha de Ingreso: enero-2008
Ubicación: Donostia - San Sebastián
Mensajes: 756
Antigüedad: 16 años, 3 meses
Puntos: 32
Respuesta: Parsear xml con DomDocument

Gracias gente. Cuando tenga tiempo intentaré hacerlo de esa manera.

Etiquetas: domdocument, parsear, xml
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 09:23.