I have a xml response like that;
<n:Crev xmlns:soap="http://a.com"
xmlns:obj="http://b.com"
xmlns:n="http://c.com"
xmlns:msg="http://d.com"
xmlns="http://e.com"
xmlns:xsi="http://f.com"
xsi:schemaLocation="http://g.com">
<n:Header>
<msg:mydata>123123</msg:mydata>
</n:Header>
</n:Crev>
now I want to get 'msg:mydata' value..
I tried some xpaths but they didn't work and tried online xpath creator it gives something like;
'/n:Crev[#xmlns:soap="http://a.com"]/n:Header/msg:mydata/text()'
but it didn't work also.. So how can I write xpath for that?
Thanks
I've succeeded with following code:
<?php
$xmlStr = '<n:Crev xmlns:soap="http://a.com"
xmlns:obj="http://b.com"
xmlns:n="http://c.com"
xmlns:msg="http://d.com"
xmlns="http://e.com"
xmlns:xsi="http://f.com"
xsi:schemaLocation="http://g.com">
<n:Header>
<msg:mydata>123123</msg:mydata>
</n:Header>
</n:Crev>';
$xmlDoc = new DOMDocument();
$xmlDoc->loadXML($xmlStr);
$xmlPath = new DOMXPath($xmlDoc);
var_dump($xmlPath->query('//n:Crev/n:Header/msg:mydata')->item(0)->textContent);
result:
string '123123' (length=6)
n or msg are namespace prefixes. The actual namespaces are the values of the xmlns attributes. The XML parser will resolve the namespaces.
Here is a small example:
$document = new DOMDocument();
$document->loadXml('<n:Crev xmlns:n="http://c.com"/>');
var_dump(
$document->documentElement->namespaceURI,
$document->documentElement->localName
);
Output:
string(12) "http://c.com"
string(4) "Crev"
The following XMLs all would have the same output:
<n:Crev xmlns:n="http://c.com"/>
<Crev xmlns="http://c.com"/>
<c:Crev xmlns:c="http://c.com"/>
You can read the node as {http://c.com}Crev.
To fetch nodes or scalar values from the DOM you can use Xpath::evaluate(). But to match namespaces you will have to register prefixes for the Xpath expressions. This allows the Xpath engine to resolve the namespaces and match them against the node properties. The prefixes do not have to be the same as in the document.
$xml = <<<'XML'
<n:Crev xmlns:n="http://c.com" xmlns:msg="http://d.com">
<n:Header>
<msg:mydata>123123</msg:mydata>
</n:Header>
</n:Crev>
XML;
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace('c', 'http://c.com');
$xpath->registerNamespace('msg', 'http://d.com');
var_dump(
$xpath->evaluate('string(/c:Crev/c:Header/msg:mydata)')
);
Output:
string(6) "123123"
If the expression is an location path like /c:Crev/c:Header/msg:mydata the result with be an DOMNodeList, but Xpath functions or operators can return scalar values.
Related
So my XML Looks like this :-
<ns0:ASN xmlns:ns0="http://schemas.microsoft.com/dynamics/2008/01/documents/ASN" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:CustPackingSlipJour class="entity">
<ns0:BON_FileNameSeqNum>40</ns0:BON_FileNameSeqNum>
<ns0:BON_TotalNetAmount>10.00</ns0:BON_TotalNetAmount>
<ns0:BON_TotalTaxAmount>.00</ns0:BON_TotalTaxAmount>
<ns0:InvoiceAccount>Acc</ns0:InvoiceAccount>
<ns0:LanguageId>EN</ns0:LanguageId>
<ns0:OrderAccount>I</ns0:OrderAccount>
<ns0:PurchaseOrder>74</ns0:PurchaseOrder>
<ns0:Qty>13.00</ns0:Qty>
<ns0:SalesId>00025873_054</ns0:SalesId>
<ns0:CustPackingSlipTrans class="entity">
<ns0:BON_LineNetAmount>19.00</ns0:BON_LineNetAmount>
<ns0:BON_SalesPrice>0.00</ns0:BON_SalesPrice>
<ns0:DeliveryDate>2016-11-30</ns0:DeliveryDate>
<ns0:ItemId>25712</ns0:ItemId>
<ns0:Ordered>1.00</ns0:Ordered>
<ns0:PackingSlipId>00339_061</ns0:PackingSlipId>
<ns0:Qty>1.00</ns0:Qty>
</ns0:CustPackingSlipTrans>
<ns0:CustPackingSlipTrans class="entity">
<ns0:BON_LineNetAmount>19.00</ns0:BON_LineNetAmount>
<ns0:BON_SalesPrice>0.00</ns0:BON_SalesPrice>
<ns0:DeliveryDate>2-11-30</ns0:DeliveryDate>
<ns0:ItemId>25823-35714</ns0:ItemId>
<ns0:Ordered>1.00</ns0:Ordered>
<ns0:PackingSlipId>00_061</ns0:PackingSlipId>
<ns0:Qty>1.00</ns0:Qty>
</ns0:CustPackingSlipTrans>
</ns0:CustPackingSlipJour>
</ns0:ASN>
How can I access the value of ItemId for all CustPackingSlipTrans ?
I have tried various ways of getting it, for instance registering xpath and then trying to access. However, it ins't working for me. Whats the best way to get it's value?
The solution using DOMXPath::query method:
// $xml contains your xml contents
$doc = new \DOMDocument();
$doc->loadXML($xml);
$xpath = new \DOMXPath($doc);
foreach ($xpath->query("ns0:CustPackingSlipJour/ns0:CustPackingSlipTrans/ns0:ItemId") as $node) {
var_dump($node->nodeValue);
}
The output:
string(5) "25712"
string(11) "25823-35714"
DEMO
You need to register the namespace with the DomXPath:
$xp = new DomXPath ($doc);
$xp->registerNamespace ('pfx', 'http://pfxuri');
I'm trying to parse a remote XML file, which is valid:
$xml = simplexml_load_file('http://feeds.feedburner.com/HammersInTheHeart?format=xml');
The root element is feed, and I'm trying to grab it via:
$nodes = $xml->xpath('/feed'); //also tried 'feed', without slash
Except it doesn't find any nodes.
print_r($nodes); //empty array
Or any nodes of any kind, so long as I search for them by tag name, in fact:
$nodes = $xml->xpath('//entry');
print_r($nodes); //empty array
It does find nodes, however, if I use wildcards, e.g.
$nodes = $xml->xpath('/*/*[4]');
print_r($nodes); //node found
What's going on?
Unlike DOM, SimpleXML has no concept of a document object, only elements. So if you load an XML you always get the document element.
$feed = simplexml_load_file($xmlFile);
var_dump($feed->getName());
Output:
string(4) "feed"
That means that all Xpath expression have to to be relative to this element or absolute. Simple feed will not work because the context already is the feed element.
But here is another reason. The URL is an Atom feed. So the XML elements in the namespace http://www.w3.org/2005/Atom. SimpleXMLs magic syntax recognizes a default namespace for some calls - but Xpath does not. Here is not default namespace in Xpath. You will have to register them with a prefix and use that prefix in your Xpath expressions.
$feed = simplexml_load_file($xmlFile);
$feed->registerXpathNamespace('a', 'http://www.w3.org/2005/Atom');
foreach ($feed->xpath('/a:feed/a:entry[position() < 3]') as $entry) {
var_dump((string)$entry->title);
}
Output:
string(24) "Sharing the goals around"
string(34) "Kouyate inspires Hammers' comeback"
However in SimpleXML the registration has to be done for each object you call the xpath() method on.
Using Xpath with DOM is slightly different but a lot more powerful.
$document = new DOMDocument();
$document->load($xmlFile);
$xpath = new DOMXpath($document);
$xpath->registerNamespace('a', 'http://www.w3.org/2005/Atom');
foreach ($xpath->evaluate('/a:feed/a:entry[position() < 3]') as $entry) {
var_dump($xpath->evaluate('string(a:title)', $entry));
}
Output:
string(24) "Sharing the goals around"
string(34) "Kouyate inspires Hammers' comeback"
Xpath expression using with DOMXpath::evaluate() can return scalar values.
I have some problems with make query to the XPath. I try to load WSDL file and them get some nodes using XPath.
$DOMDocument = new DOMDocument();
$DOMDocument->loadXML($wsdl);
$DOMXpath = new DOMXPath($DOMDocument);
$elements = $DOMXpath->query('//definitions//binding');
var_dump($elements);
Result is:
class DOMNodeList#15 (1) {
public $length =>
int(0)
}
Here is WSDL file: http://pastebin.com/YDRzbq3x
How to make correct XPath query to traversing over nodes.
Your XML has default namespace (xmlns="http://schemas.xmlsoap.org/wsdl/"). In this case, you need to register a prefix that point to that default namespace URI, then use that prefix in your XPath query :
.......
$DOMXpath->registerNamespace('d', "http://schemas.xmlsoap.org/wsdl/");
$elements = $DOMXpath->query('//d:definitions//d:binding');
.......
I'm trying to parse an xml data that I'm getting via an api call. I can use file_get_contents to read into a string but simpleXML_load_string seems to fail to read it. I can save it to a file and then simpleXML_load_file works. But I would rather not write the contents to a file. I can't seem to understand how to use DOM or XMLParse with this either. I'm new to PHP and parsing XML. The output data from the api call is below.
<Search>
<DS_Rating>DS3</DS_Rating>
<Overall>17.5</Overall>
<LargestGiftLow>0</LargestGiftLow>
<LargestGiftHigh>0</LargestGiftHigh>
<EstimatedCapacityRange>I - $15,000 - $24,999</EstimatedCapacityRange>
<EstimatedCapacity>20452</EstimatedCapacity>
<RealEstateEst>270073</RealEstateEst>
<RealEstateCount>1</RealEstateCount>
<LikelyMatchesCount>0</LikelyMatchesCount>
<LikelyMatchesTotal>0</LikelyMatchesTotal>
<FndBoard></FndBoard>
<GSBoard></GSBoard>
<PoliticalLikelyCount>0</PoliticalLikelyCount>
<PoliticalLikelyTotal>0</PoliticalLikelyTotal>
<BusinessRevenues>0</BusinessRevenues>
<SECStockValue>0</SECStockValue>
<SECInsider></SECInsider>
<MarketGuide></MarketGuide>
<IRS990PF></IRS990PF>
<RealEstateTrust></RealEstateTrust>
<MarketGuideComp>0</MarketGuideComp>
<MarketGuideOptions>0</MarketGuideOptions>
<BusinessAffiliation></BusinessAffiliation>
<Pension></Pension>
<PensionAssets>0</PensionAssets>
<CorpTech></CorpTech>
<Pilot></Pilot>
<AirplaneOwner></AirplaneOwner>
<Boat></Boat>
<submit_time>2014-03-11 15:48:45</submit_time>
</Search>
Figured out that the issue was that what I was seeing in the browser was actually a php output with html_entiity encoded. I was able to process it with the code below which let me load it with simplexml.
$rawxml = html_entity_decode($rawxml);
$rawxml = str_replace(array(' ', "<pre>"), '', $rawxml);
$rawxml = utf8_encode($rawxml);
$xml = simplexml_load_string($rawxml);
If you XML is in a file use
simplexml_load_file
if you have it in a string use
simplexml_load_string
Then you can use the following code to access it.
<?php
$yourxml = simplexml_load_file('your.xml');
echo $yourxml->search[0]->DS_Rating;
?>
This would then output
DS3
to the browser via the 'echo' in your code. I hope this points you in the correct direction.
Try to use this:
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" ?>'.$yourXMLString);
In DOM you load the XML into a DOMDocument and create a DOMXpath instance for it.
$dom = new DOMDocument();
$dom->loadXml($xmlString);
//$dom->load($xmlFile);
$xpath = new DOMXpath($dom);
DOMXpath::evaluate() is used to fetch data from the DOM.
$rating = $dom->evaluate('string(/Search/DS_Rating)');
An Xpath expression like /Search/DS_rating always returns a node list. You can use foreach() to iterate it. The string() function in Xpath takes the first node from the list and casts it into a string. If here is not node in the list the result is an empty string.
$xmlString = <<<'XML'
<Search>
<DS_Rating>DS3</DS_Rating>
<Overall>17.5</Overall>
</Search>
XML;
$dom = new DOMDocument();
$dom->loadXml($xmlString);
$xpath = new DOMXpath($dom);
var_dump(
$xpath ->evaluate('string(/Search/DS_Rating)')
);
Output: https://eval.in/118921
string(3) "DS3"
I'd like to search for nodes with the same node name in a SimpleXML Object no matter how deep they are nested and create an instance of them as an array.
In the HTML DOM I can do that with JavaScript by using getElementsByTagName(). Is there a way to do that in PHP as well?
Yes use xpath
$xml->xpath('//div');
Here $xml is your SimpleXML object.
In this example you will get array of all 'div' elements
$fname = dirname(__FILE__) . '\\xml\\crRoll.xml';
$dom = new DOMDocument;
$dom->load($fname, LIBXML_DTDLOAD|LIBXML_DTDATTR);
$root = $dom->documentElement;
$xpath = new DOMXpath($dom);
$xpath->registerNamespace('cr', "http://www.w3.org/1999/xhtml");
$candidateNodes = $xpath->query("//cr:break");
foreach ($candidateNodes as $child) {
$max = $child->getAttribute('tstamp');
}
This finds all the BREAK nodes (tstamp attr) using XPath ...
Only on DOMDocument::getElementsByTagName,
however, you can import/export SimpleXML into DOMDocument,
or simply use DOMDocument to parse XML.
Another answer mentioned about Xpath,
it will return duplication of node, if you have something like :-
<div><div>1</div></div>