Select xml node by attribute in php [duplicate] - php

This question already has answers here:
SimpleXML: Selecting Elements Which Have A Certain Attribute Value
(2 answers)
Closed 2 years ago.
How do I find the node value by knowing the attribute value without traversing through every child and every attribute/value ?
$dom = new DOMDocument;
$dom->load('test.xml');
$rows = $dom->getElementsByTagName('row');
foreach ($rows as $row) {
$header = VALUE OF <field name="header">
$text = VALUE OF <field name="text">
}
XML:
<resultset>
<row>
<field name="item">2424</field>
<field name="header">blah blah 1</field>
<field name="text" xsi:nil="true" />
...
</row>
<row>
<field name="item">5321</field>
<field name="header">blah blah 2</field>
<field name="text">some text</field>
...
</row>
</resultset>

The simplest thing to do is use DOMXPath::querydocs
The following code finds all the <field> nodes within <row> nodes that have a name attribute equal to "header":
$dom = new DOMDocument;
$dom->loadXML($str); // where $str is a string containing your sample xml
$xpath = new DOMXPath($dom);
$query = "//row/field[#name='header']";
$elements = $xpath->query($query);
foreach ($elements as $field) {
echo $field->nodeValue, PHP_EOL;
}
Using the sample xml you provide, the above outputs:
blah blah 1
blah blah 2

Related

Accessing a specific XML element using xpath in PHP 7.x

Ok so I have some XML data.
$mydata = <<<XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE fmresultset PUBLIC "-//FMI//DTD fmresultset//EN" "https://HIDDEN:443/fmi/xml/fmresultset.dtd">
<fmresultset xmlns="http://www.filemaker.com/xml/fmresultset" version="1.0">
<resultset count="1" fetch-size="1">
<record mod-id="27" record-id="754">
<field name="a_Constant_c">
<data>1</data>
</field>
<field name="a_Sch_ID_pk">
<data>100060</data>
</field>
<field name="a_SchoolHead_pk">
<data>100060_1</data>
</field>
<field name="b___Data_____________">
<data/>
</field>
<field name="b_1Name_School_Code_t">
<data>PJA</data>
</field>
<field name="b_1Name_School_t">
<data>Palmetto</data>
</field>
<field name="b_1Name_SchoolHead_t">
<data>John Doe</data>
</field>
<field name="b_Ad_Address1_t">
<data/>
</field>
<field name="b_Ad_Address2_t">
<data>123 Main St.</data>
</record>
</resultset>
</fmresultset>
XML;
Now what I want to do is basically be able to read the value of the data from a specific field and assign it to a variable.
So far I have something like this...
$xml = simplexml_load_string($mydata);
Now I want to be able to assign let's say the data in the field name b_1Name_School_Code_t (which is PJA)
So I think it should be something like this
$school = $xml->resultset->record->field->data;
echo "School Name: ".$school;
Then I would like to see on the screen
School Name: PJA
So what I am missing to be able to make this happen?
You are only getting to the first field element in your example, which is why you get 1. Instead, loop through all the field elements, and stop when you get to the one you need:
$xml = simplexml_load_string($mydata);
$fields = $xml->resultset->record->field;
foreach ($fields as $field) {
if ((string) $field->attributes()->name === "b_1Name_School_Code_t") {
echo "School name: ".$field->data; // School name: PJA
break;
}
}
Demo
I use SimpleXMLElement::attributes() to get the name attribute of the element (note the cast to string, otherwise you get an SimpleXMLElement)
However, it would make more sense to use XPath to go directly to the element you're after:
$xml = simplexml_load_string($mydata);
$xml->registerXPathNamespace("fmresultset", "http://www.filemaker.com/xml/fmresultset");
$node = $xml->xpath("//fmresultset:resultset/fmresultset:record/fmresultset:field[#name='b_1Name_School_Code_t']");
var_dump($node[0]->data); // PJA
Demo
Notice the namespace registration and the accessing of the first element, since xpath() returns an array of SimpleXMLElements

Selecting Attribute and listing Value base on NODE Value using Xpath

