I have so called "GAEB" files, which are in XML structure.
I loop through these via foreach and simplexml.
XML/GAEB File:
<GAEB>
<Award>
<BoQ>
<BoQBody>
<BoQCtgy RNoPart="01">
<BoQBody>
<BoQCtgy RNoPart="01">
<BoQBody>
<BoQCtgy>
<BoQBody RNoPart="01">
<Itemlist>
<Item RNoPart="1">
<Item RNoPart="2">
</Itemlist>
</BoQBody>
</BoQCtgy>
<BoQCtgy>
<BoQBody RNoPart="02">
<Itemlist>
<Item RNoPart="1">
<Item RNoPart="2">
</Itemlist>
</BoQBody>
</BoQCtgy>
</BoQBody>
</BoQCtgy>
<BoQCtgy RNoPart="02">
<BoQBody>
<BoQCtgy>
<BoQBody RNoPart="01">
<Itemlist>
<Item RNoPart="1">
<Item RNoPart="2">
</Itemlist>
</BoQBody>
</BoQCtgy>
<BoQCtgy>
<BoQBody RNoPart="02">
<Itemlist>
<Item RNoPart="1">
<Item RNoPart="2">
</Itemlist>
</BoQBody>
</BoQCtgy>
</BoQBody>
</BoQCtgy>
</BoQBody>
</BoQCtgy>
</BoQBody>
</BoQ>
</Award>
</GAEB>
My PHP Code Loops through all $xml->BoQBody->BoQCtgy till it finds a Itemlist.
Then looping through that Itemlist and get some informations from there.
After that start loop again.
PHP:
<?php
$file = "pathtoxmlfile";
$xml = simplexml_load_file($file);
function loop($path, $xml){
foreach($path->BoQBody->BoQCtgy as $BoQCtgy){
$nr = $BoQCtgy->attributes()["RNoPart"];
echo $nr;
if(ISSET($BoQCtgy->BoQBody->Itemlist) === TRUE{
foreach($BoQCtgy->BoQBody->Itemlist->Item as $item){
$pos = $item->attributes()["RNoPart"];
echo $pos;
}
}
}
loop($BoQCtgy,$xml);
}
loop($xml->Award->BoQ,$xml);
?>
How I get a clear numbering of all my positions?
The above example should be:
01
01.01
01.01.01
01.01.01.1
01.01.01.2
01.01.02
01.01.02.1
01.01.02.2
The problem is, the deepth is everytime a other.
I get all positions and all values I need with the PHP Code without any problems.
But I can't get a matching numbering...
Hope somebody knows a solution.
Using XPath you don't have to worry about what depth items are at. In this case it first looks for any node with an RNoPart attribute using //*[#RNoPart]...
// - any level
any node
[#RNoPart] - with a RNoPart attribute (the # indicates an attribute)
It loops over the results and then uses the ancestor axes in XPath to look for all parent elements with another RNoPart attribute, using ancestor::*/#RNoPart.
As it loops over these (in this example) it just outputs the values followed by a . and a new line after each sub set.
So put together, you get...
foreach ( $xml->xpath("//*[#RNoPart]") as $part ) {
foreach ( $part['RNoPart']->xpath("ancestor::*/#RNoPart") as $part ) {
echo $part.".";
}
echo PHP_EOL;
}
and with your sample XML, outputs...
01.
01.01.
01.01.01.
01.01.01.1.
01.01.01.2.
01.01.02.
01.01.02.1.
01.01.02.2.
01.02.
01.02.01.
01.02.01.1.
01.02.01.2.
01.02.02.
01.02.02.1.
01.02.02.2.
Related
New to XML here.
Consider this simple XML schema:
<products>
<category name="furniture">
<item name="chair" name2="table">
<size>
<small>10</small>
<large>20</large>
</size>
</item>
<item name="cabinet">
<size>
<small>15</small>
<large>30</large>
</size>
</item>
<item name="shelf" name2="box" name3="frame">
<size>
<small>5</small>
<large>10</large>
</size>
</item>
</category>
</products>
Notice each <item> element has a different amount of attributes.
I've been trying to echo out the attributes using XPATH and a foreach loop without success.
Surely I'm missing a small piece of syntax.
$dom=simplexml_load_file("file.xml");
foreach ($dom->xpath("/products/category[#name='furniture']/item") as $parse)
echo'<tr><td>'.$parse->attributes().'</td></tr>';
$parse->attributes(); only gives me the first attribute of the element.
Output looks like this:
<tr><td>chair</td></tr>
<tr><td>cabinet</td></tr>
<tr><td>shelf</td></tr>
What am I missing?
Use a nested foreach loop:
foreach ($dom->xpath("/products/category[#name='furniture']/item") as $parse) {
foreach ($parse->attributes() as $attr) {
echo '<tr><td>'. $attr . '</td></tr>'."\n";
}
}
I have the following XML all contained in one cell in a MSSQL DB:
<receipt reference="INT000003" major="2" minor="14.804" beta="">
<dates id="Booking Dates">
<item id="Date of Booking">23 May 2013 - 17:09</item>
</dates>
<advertisement id="advertisement details">
<item id="Booked by">Mr System Administrator</item>
<item id="Brand or Product">Testing</item>
<item id="Priority">500</item>
</advertisement>
</receipt>
I want to get the value <item id="Brand or Product">Testing</item> out of that cell (specifically "Testing" though) to use in a PHP based webpage. Does anyone know of any PHP to read this type of XML and search for values?
Thanks.
You can use DOMXPath::query for it in PHP. First select the entire XML from the table as you normally would and then get the correct elements.
<?php
$xml = <<<END
<receipt reference="INT000003" major="2" minor="14.804" beta="">
<dates id="Booking Dates">
<item id="Date of Booking">23 May 2013 - 17:09</item>
</dates>
<advertisement id="advertisement details">
<item id="Booked by">Mr System Administrator</item>
<item id="Brand or Product">Testing</item>
<item id="Priority">500</item>
</advertisement>
</receipt>
END; //you would load it from the table
$dom = new DOMDocument;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$query = "//advertisement/item";
$items = $xpath->query($query);
foreach ($items as $item) {
echo $item->nodeValue;
}
?>
This will output
Mr System Administrator
Testing
500
And if you would need the value of a specific ID you can use
<?php
$dom = new DOMDocument;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$query = "//advertisement/item[#id='Brand or Product']";
$items = $xpath->query($query);
foreach ($items as $item) {
echo $item->nodeValue;
}
Output:
Testing
This can also done in SQL as below :
declare #xml xml =
'<receipt reference="INT000003" major="2" minor="14.804" beta="">
<dates id="Booking Dates">
<item id="Date of Booking">23 May 2013 - 17:09</item>
</dates>
<advertisement id="advertisement details">
<item id="Booked by">Mr System Administrator</item>
<item id="Brand or Product">Testing</item>
<item id="Priority">500</item>
</advertisement>
</receipt>'
select #xml.value
('(/receipt/advertisement/item[#id="Brand or Product"])[1]', 'nvarchar(100)')
Also, you can directly fetch the value from table as below :
select cast(YOUR_COLUMN_NAME as XML).value('(/receipt/advertisement/item[#id="Brand or Product"])[1]', 'nvarchar(100)')
as s from YOUR_TABLE_NAME
This is a snippet of XML that I'm working with:
<category name="pizzas">
<item name="Tomato & Cheese">
<price size="small">5.50</price>
<price size="large">9.75</price>
</item>
<item name="Onions">
<price size="small">6.85</price>
<price size="large">10.85</price>
</item>
<item name="Peppers">
<price size="small">6.85</price>
<price size="large">10.85</price>
</item>
<item name="Broccoli">
<price size="small">6.85</price>
<price size="large">10.85</price>
</item>
</category>
This is what my php looks like:
$xml = $this->xml;
$result = $xml->xpath('category/#name');
foreach($result as $element) {
$this->category[(string)$element] = $element->xpath('item');
}
everything works ok except $element->xpath('item');
I also tried using: $element->children(); as well as other xpath queries, but they all return null.
Why can't I access children of a category?
It looks like you're trying to build a tree based on categories, keyed by category name. To do that, you should change your code to look like this:
$xml = $this->xml;
//Here, match the category tags themselves, not the name attribute.
$result = $xml->xpath('category');
foreach($result as $element) {
//Iterate through the categories. Get their name attributes for the
//category array key, and assign the item xpath result to that.
$this->category[(string)$element['name']] = $element->xpath('item');
}
With your original code here: $result = $xml->xpath('category/#name'); your result was the name attribute nodes, which, as attributes, cannot have children.
Now if you simply wanted a list of all items, you could use $xml->xpath('category/items'), but that doesn't appear to be what you had wanted.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
A simple program to CRUD node and node values of xml file
I would like to change some data in a xml file with php.
So in my xml file I have this :
<items><item href="p002.xhtml" id="p002" media-type="application/xhtml+xml"/>
<item href="img/b002.jpg" id="b002" media-type="image/jpeg"/>
<item href="p003.xhtml" id="p003" media-type="application/xhtml+xml"/>
<item href="img/b003.jpg" id="b003" media-type="image/jpeg"/>
<item href="p004.xhtml" id="p004" media-type="application/xhtml+xml"/>
<item href="img/b004.jpg" id="b004" media-type="image/jpeg"/>
<item href="p005.xhtml" id="p005" media-type="application/xhtml+xml"/>
<item href="img/b005.jpg" id="b005" media-type="image/jpeg"/></items>
I would like to open the file, delete all item greater than 0003 and save changes. I have some tags between this extract.
Result:
<items><item href="p002.xhtml" id="p002" media-type="application/xhtml+xml"/>
<item href="img/b002.jpg" id="b002" media-type="image/jpeg"/>
<item href="p003.xhtml" id="p003" media-type="application/xhtml+xml"/>
<item href="img/b003.jpg" id="b003" media-type="image/jpeg"/></items>
Trying :
if( ! $xml = simplexml_load_file("pack.xml") ) {
echo 'unable to load XML file';
}
else {
echo "<ul>";
foreach($xml->items->item as $v ){
//echo "<li>".$v[href]."</li>";
if($v[href]=="p003.xhtml" || $v[href]=="img/bg003.jpg"){
echo "<li>".$v[href]."</li>";
}
}
echo "</ul>";
}
How to check the greater than p003.xhtml and img/bg003.jpg ?
You are going to want to parse the file using simplexml. This will generate a nice set of DOM like classes for you to work with. From these classes you can search for elements with your criteria and remove them before saving the xml tree back to text
I can get the data from the xml apart from all the <Item> data. The code below only gets the data for the last one. I thought the foreach would get it for each of them but it doesn't seem to.
<magic5Out version="2.1.0">
<Report customerPK="Survey_2" locationPK="229" userId="2299" template="13600" formDate="2012-04-11T00:00:00" dateTimeStarted="2012-04-11T07:34:04" dateTimeMobileReleased="2012-04-11T07:37:03" currentStatus="5" reportGuid="b174d011-77bb-4882-b87e-a2c60bdf265d">
<Results>
<Item itemPK="SurveyTab_9">
<q1 listEntry="1.8m" listEntryId="239107"/>
<q1Comments text=""/>
<q2 listEntry="Green" listEntryId="239113"/>
<q2Comments text=""/>
<item_comments text="test"/>
</Item>
<Item itemPK="SurveyTab_24">
<q1 listEntry="2.2m" listEntryId="239108"/>
<q1Comments text=""/>
<q2 listEntry="Silver" listEntryId="239112"/>
<q2Comments text=""/>
<item_comments text=""/>
</Item>
<Item itemPK="SurveyTab_10">
<q1 listEntry="3.0m" listEntryId="239110"/>
<q1Comments text=""/>
<q2 listEntry="White" listEntryId="239111"/>
<q2Comments text=""/>
<item_comments text="No feed"/>
</Item>
<Item itemPK="SurveyTab_23">
<q1 listEntry="2.2m" listEntryId="239108"/>
<q1Comments text=""/>
<q2 listEntry="Green" listEntryId="239113"/>
<q2Comments text=""/>
<item_comments text=""/>
</Item>
<surveyorComments0 text="testing"/>
<surveyorName text="NICK"/>
<surveyorSig opFile="D:\Sites\WebApp_eden\Output\2100\XMLSurvey\Attachments\1cf582f9-776c-472e-b8ce-877a51fae5e1.png"/>
</Results>
</Report>
</magic5Out>
here's the php I'm using:
$xml = simplexml_load_file($xml_file);
/* more code here that works OK */
foreach($xml->Report->Results->Item as $tab) {
$tab_name = (string) $tab['itemPK'];
$q1_result = $tab->q1['listEntry'];
$q2_result = $tab->q2['listEntry']; etc.
$q1_comment = escape_data($tab->q1Comments['text']);
$q2_comment = escape_data($tab->q2Comments['text']);
$item_comment = escape_data($tab->item_comments['text']);
}
When you make a loop and define a variable then you have in your case the last value from the loop in your variable.
You overwrite your variable everytime.
foreach($xml->Report->Results->Item as $tab) {
$tab_name[] = (string) $tab['itemPK'];
$q1_result[] = $tab->q1['listEntry'];
$q2_result[] = $tab->q2['listEntry']; etc.
$q1_comment[] = escape_data($tab->q1Comments['text']);
$q2_comment[] = escape_data($tab->q2Comments['text']);
$item_comment[] = escape_data($tab->item_comments['text']);
}
try something like this. Then you have an array with all the values.
There must have been something elsewhere in the code that was screwing this up - I tried a load of other things and eventually reverted to the php I posted above and it worked this time. Hope it was only my own time I wasted on this.