Home > other >  Display xml values with namespace - using php
Display xml values with namespace - using php

Time:12-05

I would like to know how do I display these values from an api that returns me an xml. I've looked in some places, but it's always one without the namespace and others with namespace... but mine has both and it always bugs and doesn't display the values..

my xml:

<QTableGridDataSourceForMobileOfDocumentWBuH9k12 xmlns="http://schemas.datacontract.org/2004/07/Sinfic.DataContracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<TotalRows>1</TotalRows>
<Rows xmlns:a="http://schemas.datacontract.org/2004/07/Sinfic.DataContracts.Documents">
<a:Document>
<a:a>6017</a:a>
<a:aa>135</a:aa>
<a:ab>-23.15749833</a:ab>
<a:ac>-45.79356167</a:ac>
<a:ad>6.80</a:ad>
<a:ai>0</a:ai>
<a:aj>Administrator</a:aj>  
<a:am>32872</a:am>
<a:an>Leonardo Righi</a:an>
<a:ao>16470252</a:ao>
<a:ap>16470108</a:ap>
<a:aq>
<a:data>
<a:key>
<a:id>d0180056-f7e6-4b13-8865-a963a9a131</a:id>
<a:tag>nomeTecnico</a:tag>
</a:key>
<a:value>Denis Rodrigues</a:value>
</a:data>
<a:ar>
<a:data>
<a:key>
<a:id>d6052d01-92b3-45a5-9059-f401eddf0ef5</a:id>
<a:tag>ImageAnswer</a:tag>
</a:key>
<a:value>27422</a:value>
</a:data>
</a:ar>
<a:b>150</a:b>
<a:bb>Manutenção Automáticas</a:bb>
<a:bc>02 - CELULARES</a:bc>
<a:bd>Cancelado</a:bd>
<a:bf>09/03/2022 14:52</a:bf>
<a:bg>11/03/2022 15:00</a:bg>
<a:bh>Automaticas</a:bh>
<a:bi>5</a:bi>
<a:bj>09/03/2022 14:41</a:bj>
<a:bk>09/03/2022 14:52</a:bk>
<a:bq>LOGISTICA LTDA</a:bq>
<a:br>2</a:br>
<a:bs>2</a:bs>
<a:bt>false</a:bt>
<a:bu>MyDocs</a:bu>
<a:bv># 1.4.17[14017]</a:bv>
<a:by>f1edqKgAgFWvOHGTmEFw42uggIDQt-K8pKPFaC6Em-Z7etzLOSr3Al6eCPndbg2</a:by>        
<a:cd>656</a:cd>
<a:ce>13235</a:ce>
<a:l>DENIS </a:l>
<a:o>f8b521e8-e92f-478e-a883</a:o>
</a:Document>
</Rows>
</QTableGridDataSourceForMobileOfDocumentWBuH9k12>

I tried this code, as close as I got:

<?php
$x = simplexml_load_file('teste.xml');
$campos = $x->
children('a', true)->
children('a', true);


foreach($campos as $chave => $valor){

echo $chave.' : '. $valor . '<br>';
    
}

?>

CodePudding user response:

You can access the children by giving the namespace or its prefix. I prefer the prefix, because it is shorter.

Demo: https://3v4l.org/VNt5d

Note

Your data is still invalid. <a:aq> is not closed. So I removed it for my answer!

$xml = simplexml_load_string($xmlText);

foreach($xml->Rows->children('a', true) as $document) {
    foreach($document as $key => $value) {
        echo "$key: $value\n";
    }
}

Output

a: 6017
aa: 135
ab: -23.15749833
ac: -45.79356167
ad: 6.80
ai: 0
aj: Administrator
am: 32872
an: Leonardo Righi
ao: 16470252
ap: 16470108
data: 



ar: 


b: 150
bb: Manutenção Automáticas
bc: 02 - CELULARES
bd: Cancelado
bf: 09/03/2022 14:52
bg: 11/03/2022 15:00
bh: Automaticas
bi: 5
bj: 09/03/2022 14:41
bk: 09/03/2022 14:52
bq: LOGISTICA LTDA
br: 2
bs: 2
bt: false
bu: MyDocs
bv: # 1.4.17[14017]
by: f1edqKgAgFWvOHGTmEFw42uggIDQt-K8pKPFaC6Em-Z7etzLOSr3Al6eCPndbg2
cd: 656
ce: 13235
l: DENIS 
o: f8b521e8-e92f-478e-a883

CodePudding user response:

You mistake the namespaces prefixes with the actual namespace. The namespace definitions are the xmlns/xmlns:* attributes. Prefixes are optional for element nodes. The document element should be read as {http://schemas.datacontract.org/2004/07/Sinfic.DataContracts}QTableGridDataSourceForMobileOfDocumentWBuH9k12. Here are 3 examples that all resolve to this:

  • <QTableGridDataSourceForMobileOfDocumentWBuH9k12 xmlns="http://schemas.datacontract.org/2004/07/Sinfic.DataContracts">
  • <q:QTableGridDataSourceForMobileOfDocumentWBuH9k12 xmlns:q="http://schemas.datacontract.org/2004/07/Sinfic.DataContracts">
  • <qtable:QTableGridDataSourceForMobileOfDocumentWBuH9k12 xmlns:qtable="http://schemas.datacontract.org/2004/07/Sinfic.DataContracts">

Namespaces can be redefined on any element node. So a prefix will only be valid until redefined. That makes it a really bad idea to rely on the prefixes in the document. Always use the namespace URI and/or define your own prefixes.

SimpleXML does some implicit namespace handling in the background - like using the default namespace of the current context node. The explicit variant would look like this:

const XMLNS_CONTRACTS = 'http://schemas.datacontract.org/2004/07/Sinfic.DataContracts';
const XMLNS_DOCUMENT = 'http://schemas.datacontract.org/2004/07/Sinfic.DataContracts.Documents';

$qTable = simplexml_load_string(getXMLString());

foreach($qTable->children(XMLNS_CONTRACTS)->Rows->children(XMLNS_DOCUMENT) as $document) {
    foreach($document as $key => $value) {
        var_dump([$key, (string)$value]);
    }
} 

Or with DOM and Xpath:

Take note that the example uses its own prefixes for the Xpath expressions. It only depends on the namespace URIs.

const XMLNS_CONTRACTS = 'http://schemas.datacontract.org/2004/07/Sinfic.DataContracts';
const XMLNS_DOCUMENT = 'http://schemas.datacontract.org/2004/07/Sinfic.DataContracts.Documents';

$document = new DOMDocument();
$document->loadXML(getXMLString());
$xpath = new DOMXpath($document);
$xpath->registerNamespace('c', XMLNS_CONTRACTS);
$xpath->registerNamespace('d', XMLNS_DOCUMENT);

foreach ($xpath->evaluate('//c:Rows/d:Document') as $rowsDocument) {
    foreach($xpath->evaluate('./d:*', $rowsDocument) as $cell) {
        var_dump(
            [$cell->localName, $cell->textContent]
        );
    }
}

The XML format is not a good one imho - so it might feel annoying to use. XML tags are supposed to be fixed and semantic. Dynamic tag names a big no go.

  • Related