How do i get All Attribute Value ID of every node FLOWER?
<Files>
<data id="1">
<Type>Flower</Type>
</data>
<data id="2">
<Type>Flower</Type>
</data>
<data id="3">
<Type>Flower</Type>
</data>
<data id="4">
<Type>Flower</Type>
</data>
</Files>
In mysql case it will be like SELECT id from Files WHERE Type="Flower"
How do i code xpath for this condition?
and List it using SimpleXML within option box.
<select>
<?php
foreach ($type as $id) {
echo '<option value="'.$id.'">'.$id.'</option>';
}
?>
</select>
To get all #id attribute's values try
/Files/data[normalize-space(Type) = 'Flower']/#id
'//data[(./Type/text()="Flower")]/#id'
Your XML is invalid, the closing root element does not match and the Type elements are closed as type. XML is case sensitive.
Xpath works uses location paths and conditions a location path is a hierarchical path to the element from the current context. They return a list of nodes. The list can be filtered using conditions.
SimpleXMLElement objects have a method xpath() to execute an expression in the context of the associated node.
$xml = <<<'XML'
<Files>
<data id="1">
<type>Flower</type>
</data>
<data id="2">
<type>Flower</type>
</data>
<data id="3">
<type>Flower</type>
</data>
<data id="4">
<type>Flower</type>
</data>
</Files>
XML;
$files = new SimpleXMLElement($xml);
$target = new SimpleXMLElement('<select/>');
foreach ($files->xpath('data[type = "Flower"]') as $data) {
echo '.';
$option = $target->addChild('option', $data['id']);
$option['value'] = $data['id'];
}
echo $target->asXml();
You should not create you XML as text. Use an XML Api for it.
DOM is more specific and powerful. For example you can serialize the created DOM as HTML.
$source = new DOMDocument();
$source->loadXml($xml);
$xpath = new DOMXpath($source);
$target = new DOMDocument();
$select = $target->appendChild($target->createElement('select'));
foreach ($xpath->evaluate('/Files/data[type = "Flower"]') as $data) {
$option = $select->appendChild($target->createElement('option'));
$option->setAttribute('value', $data->getAttribute('id'));
$option->appendChild($target->createTextNode($data->getAttribute('id')));
}
echo $target->saveHtml($select);
This is how i used the answer Feel free to use the code if you like.
Thanks!!
<?php
//I have used 2 given answer as example on how i used it. Feel Free to use the code below
$type = $_GET['type'];
if(file_exists("xml/data.xml")) {
$xml = simplexml_load_file('xml/data.xml') or die("Data Missing"); }
<!-- Code Example 1 -->
$ids = $xml->xpath('//data[(./Type/text()="'.$type.'")]/#id');
<!-- Code Example 2 -->
$idx = $xml->xpath('/Files/data[normalize-space(Type) = "'.$type.'"]/#id');
?>
<!-- Example 1 -->
<select>
<?php
//echo $ids[0];
foreach ($ids as $id) {
echo '<option value="'.$id[0].'">'.$id[0].'</option>';
}
?>
</select>
<!-- Example 2 -->
<select>
<?php
//echo $ids[0];
foreach ($idx as $id2) {
echo '<option value="'.$id2[0].'">'.$id2[0].'</option>';
}
?>
</select>
<a href="logout.php">Logout
</a>

SimpleXMLElement(): Get value of XML tag based off attribute value [duplicate]

