I'm trying to understand the basics of DOMXPath in PHP. I have an XML file that starts with what's below.
<?xml version="1.0"?>
<ListFinancialEventsResponse xmlns="http://mws.amazonservices.com/Finances/2015-05-01">
<ListFinancialEventsResult>
<FinancialEvents>
<ShipmentEventList>
<ShipmentEvent>
I'm trying to get the FinancialEvents tags using the below PHP with a few different xpath query attempts but neither works.
$file = file_get_contents('file.xml');
$dom = new DOMDocument();
$dom->loadXML($file);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('m','http://mws.amazonservices.com/Finances/2015-05-01');
$events = $xpath->query('FinancialEvents'); // Attempt 1
$events = $xpath->query('m:FinancialEvents');// Attempt 2
According to the docs, these should return all nodes with name 'FinancialEvents'. I know that it works if I use the below xpath query
$events = $xpath->query('//m:FinancialEvents');
So my question is, why don't my first 2 queries work? Isn't the element <FinancialEvents> also a node of the same name?
Thanks
Not tested but you could try:
$query='//ListFinancialEventsResult/FinancialEvents';
$events=$xp->query( $query );
if( !empty( $events ) && $events->length > 0 ){
foreach( $events as $event ){
echo $event->nodeValue;
}
}
I suspect that the first couple of queries do not return a nodelist is because you are effectively trying to find nodes FinancialEvents at root level ~ if you supplied a reference node ( which would be a DOMNode ListFinancialEventsResult )for the query then it would work.
Related
I am using xpath to find content from a epg-file, but for this source, my code simply won't work. And now i have come to the point that i cant solve this myself.
The XML looks like this (as you see, 2 namespaces, v3 and v31).
<?xml version="1.0" encoding="UTF-8"?>
<v3:schedule timestamp="2017-05-12T16:11:06.595Z" xmlns:v3="http://common.tv.se/schedule/v3_1">
<v3:from>2017-05-12T22:00:00.000Z</v3:from>
<v3:to>2017-05-13T22:00:00.000Z</v3:to>
...
<v3:contentList>
<v31:content timestamp="2017-05-12T16:11:06.595Z" xmlns:v31="http://common.tv.se/content/v3_1">
<v31:contentId>content.1375706-006</v31:contentId>
<v31:seriesId>series.40542</v31:seriesId>
<v31:seasonNumber>3</v31:seasonNumber>
<v31:episodeNumber>6</v31:episodeNumber>
<v31:numberOfEpisodes>8</v31:numberOfEpisodes>
<v31:productionYear>2017</v31:productionYear>
...
<v3:eventList>
<v31:event timestamp="2017-05-12T16:11:06.595Z" xmlns:v31="http://common.tv.se/event/v3_1">
<v31:eventId>event.26072881</v31:eventId>
<v31:channelId>channel.24</v31:channelId>
<v31:rerun>true</v31:rerun>
<v31:live>false</v31:live>
<v31:hidden>false</v31:hidden>
<v31:description/>
<v31:timeList>
<v31:time type="public">
<v31:startTime>2017-05-12T22:55:00.000Z</v31:startTime>
<v31:endTime>2017-05-12T23:55:00.000Z</v31:endTime>
<v31:duration>01:00:00:00</v31:duration>
</v31:time>
</v31:timeList>
<v31:contentIdRef>content.1375706-006</v31:contentIdRef>
<v31:materialIdRef>material.1010161108005267221</v31:materialIdRef>
<v31:previousEventList/>
<v31:comingEventList/>
</v31:event>
...
<v3:materialList>
<v31:material timestamp="2017-05-12T16:11:06.595Z" xmlns:v31="http://common.tv.se/material/v3_1">
<v31:materialId>material.1010161108005267221</v31:materialId>
<v31:contentIdRef>content.1375706-006</v31:contentIdRef>
<v31:materialType>tx</v31:materialType>
<v31:videoFormat>576i</v31:videoFormat>
<v31:audioList>
<v31:format language="unknown">stereo</v31:format>
</v31:audioList>
<v31:aspectRatio>16:9</v31:aspectRatio>
<v31:materialReferenceList>
</v31:materialReferenceList>
</v31:material>
...
And the "contentIdRef" is what keeps the different elements (event and material) together.
And i want to find all the data, based on contentIdRef.
I have used this (in php):
$parent = $this->xmldata->xpath('//v31:event/v31:contentIdRef[.="content.1375706-006"]/parent::*')
and i have also tried
$parent = $this->xmldata->xpath('//v31:event/v31:contentIdRef[.="content.1375706-006"]/parent::*/child::*');
But, the first alternative just (with print_r) returns v31:event "timestamp"
the second alternative returns 11 "simpleXMLobjects" that are empty ( why are they empty?? ), so based on the amount of objects, i think i have "hit the spot", but i can't find out why they are empty....
And yes, i have registered namespaces throughout my code ( i wish it was that simple ).
TLDR;
I want to 1. get all contentIds from first block (v3:contentList),
2. get all eventdata for each contentId,
3. get all materialdata for each content id...
I sincerely hope you can help :/
Did you register prefixes for the namespaces in the Xpath expressions? Always register your own prefixes for the namespaces you're using. PHP registers the namespace definition of the current context node by default. But this can change on any element node in the document and not all prefixes might be defined on the document element.
$schedule = new SimpleXMLElement($xml);
$schedule->registerXpathNamespace('s', 'http://common.tv.se/schedule/v3_1');
$schedule->registerXpathNamespace('e', 'http://common.tv.se/event/v3_1');
$events = $schedule->xpath(
'//e:event[e:contentIdRef = "content.1375706-006"]'
);
foreach ($events as $event) {
echo $event->asXml(), "\n\n";
}
Or with DOM:
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace('s', 'http://common.tv.se/schedule/v3_1');
$xpath->registerNamespace('e', 'http://common.tv.se/event/v3_1');
$events = $xpath->evaluate('//e:event');
foreach ($events as $event) {
echo $document->saveXml($event), "\n\n";
}
I read many stackoverflow question and I'm using this code but I don't know why this is not work.
Here is a code.
$url = 'http://m.cricbuzz.com/cricket-schedule';
$source = file_get_contents($url);
$doc = new DOMDocument;
#$doc->loadHTML($source);
$xpath = new DOMXPath($doc);
$classname = "list-group";
$events = $xpath->query("//*[contains(#class, '$classname')]");
var_dump($xpath);
Can you please check it why this is not working actually I want to get data from list-group
The code is correct. It correctly fetches a list of DOM nodes having the specified class attribute value into the $events variable:
$events = $xpath->query("//*[contains(#class, '$classname')]");
which is an instance of DOMNodeList. Next you should iterate the list and fetch the data you need from $events. For example, if you need the outer HTML for the nodes, use something like this:
foreach ($events as $e) {
printf("<<<<<\n%s\n>>>>>\n", $e->ownerDocument->saveXML($e));
}
P.S.: I would rename $events to $elements.
Having a real bugger of an Xpath issue. I am trying to match the nodes with a certain value.
Here is an example XML fragment.
http://pastie.org/private/xrjb2ncya8rdm8rckrjqg
I am trying to match a given MatchNumber node value to see if there are two or more. Assuming that this is stored in a variable called $data I am using the below expression. Its been a while since ive done much XPath as most thing seem to be JSON these days so please excuse any rookie oversights.
$doc = new DOMDocument;
$doc->load($data);
$xpath = new DOMXPath($doc);
$result = $xpath->query("/CupRoundSpot/MatchNumber[.='1']");
I need to basically match any node that has a Match Number value of 1 and then determine if the result length is greater than 1 ( i.e. 2 or more have been found ).
Many thanks in advance for any help.
Your XML document has a default namespace: xmlns="http://www.fixtureslive.com/".
You have to register this namespace on the xpath element and use the (registered) prefix in your query.
$xpath->registerNamespace ('fl' , 'http://www.fixtureslive.com/');
$result = $xpath->query("/fl:ArrayOfCupRoundSpot/fl:CupRoundSpot/fl:MatchNumber[.='1']");
foreach( $result as $e ) {
echo '.';
}
The following XPath:
/CupRoundSpot[MatchNumber = 1]
Returns all the CupRoundSpot nodes where MatchNumber equals 1. You could use these nodes futher in your PHP to do stuff with it.
Executing:
count(/CupRoundSpot[MatchNumber = 1])
Returns you the total CupRoundSpot nodes found where MatchNumber equals 1.
You have to register the namespace. After that you can use the Xpath count() function. An expression like that will only work with evaluate(), not with query(). query() can only return node lists, not scalar values.
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
$xpath->registerNamespace('fl', 'http://www.fixtureslive.com/');
var_dump(
$xpath->evaluate(
'count(/fl:ArrayOfCupRoundSpot/fl:CupRoundSpot[number(fl:MatchNumber) = 1])'
)
);
Output:
float(2)
DEMO: https://eval.in/130366
To iterate the CupRoundSpot nodes, just use foreach:
$nodes = $xpath->evaluate(
'/fl:ArrayOfCupRoundSpot/fl:CupRoundSpot[number(fl:MatchNumber) = 1]'
);
foreach ($nodes as $node) {
//...
}
PHP DOM is returning all the nodes even if I am in a specific tag. I have been trying to solve this thing for around 2 weeks now but no progress. Please help.
Here is my code:
$dom = new DOMDocument;
$dom->loadhtmlfile($url);
$doc=$dom->documentElement;
$res = $doc->getElementsByTagName('td')->item(54);
$tables = $res->getElementsByTagName('table'); //Here it returns every 'table', not just the ones which are under that 'td'
From the documentation: getElementsByTagName — Searches for all elements with given local tag name
If you want to find the table inside a 'td' element, use a XPath query.
$xpath = new DOMXpath($dom);
$tables = $xpath->query("//td/table");
I am loading HTML into DOM and then querying it using XPath in PHP. My current problem is how do I find out how many matches have been made, and once that is ascertained, how do I access them?
I currently have this dirty solution:
$i = 0;
foreach($nodes as $node) {
echo $dom->savexml($nodes->item($i));
$i++;
}
Is there a cleaner solution to find the number of nodes, I have tried count(), but that does not work.
You haven't posted any code related to $nodes so I assume you are using DOMXPath and query(), or at the very least, you have a DOMNodeList.
DOMXPath::query() returns a DOMNodeList, which has a length member. You can access it via (given your code):
$nodes->length
If you just want to know the count, you can also use DOMXPath::evaluate.
Example from PHP Manual:
$doc = new DOMDocument;
$doc->load('book.xml');
$xpath = new DOMXPath($doc);
$tbody = $doc->getElementsByTagName('tbody')->item(0);
// our query is relative to the tbody node
$query = 'count(row/entry[. = "en"])';
$entries = $xpath->evaluate($query, $tbody);
echo "There are $entries english books\n";