I have an XML file similar to the text below:
<?xml version="1.0" standalone="yes"?>
<Calendar xmlns="urn:AvmInterchangeSchema-Calendario-1.0">
<Date>
<Day>12/04/2017</Day>
<TypesDay>
<Type>Test 1</Type>
<Type>Test 2</Type>
<Type>Test 3</Type>
</TypesDay>
</Date>
</Calendar>
And I am using this Xpath to select the nodes:
$xml = simplexml_load_file("file.xml");
$response = $xml->xpath('//*[text()="'.date("d/m/Y").'"]');
How can I take the "TypesDay" entries if that condition is met?
I hope not to create duplicates ... I'm going crazy for hours and it will definitely be a trivial thing.
There are a few approaches to do this. First of all, you should register the namespace:
$xml->registerXPathNamespace('x', 'urn:AvmInterchangeSchema-Calendario-1.0');
I'm assuming that your node name with the value 12/04/2017 could change.
First
Find a node called TypesDay inside the named namespace x that the parent node has a child node with value 12/04/2017
$response = $xml->xpath('//*[*[text()="'.date("d/m/Y").'"]]/x:TypesDay');
Second
Find a node called TypesDay inside the named namespace x that is sibling of node with value 12/04/2017
$response = $xml->xpath('//*[text()="'.date("d/m/Y").'"]/following-sibling::x:TypesDay');
The result for both is:
array(1) {
[0]=>
object(SimpleXMLElement)#2 (1) {
["Type"]=>
array(3) {
[0]=>
string(6) "Test 1"
[1]=>
string(6) "Test 2"
[2]=>
string(6) "Test 3"
}
}
}
After all, if you want only the entries, just add the next level /x:Type:
$response = $xml->xpath('//*[*[text()="'.date("d/m/Y").'"]]/x:TypesDay/x:Type');
Or:
$response = $xml->xpath('//*[text()="'.date("d/m/Y").'"]/following-sibling::x:TypesDay/x:Type');
Result:
array(3) {
[0]=>
object(SimpleXMLElement)#3 (1) {
[0]=>
string(6) "Test 1"
}
[1]=>
object(SimpleXMLElement)#4 (1) {
[0]=>
string(6) "Test 2"
}
[2]=>
object(SimpleXMLElement)#5 (1) {
[0]=>
string(6) "Test 3"
}
}
Related
Does anybody know why SimpleXMLElement is removing the attributes in my XML??
I have XML data that looks like this (note the translation "language" attribute):
<events>
<event id="d8f17143-0c67-48aa-a7f1-003a5ddbd28f">
<details>
<names>
<translation language="en">English title</translation>
<translation language="de">German title</translation>
</names>
</details>
</event>
</events>
I run it through SimpleXmlElement like so:
$xmlConvertedData = new \SimpleXMLElement($xml);
I dump out the data and it looks like so:
object(SimpleXMLElement)#958 (2) {
["#attributes"]=>
array(1) {
["Index"]=>
string(1) "1"
}
["Events"]=>
object(SimpleXMLElement)#956 (1) {
["Event"]=>
array(1) {
[0]=>
object(SimpleXMLElement)#959 (1) {
["Details"]=>
object(SimpleXMLElement)#826 (13) {
["Names"]=>
object(SimpleXMLElement)#834 (1) {
["Translation"]=>
array(2) {
[0]=>
string(32) "English title"
[1]=>
string(33) "German title"
}
}
}
}
}
}
}
...notice "translation" no longer has a "language" attribute, just an ID number 0 and 1. I need to know the attribute value because the XML does not always show the same language first.
(I edited the shortened the sample code to one record, so please ignore the #958 part)
Do not use any of the print_r() or var_dump() on a SimpleXML object, this will abbreviate the output as there is potentially a lot of it. If you want to check the document loaded use asXML()...
echo $xmlConvertedData->asXML();
or to output the one elements language...
echo $xmlConvertedData->event[0]->details->names->translation['language'];
( You also need to correct the last element of the sample - </events>)
I'm trying to create database of new releases from boomkat.com RSS feed. Feed is located here:
link
Now, I'm having issues with selection of stuff inside paragraph tags.
One paragraph in RSS feed looks like this:
<p>GOAT<br/>World Music<br/>ROCKET RECORDINGS<br/>INDIE / ROCK / ALTERNATIVE<br/>MP3 Release</p>
What I did so far is this:
<?php
$dom = new DOMDocument;
$dom->validateOnParse = true;
$dom->load("http://feeds.boomkat.com/boomkat_downloads_just_arrived");
$content = $dom->getElementsByTagName('content');
foreach ($content as $result) {
echo $result->nodeValue, PHP_EOL;
}
?>
But that gives me whole feed. Writing 'p' in getElementsByTagName doesn't work.
I would suggest using DOMDocument::loadHTMLFile() method instead of DOMDocument::load() (as load() is strictly for reading XML, not HTML).
The reason why you're getting the whole document, is because you are querying the entire document for a element called "content". There is no such HTML element. Instead you should be using
$dom->getElementsByTagName('p');
This will grab all the tags in the HTML document, and then you can loop over that. The primary reason why querying tags with "p" doesn't work, is because you need to load the document as strict HTML, and not use the default XML.
OK, well I don't understand why you're having problems, but I just tried what I suggested with the URL you provided, and got a proper print out of all the text of each <p> tag.
Here's the code:
$doc = new DOMDocument();
$doc->loadHTMLFile("http://boomkat.com/downloads/601228-goat-world-music");
$content = $doc->getElementsByTagName("p");
foreach($content as $element) {
Util::debug($element->textContent); // helper method similar to PHP's var_dump()
}
Here's the results I was able to print to the screen:
string(91) "Residual Echoes have come up with a really rather lovely disc of psychedelic folk goodness."
string(8) "MAMMATUS"
string(8) "Mammatus"
string(17) "ROCKET RECORDINGS"
string(45) "MP3 Download // £2.95FLAC Download // £3.95"
string(0) ""
string(19) "SERPENTINA SATELITE"
string(16) "Mecanica Celeste"
string(17) "ROCKET RECORDINGS"
string(45) "MP3 Download // £3.95FLAC Download // £4.95"
string(0) ""
string(12) "SUNCOIL SECT"
string(25) "One Note Obscures Another"
string(17) "ROCKET RECORDINGS"
string(45) "MP3 Download // £6.99FLAC Download // £7.99"
string(0) ""
string(16) "TEETH OF THE SEA"
string(10) "Hypnoticon"
string(17) "ROCKET RECORDINGS"
string(45) "MP3 Download // £2.50FLAC Download // £3.50"
string(52) "Proggy kosmiche rock from London's Teeth Of The Sea."
string(16) "TEETH OF THE SEA"
string(21) "Orphaned By the Ocean"
string(17) "ROCKET RECORDINGS"
string(45) "MP3 Download // £5.99FLAC Download // £6.99"
Was this something you were doing in the code?
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
A simple program to CRUD node and node values of xml file
How would I get a specific Attribute out of this XML feed?
Example - I have been using a line similar to this to get other XML details but I am unsure how I could change it to get a specific Attribute.
$mainPropertyDetails = $mainPropertyUrl->Attributes->attribute;
Attributes:
<Attributes>
<Attribute>
<Name>bedrooms</Name>
<DisplayName>Bedrooms</DisplayName>
<Value>4 bedrooms</Value>
</Attribute>
<Attribute>
<Name>bathrooms</Name>
<DisplayName>Bathrooms</DisplayName>
<Value>2 bathrooms</Value>
</Attribute>
<Attribute>
<Name>property_type</Name>
<DisplayName>Property type</DisplayName>
<Value>House</Value>
</Attribute>
SimpleXML implements these nodes as an array. If you were to var_dump() this, you would see something like:
// Dump the whole Attributes array
php > var_dump($xml->Attributes);
object(SimpleXMLElement)#6 (1) {
["Attribute"]=>
array(3) {
[0]=>
object(SimpleXMLElement)#2 (3) {
["Name"]=>
string(8) "bedrooms"
["DisplayName"]=>
string(8) "Bedrooms"
["Value"]=>
string(10) "4 bedrooms"
}
[1]=>
object(SimpleXMLElement)#5 (3) {
["Name"]=>
string(9) "bathrooms"
["DisplayName"]=>
string(9) "Bathrooms"
["Value"]=>
string(11) "2 bathrooms"
}
[2]=>
object(SimpleXMLElement)#3 (3) {
["Name"]=>
string(13) "property_type"
["DisplayName"]=>
string(13) "Property type"
["Value"]=>
string(5) "House"
}
}
}
It is therefore just a matter of accessing specific ones by their array index:
// Get the second Attribute node
var_dump($xml->Attributes[0]->Attribute[1]);
object(SimpleXMLElement)#6 (3) {
["Name"]=>
string(9) "bathrooms"
["DisplayName"]=>
string(9) "Bathrooms"
["Value"]=>
string(11) "2 bathrooms"
}
Get the Attribute node based on a child's value:
Using xpath() you can query for the parent Attribute node based on a child's text value:
// Get the Attribute containing the Bathrooms DisplayName
// Child's text value is queried via [AttrName/text()="value"]
var_dump($xml->xpath('//Attributes/Attribute[DisplayName/text()="Bathrooms"]');
array(1) {
[0]=>
object(SimpleXMLElement)#6 (3) {
["Name"]=>
string(9) "bathrooms"
["DisplayName"]=>
string(9) "Bathrooms"
["Value"]=>
string(11) "2 bathrooms"
}
}
I think I'm missing something really obvious here, but can someone explain to me why I'm getting the output I am and not the output I expect on the following var dumps:
Here's the original xml:
<result>
<category>
<id>3</id>
<name>Category 1</name>
<subcategory>
<id>9</id>
<name>SubCat 1</name>
</subcategory>
<subcategory>
<id>10</id>
<name>SubCat 2</name>
</subcategory>
<subcategory>
<id>11</id>
<name>SubCat 3</name>
</subcategory>
</category>
</result>
What I am doing:
$xml = new SimpleXMLElement($file);
foreach($xml->category as $node)
{
echo "dump 1:
";
var_dump($node);
echo "**********************************************
dump 2:
";
var_dump($node->subcategory);
die();
}
This outputs:
dump 1:
object(SimpleXMLElement)#130 (3) {
["id"]=>
string(1) "3"
["name"]=>
string(10) "Category 1"
["subcategory"]=>
array(3) {
[0]=>
object(SimpleXMLElement)#133 (2) {
["id"]=>
string(1) "9"
["name"]=>
string(8) "SubCat 1"
}
[1]=>
object(SimpleXMLElement)#135 (2) {
["id"]=>
string(2) "10"
["name"]=>
string(8) "SubCat 2"
}
[2]=>
object(SimpleXMLElement)#136 (2) {
["id"]=>
string(2) "11"
["name"]=>
string(8) "SubCat 3"
}
}
}
**********************************************
dump 2:
object(SimpleXMLElement)#138 (2) {
["id"]=>
string(1) "9"
["name"]=>
string(8) "SubCat 1"
}
The first var dump outputs what I'd expect, but the output I would expect for the second var_dump would be:
array(3) {
[0]=>
object(SimpleXMLElement)#133 (2) {
["id"]=>
string(1) "9"
["name"]=>
string(8) "SubCat 1"
}
[1]=>
object(SimpleXMLElement)#135 (2) {
["id"]=>
string(2) "10"
["name"]=>
string(8) "SubCat 2"
}
[2]=>
object(SimpleXMLElement)#136 (2) {
["id"]=>
string(2) "11"
["name"]=>
string(8) "SubCat 3"
}
}
Or even an object containing all the array items. Why is this not the case?
I can see when I call var_dump($node->subcategory) it's dumping the first 'subcategory' node that it finds, but why then does it cast all the 'subcategory' nodes to an array for the first var dump but not for the second? And how would I mimic this behaviour to detect if 'subcategory' contains more than one object (as it does in the first var dump)?
Basically what I'm trying to do is detect if a property of the SimpleXMLElement contains an array of more values (i.e. if it contains child nodes)
I've tried all sorts, but I can't seem to detect if one of the properties of the simpleXml object contains a set of arrays.
Update:
I found this works:
if(count($node->subcategory)>1)
{
// we have more than one subcategory
}
But it's not the most elegant way, I'm sure there must be a cleaner method?
This property is object of iterarator:
$node->subcategory
And if you need to get all items try:
foreach($xml->category as $node)
{
...
foreach($node->subcategory as $subcategory)
{
$data[] = (array) $subcategory
}
...
}
If you need to know count of subcategory items you successfully used count-method.
And you may use xpath if will not change XML tree:
$categories = $xml->xpath('/category/subcategory');
var_dump($categories)
Adjust your xml file:
<result>
<category>
<id>3</id>
<name>Category 1</name>
<subcategories>
<subcategory>
<id>9</id>
<name>SubCat 1</name>
</subcategory>
<subcategory>
<id>10</id>
<name>SubCat 2</name>
</subcategory>
<subcategory>
<id>11</id>
<name>SubCat 3</name>
</subcategory>
</subcategories>
</category>
</result>
And try:
var_dump($node->subcategories);
I have seen several similar questions, but not found the exact answer I'm looking for. It may be that the functionality I am looking for does not exist.
If I do an xpath query that results in an array of objects, but each object only holds one value, a string, I'd like to quickly convert that into an array of strings. Obviously I can do a foreach on the object and push the string value onto a new array, but if there is a built in function I'm not thinking of, please let me know.
example:
array(3) {
[0]=>
object(SimpleXMLElement)#24 (1) {
[0]=>
string(20) "Network Media Player"
}
[1]=>
object(SimpleXMLElement)#25 (1) {
[0]=>
string(12) "Music Player"
}
[2]=>
object(SimpleXMLElement)#26 (1) {
[0]=>
string(8) "Juke Box"
}
}
I'd like that to become
array('Network Media Player','Music Player','Juke Box')
Here's my test :
<pre><?php
$xml = "<data>
<item>
<value>Network Media Player</value>
</item>
<item>
<value>Music Player</value>
</item>
<item>
<value>Jukebox Player</value>
</item>
</data>";
$sx = simplexml_load_string($xml);
print_r($sx);
print_r(explode("|",implode("|",$sx->xpath("//data/item/value"))));
?></pre>
and here's the result : http://codepad.org/ZkaWpzMc