How to extract a chunk of an xml using PHP?

Asked

Viewed 305 times

1

How can I capture/return everything between tags <*:Body> and </*:Body> using PHP, so that it doesn’t matter how many lines there are before or after both tags?

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <ConsultarRequest>
   <Cliente>
    <sistema>XPTO</sistema>
   </Cliente>
   <numDDD>xx</numDDD>
   <numTerminal>xxxxxxxx</numTerminal>
  </ConsultarRequest>
 </soapenv:Body>
</soapenv:Envelope>

The final result I hope is:

  <ConsultarRequest>
   <Cliente>
    <sistema>XPTO</sistema>
   </Cliente>
   <numDDD>xx</numDDD>
   <numTerminal>xxxxxxxx</numTerminal>
  </ConsultarRequest>

Important: XML has a variable structure. In some cases within body there can be several values at the same level. Optionally I would like to do this via regex, interval tags <soapenv:body> and </soapenv:body>.

  • The code I posted uses Domxpath and Domxpath can be easily adapted to pick up any tag or variation from it.

1 answer

5


Don’t use Regex for that, not that it won’t work, but if anything changes in xml SOAP you will have to maintain your regex for sure, and until maintenance occurs everything will be broken.

What you can (and should preferably) use is DOMDocument+DOMXapth (or other DOM Apis for PHP), example that will solve your case:

<?php

$xml = '<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <ConsultarRequest>
   <Cliente>
    <sistema>XPTO</sistema>
   </Cliente>
   <numDDD>xx</numDDD>
   <numTerminal>xxxxxxxx</numTerminal>
  </ConsultarRequest>
 </soapenv:Body>
</soapenv:Envelope>';

$encontrou = false;

$doc = new DOMDocument;
$doc->loadxml($xml);

$xpath = new DOMXpath($doc);

//Registrado o namespace para que a query funcione com ele
$xpath->registerNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');

//O `//` busca o elemento <soapenv:Body> em QUALQUER parte do documento
$elementos = $xpath->query("//soapenv:Body");

//Verifica se retornou pelo menos um elemento
if ($elementos) {
    //Dentro <soapenv:Body> pega o primeiro elemento, que no seu exemplo é o `<ConsultarRequest>`, mas pode variar dependendo da resposta
    $node = $elementos[0]->getElementsByTagName('*')->item(0);

    //Se encontrar um elemento então entra na IF
    if ($node) {
        $encontrou = true;

        //Pega o conteudo do primeiro elemento, incluindo ele, e transforma em uma string
        $html = $node->ownerDocument->saveHTML( $node );

        echo 'Resultado:<br>';
        echo htmlentities($html); //O htmlentities é somente para você visualizar no navegador, ele é dispensável
    }
}

if (!$encontrou) {
    echo 'não foram encontrados elementos';
}

Whether to manipulate/read data from <ConsultarRequest> you may not need to turn into a string, or need the string for anything, the string itself DOMNode and DOMXpath will solve all your problems, for example:

<?php

$xml = '<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <ConsultarRequest>
   <Cliente>
    <sistema>XPTO</sistema>
   </Cliente>
   <numDDD>xx</numDDD>
   <numTerminal>xxxxxxxx</numTerminal>
  </ConsultarRequest>
 </soapenv:Body>
</soapenv:Envelope>';

$encontrou = false;

$doc = new DOMDocument;
$doc->loadxml($xml);

$xpath = new DOMXpath($doc);

$sistema = $xpath->query("//ConsultarRequest/Cliente/sistema");
$ddd = $xpath->query("//ConsultarRequest/numDDD");
$terminal = $xpath->query("//ConsultarRequest/numTerminal");

echo 'Sistema: ', $sistema[0]->nodeValue, '<br>';
echo 'ddd: ', $ddd[0]->nodeValue, '<br>';
echo 'Terminal: ', $terminal[0]->nodeValue, '<hr>';
  • This topic was opened to solve a problem I am having in this project: https://github.com/crphp/webservice, where by submitting to the Soap class (src/Soap.php) a literal xml is returned error, since __soapCall adds the same headers when firing the request...

  • @Fábiojânio you can adapt the Xpath as you wish, I gave you the way just you study and adapt to all your needs, even more if they are variants, understand the answer as the way and as a study for you. Actually, the first code I posted picks up something inside :Body, the second you can create querys for all situations and with Ifs go checking which is which.

  • Thank you. I have made the necessary adjustments. See: https://github.com/crphp/webservice/blob/master/src/Soap.php line 72 to 85

Browser other questions tagged

You are not signed in. Login or sign up in order to post.