This question already has answers here:
SimpleXML: Selecting Elements Which Have A Certain Attribute Value
(2 answers)
Closed 8 years ago.
I have the following XML file:
<?xml version="1.0" encoding="UTF-8"?>
<result name="response">
<doc>
<str name="index">2</str>
<str name="summary">A summary</str>
<str name="title">A Title</str>
<arr name="media">
<str>/image/123.jpg</str>
</arr>
</doc>
</result>
I'm grabbing the contents and creating a SimpleXMLElement in PHP. I need to be able to grab the contents of a specific tag based on it's name value. E.g. If I was trying to echo out "A summary" something like this:
echo $xmlObj->doc->str['name']->summary;
I know that doesn't work but what will? I've looked at a lot of similar questions but haven't found one with this specific problem. Cheers.
Use XPath (http://www.w3schools.com/php/func_simplexml_xpath.asp)
<?php
$string = <<<XML
<a>
<b>
<c>text</c>
<c>stuff</c>
</b>
<d>
<c>code</c>
</d>
</a>
XML;
$xml = new SimpleXMLElement($string);
/* Search for <a><b><c> */
$result = $xml->xpath('/a/b/c');
while(list( , $node) = each($result)) {
echo '/a/b/c: ',$node,"\n";
}
/* Relative paths also work... */
$result = $xml->xpath('b/c');
while(list( , $node) = each($result)) {
echo 'b/c: ',$node,"\n";
}
?>
The solution to the problem is as follows:
$summary = $xmlObj->xpath('doc/str[#name="summary"]');
if($summary) {
echo $summary[0];
}
It involves using XPath as a4arpan pointed out.

PHP XPath - Select one specific node and his parent node with one rule [duplicate]

This question already has answers here:
How do I select multiple sets of attributes within an XML document using XPath?
(2 answers)
Closed 9 years ago.
I'm working on parsing some XML files using Xpath. I want to select one specific Category node and his parent node (Sport) with one expression?!
XML document: livescore_full.xml
<? xml version = "1.0" encoding = "UTF-8" ?>
<LivescoreData generatedAt="2013-08-18T09:41:19 CEST" type="full">
<Sport SportId="1">
<Name language="en">Soccer</Name>
<Category CategoryId="48">
<Name language="en">Argentina</Name>
<Tournament TournamentId="68" UniqueTournamentId="155">
<Name language="en">Primera Division, Torneo Inicial</Name>
</Tournament>
</Category>
<Category CategoryId="49">
<Name language="en">Brazil</Name>
<Tournament TournamentId="69" UniqueTournamentId="156">
<Name language="en">Brazil Primera Division</Name>
</Tournament>
</Category>
</Sport>
<Sport SportId="2">
<Name language="en">Basketball</Name>
<Category CategoryId="55">
<Name language="en">Spain</Name>
<Tournament TournamentId="545" UniqueTournamentId="453">
<Name language="en">Primera Division, Torneo Inicial</Name>
</Tournament>
</Category>
<Category CategoryId="56">
<Name language="en">England</Name>
<Tournament TournamentId="654" UniqueTournamentId="5656">
<Name language="en">England</Name>
</Tournament>
</Category>
</Sport>
</LivescoreData>
$xml = simplexml_load_file("livescore_full.xml");
$data = $xml->xpath('//Category[#CategoryId="48"]');
print_r($data); // only return data for specific Category node
$data contains data about Category node id=48, but there is no information about the sport id and sport name.
How to write Xpath rule to select Sport and Category data using CategoryId attribute? I tried some variations with the ancestor-or-self, but without success.
"/LiveScoreData/Sport[Category[#CategoryId='48']"
Would be one way.
One easy answer which comes to mind is (How do I select multiple nodesets):
$data = $xml->xpath('//Category[#CategoryId="48"] | //Sport[Category[#CategoryId="48"]]');
However, I'd drop SimpleXML for this case and do this:
$dom = new DOMDocument();
$dom->load("livescore_full.xml");
$xpath = new DOMXPath($dom);
$category = $xpath->query('//Category[#CategoryId="48"]')->item(0);
//then sport is just it's parentNode:
$sport = $category->parentNode;
//removing all other cats:
$dom = new DOMDocument();
$dom->load("livescore_full.xml");
$xpath = new DOMXPath($dom);
$categories = $xpath->query('//Sport[Category[#CategoryId="48"]]/Category[#CategoryId!="48"]');
while($othercat = $categories->item(0)){
$othercat->parentNode->removeChild($othercat);
}

display only nodes in XML with specific attributes in php [duplicate]

This question already has answers here:
Using XPath, How do I select a node based on its text content and value of an attribute?
(2 answers)
Closed 9 years ago.
if i have:
<listing>
<name>Bob</name>
<age>20</age>
<hair>red</hair>
</listing>
<listing>
<name>John</name>
<age>24</age>
<hair>black</hair>
</listing>
how do i code my php page to only display listings if hair = black
so that it would only pull in
<listing>
<name>John</name>
<age>24</age>
<hair>black</hair>
</listing>
Thanks
Use XPath.
// First, your XML must be wraped with some root tag.
$data = <<<XML
<root>
<listing>
<name>Bob</name>
<age>20</age>
<hair>red</hair>
</listing>
<listing>
<name>John</name>
<age>24</age>
<hair>black</hair>
</listing>
</root>
XML;
// Instancing the SimpleXMLElement within the XML(obviously)
$xml = new SimpleXMLElement($data);
// XPath
$xpath = $xml->xpath("listing[contains(hair,'black')]");
/**
* eXplained XPath:
* <listing> that
* <hair>'s content is equal black
*/
foreach($xpath as $node){
// just for fun echoes the <results> node
echo $node->asXml();
}

Categories