SimpleXML: Getting attributes into variables - php

I am building my website with a central XML-file and SimpleXML. The pages have some different features like the language. I would like to put these features into the XML-file with attributes of the parent node:
<content>
<item id="one" lang="en">
<title>Hello</title>
</item>
</content>
I call a certain item by the id-attribute and I know how to call subnodes like :
$xml = simplexml_load_file('file.xml');
$lang = $bl->xpath('/content/item[#id="one"]/title/text()');
$lang = $lang[0]; echo $lang;
But how do I get the attribute LANG of an item with the id="one" into a variable?

the path to the attribute
/content/item[#id="one"]/#lang
the value of the attribute data(/content/item[#id="one"]/#lang)

Related

How to Insert new XML element at the top of other nodes? [duplicate]

I have a previously generated XML like this:
<newsletter>
<header>
</magazine>
</image>
<strap/>
</header>
<intro>
<date/>
<text/>
</edimg>
</intro>
<shop>
<heading/>
<article/>
<title/>
<img/>
<link/>
<excerpt/>
</shop>
<sidebar>
<cover/>
<cover_link/>
<text/>
<advert>
<link/>
<image/>
</advert>
</sidebar>
</newsletter>
I need to be able to insert an element in between the <intro> and the <shop> elements
this:
$section = $dom->documentElement->appendChild($dom->createElement('section'));
will just create the element within <newsletter> .
I assumed this would be fairly simple , but cannot seem to find a solution .
Thanks.
You might try this; I didn't test it, but the solution comes from using insertBefore instead of appendChild.
$shop = $dom->getElementsByTagName("shop")->item(0);
$section = $dom->documentElement->insertBefore($dom->createElement('section'),$shop);
Fetch the <shop> node and use
DOMNode::insertBefore — Adds a new child before a reference node
instead of appending to the documentElement.
You can do that from the DOMDocument as well when passing in the shop node as second argument. Personally, I find it easier to just do that from the shop node because you have to fetch it anyway:
$shopNode->insertBefore($newNode);
Try
$section = $dom->documentElement->insertBefore(
$dom->createElement('section'),
$shop)
);
where $shop points to the <shop> element.

How to insert one item before the first item currently without xpath in Domdocument using PHP [duplicate]

I have a previously generated XML like this:
<newsletter>
<header>
</magazine>
</image>
<strap/>
</header>
<intro>
<date/>
<text/>
</edimg>
</intro>
<shop>
<heading/>
<article/>
<title/>
<img/>
<link/>
<excerpt/>
</shop>
<sidebar>
<cover/>
<cover_link/>
<text/>
<advert>
<link/>
<image/>
</advert>
</sidebar>
</newsletter>
I need to be able to insert an element in between the <intro> and the <shop> elements
this:
$section = $dom->documentElement->appendChild($dom->createElement('section'));
will just create the element within <newsletter> .
I assumed this would be fairly simple , but cannot seem to find a solution .
Thanks.
You might try this; I didn't test it, but the solution comes from using insertBefore instead of appendChild.
$shop = $dom->getElementsByTagName("shop")->item(0);
$section = $dom->documentElement->insertBefore($dom->createElement('section'),$shop);
Fetch the <shop> node and use
DOMNode::insertBefore — Adds a new child before a reference node
instead of appending to the documentElement.
You can do that from the DOMDocument as well when passing in the shop node as second argument. Personally, I find it easier to just do that from the shop node because you have to fetch it anyway:
$shopNode->insertBefore($newNode);
Try
$section = $dom->documentElement->insertBefore(
$dom->createElement('section'),
$shop)
);
where $shop points to the <shop> element.

Identical nested XML elements with namespaces and PHP

Try as I may, I cannot seem to grab the value of the "Id" attribute in the nested apcm:Property element, where the "Name" attribute equals "sequenceNumber", on line 12. As you can see, there element of interest is buried in a nest of other elements with an identical name and namespace.
Using PHP, I'm having a difficult time wrapping my head around how to grab that Id value.
<?xml version="1.0" encoding="utf-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:apcm="http://ap.org/schemas/03/2005/apcm" xmlns:apnm="http://ap.org/schemas/03/2005/apnm" xmlns:georss="http://www.georss.org/georss">
<id>urn:publicid:ap.org:30085</id>
<title type="xhtml">
<apxh:div xmlns:apxh="http://www.w3.org/1999/xhtml">
<apxh:span>AP New York State News - No Weather</apxh:span>
</apxh:div>
</title>
<apcm:Property Name="FeedProperties">
<apcm:Property Name="Entitlement" Id="urn:publicid:ap.org:product:30085" Value="AP New York State News - No Weather" />
<apcm:Property Name="FeedSequencing">
<apcm:Property Name="sequenceNumber" Id="169310964" />
<apcm:Property Name="minDateTime" Value="2012-05-22T18:04:18.913Z" />
</apcm:Property>
</apcm:Property>
<updated>2012-05-22T18:04:18.913Z</updated>
<author>
<name>The Associated Press</name>
<uri>http://www.ap.org</uri>
</author>
<rights>Copyright 2012 The Associated Press. All rights reserved. This material may not be published, broadcast, rewritten or redistributed.</rights>
<link rel="self" href="http://syndication.ap.org/AP.Distro.Feed/GetFeed.aspx?idList=30085&idListType=products&maxItems=20" />
<entry>
...
</entry>
</feed>
You have to register the namespaces, and use the [] predicate to identify which Property element you are interested in. It is safest if you do NOT use double slash, i.e., if you start the look up from the document element.
<?php
$xml = <<<EOD
...
EOD;
$sxe = new SimpleXMLElement($xml);
$sxe->registerXPathNamespace('apcm', 'http://ap.org/schemas/03/2005/apcm');
$sxe->registerXPathNamespace('atom', 'http://www.w3.org/2005/Atom');
$result = $sxe->xpath('/atom:feed/acpm:Property[#Name=\'FeedProperties\']/acpm:Property[#Name=\'FeedSequencing\']/acpm:Property[#Name=\'sequenceNumber\']/#Id');
foreach ($result as $sequenceNumber) {
echo $sequenceNumber . "\n";
}
?>
Note that there may theoretically be multiple sibling Property elements with the same #Name and so this Xpath may produce multiple nodes (#Id values).

SimpleXML adding child with children and attributes

I have some XML to which I need to add a child.
Using SimpleXML, I'm not having any issue adding a simple node.
The beginning XML looks a bit like this:
<root>
<item>
<title>This is the title</title>
<sort>2</sort>
</item>
<item>
<title>This is another title</title>
<sort>3</sort>
</item>
</root>
I need to add a node that looks like this:
<label id=1>
<title type=normal>This is a label</title>
<sort>1</sort>
</label>
The result would be:
<root>
<item>
<title>This is the title</title>
<sort>2</sort>
</item>
<item>
<title>This is another title</title>
<sort>3</sort>
</item>
<label id=1>
<title type=normal>This is a label</title>
<sort>1</sort>
</label>
</root>
I'm able to add a simple child using:
$xml->root->addChild('label', 'This is a label');
I am having trouble getting the attributes and children added to this newly added node though.
I am not worried about appending versus prepending as the sorting happens in XSLT.
addChild returns the added child, so you just have to do :
$label = $xml->root->addChild('label');
$label->addAttribute('id', 1);
$title = $label->addChild('title', 'This is a label');
$title->addAttribute('type', 'normal');
$label->addChild('sort', 1);
$xml->root->addChild('label', 'This is a label');
This opereration returns a reference to the child that was just added. So you could do this:
$child = $xml->root->addChild('label', 'This is a label');
From this, you can not add your additional children and attributes to that child.
$child->addAttributes('id', '1');
Since it returns a reference, that node and attributes that were just added are part of the $xml object as well.

PHP XML inserting element after (or before) another element

I have a previously generated XML like this:
<newsletter>
<header>
</magazine>
</image>
<strap/>
</header>
<intro>
<date/>
<text/>
</edimg>
</intro>
<shop>
<heading/>
<article/>
<title/>
<img/>
<link/>
<excerpt/>
</shop>
<sidebar>
<cover/>
<cover_link/>
<text/>
<advert>
<link/>
<image/>
</advert>
</sidebar>
</newsletter>
I need to be able to insert an element in between the <intro> and the <shop> elements
this:
$section = $dom->documentElement->appendChild($dom->createElement('section'));
will just create the element within <newsletter> .
I assumed this would be fairly simple , but cannot seem to find a solution .
Thanks.
You might try this; I didn't test it, but the solution comes from using insertBefore instead of appendChild.
$shop = $dom->getElementsByTagName("shop")->item(0);
$section = $dom->documentElement->insertBefore($dom->createElement('section'),$shop);
Fetch the <shop> node and use
DOMNode::insertBefore — Adds a new child before a reference node
instead of appending to the documentElement.
You can do that from the DOMDocument as well when passing in the shop node as second argument. Personally, I find it easier to just do that from the shop node because you have to fetch it anyway:
$shopNode->insertBefore($newNode);
Try
$section = $dom->documentElement->insertBefore(
$dom->createElement('section'),
$shop)
);
where $shop points to the <shop> element.

Categories