ar\xml
This module contains simple xml generation, parsing and manipulation methods. It works as follows:
<pinp>
$x = ar('xml');
echo $x->preamble('1.0', 'iso-8859-1');
echo $x->el('rss', array('version' => '2.0'),
$x->el('channel',
$x->el('title', 'Wikipedia'),
$x->el('link', 'http://www.wikipedia.org/'),
$x->el('description',
'This feed notifies you of new articles on Wikipedia.')
)
);
</pinp>
Results in:
<?xml version="1.0" encoding="iso-8859-1" ?>
<rss version="2.0">
<channel>
<title>Wikipedia</title>
<link>http://www.wikipedia.org/</link>
<description>This feed notifies you of new articles on
Wikipedia.</description>
</channel>
</rss>
Currently the xml generator doesn't throw errors when passed incorrect values, it just skips incorrect characters or encodes them.
Parsing a piece of xml is also very straightforward:
<pinp> $dom = ar('xml')->parse( '<root><element /></root>' ); </pinp>
The result of parse()
is the same as if you created the xml with the el()
or element()
method. You can echo it as if it was a string, or manipulate the results in a DOM like fashion, e.g.:
<pinp>
$x = ar('xml');
$ul = $x->el('ul',
$x->el('li', 'item 1'),
$x->el('li', 'item 2')
$x->el('li', 'item 3')
);
$ul->firstChild->setAttribute('class', 'first');
$ul->firstChild->nextSibling->setAttribute('class', 'second');
$ul->firstChild->appendChild(
$x->el(
'a',
array('href' => 'http://www.ariadne-cms.org/' ),
'name of the link'
)
);
echo $ul;
</pinp>
You may also access the dom node as you would with simpleXML:
<pinp>
$ul->li->a->setAttribute('class', 'myLink');
$ul->li[0]->setAttribute('id', 'first');
echo $ul->li[0]->attributes['id'];
echo $ul->getElementById('first');
</pinp>
In contrast with SimpleXML, attributes aren't mapped to an array access of a node, but they are stored in the attributes property of a node. You should use setAttribute()
to change an attribute value, you must use it when setting or unsetting the 'id' attribute.
In addition the following two blocks of code look similar, but have a slightly different effect:
<pinp>
$ul->li->setAttribute('class', 'item');
$ul->li[0]->setAttribute('class', 'somethingElse');
echo $ul;
</pinp>
<pinp>
$ul->childNodes->setAttribute('class', 'item');
$ul->li[0]->setAttribute('class', 'somethingElse');
echo $ul;
</pinp>
In the first case, the list items will all have a class of 'item', except the first, which is what you would expect. In the second case, the list items all have a class of 'item', including the first. The reason is that setAttribute()
on a list of nodes will store the attribute. Just before converting the list of nodes to a string, it sets the attribute again on all childNodes
.
You can prevent that by making a temporary list of nodes, like in the first example. Using $ul->li
actually generates a new list of nodes, which is used once and then thrown away.
You might wonder what the use of this is, but it does allow some nifty things which will make your life easier. You can not just set an attribute value to a string, like above, but also to an array (which will get compacted to a string of values seperated by a space) or a list pattern.
A list pattern is a new feature. It works somewhat like a regular expression, but it works on arrays instead of strings. Instead of matching the contents of the array, it only matches the length and current position in the array. But this is enough to do something like this:
<pinp>
$ul->childNodes->setAttribute(
'class',
ar::listPattern( '(odd even?)*' )
);
$ul->appendChild( $x->node( 'li', 'item 4' ) );
echo $ul;
</pinp>
Now all the odd list items have class="odd"
and the even list items have class="even"
, even the last item which was added after the attribute was set.
methods
(string) |
attribute |
Generates a XML attribute for inclusion in an XML tag. |
(string) |
attributes |
Generates a string of attributes for inclusion in an XML tag. |
(object) |
bind |
Experimental. Simple XML Data Binding, returns a simplified native php object representation of the XML data. |
(object) |
bindAsArray |
Experimental. Same as bind(), except the named property is forced to be an array. |
(object) |
cdata |
Returns a CDATA xml enclosure |
(object) |
comment |
Generates a XML comment. |
(void) |
configure |
Allows you to configure a number of XML writer options. |
(string) |
indent |
Indents an xml string, if xml indenting is on. |
(string) |
name |
Generates a valid XML name. |
(object) |
el |
Returns an XML node with the given tag name, attributes and children. Replaces ar_xml::tag() in Ariadne > 2.7.3. |
(object) |
element |
Identical to ar_xml::el() . |
(object) |
nodes |
Generates a list of nodes. |
(object) |
parse |
Creates an XML dom from an XML string. |
(object) |
preamble |
Generates a valid XML preamble. |
(object) |
tag |
Deprecated in Ariadne > 2.7.3. Returns a XML tag with the given name, attributes and children. |
(string) |
value |
Returns a valid XML value. |
attribute
(string) ar('xml')->attribute( $name, $value )
(string) |
$name |
The name of the attribute. |
(mixed) |
$value |
The value of the attribute. |
Returns a string with a valid XML attribute, ready for inclusion in an XML tag.
attributes
(string) ar('xml')->attribute( $attributes )
(array) |
$attributes |
A list of attributes, as $name => $value pairs. |
Returns a string with a list of valid XML attributes, ready for inclusion in an XML tag.
bind
(object)
ar('xml')->bind( $nodes, $propertyName, $typeInfo = 'string' )
(object) |
$nodes |
This is a node or list of nodes in the source XML. |
(string) |
$propertyName |
This is the name of the property to bind the value(s) of the node(s) to. |
(mixed) |
$typeInfo |
This is a type indicator or function callback. Can be either 'string', 'int', 'bool', 'float', 'xml', 'html', a class name or a callable function. |
This method returns an object with properties which are filled with the contents of the bound xml (or html) nodes. Currently the binding is one-way only, changes made in the result object aren't reflected in the source xml and generating xml automatically based on changes made isn't supported.
It binds the nodeValue
property of the given node or list of nodes to the given property name on a new object it returns. You can force the type conversion of the nodeValue using the type hint. If you put a class name in the $typeInfo
argument, an instance of that class will be initialized with the nodeValue as sole argument to its constructor. If you put a function callback into $typeInfo
, this function will be called for each node in the list of nodes, with the node as sole argument.
What you can do with it is create a simplified API to access data from a specified XML format. For example, when parsing RSS, instead of doing this:
<pinp>
$dom = ar('xml')->parse(
ar('http')->get( $url )
);
echo '<ul>';
foreach ( $dom->rss->channel->item as $item ) {
echo '<li><a href="'.$item->link->nodeValue.'">'.
$item->title->nodeValue.'</a></li>';
}
echo '</ul>';
</pinp>
It would be much simpler to write this:
<pinp>
$rss = ar('connect/rss')->get( $url );
echo '<ul>';
foreach ( $rss->items as $item ) {
echo '<li><a href="'.$item->link.'">'.
$item->title.'</a></li>';
}
echo '</ul>';
</pinp>
The bind method makes the definition of such a simple API based on an underlying XML source easy. In this case the definition would look something like this:
<pinp>
$dom = ar::getvar('dom');
return ar('xml')->bind( $dom->rss->channel->title, 'title' )
->bind( $dom->rss->channel->link, 'link' )
->bindAsArray(
$dom->rss->channel->item,
'items',
function( $item ) {
return $item->bind( $item->title, 'title' )
->bind( $item->link, 'link' );
}
);
</pinp>
This will return an object with a structure like this:
object(ar_xmlDataBinding) {
['title'] => string(5) 'Title'
['link'] => string(16) 'http://blog.url/'
['items'] => array(10) {
[0] => object(ar_xmlDataBinding) {
['title'] => string(10) 'Item title'
['link'] => string(15) 'http://item.url'
}
[1] => ...
)
);
Bind will automatically generate an array if you pass it a nodes list with more than one node, otherwise it will bind the property to the given node's nodeValue directly.
Bind returns an ar_xmlDataBinding object, with which you can chain multiple calls to bind()
and bindAsArray()
, as seen in the examples above.
bindAsArray
(object) ar('xml')->bindAsArray( $nodes, $propertyName, $typeInfo = 'string' )
(object) |
$nodes |
This is a node or list of nodes in the source XML. |
(string) |
$propertyName |
This is the name of the property to bind the value(s) of the node(s) to. |
(mixed) |
$typeInfo |
This is a type indicator or function callback. Can be either 'string', 'int', 'bool', 'float', 'xml', 'html' or a callable function. |
This method returns an object with properties which are filled with the contents of the bound xml (or html) nodes. In contrast to the ar_xml::bind()
method, this method will always create the given property as an array. The source XML may have no or just one matching node, but your API can be counted upon to have this property available as an array. It may be an empty array, but an array nonetheless.
cdata
(object) ar('xml')->cdata( $value )
(string) |
$value |
The value to enclose in a CDATA enclosure. |
Returns an ar_xmlNode
object with the cdata
property set to true. If you cast this to a string, it will return the $value
string enclosed in an XML CDATA enclosure. If $value
contains the string ']]>
', this will be replaced with ']]>
'.
comment
(object) ar('xml')->comment( $comment )
(string) |
$comment |
The text of the comment |
Returns an ar_xmlNode
object with the given comment text enclosed as an xml comment .
configure
(void) ar('xml')->configure( $option, $value )
Configures a global XML option. Configurable options are:
(bool) |
comments |
Strips comments if false, default is true. |
(mixed) |
indent |
Can be set to true (indent the HTML code) or false (do not indent the HTML code) or a string to indent the HTML with. The default indentation string is '\t ' (tab). |
(bool) |
preserveWhiteSpace |
If true, text nodes containing only white space will be preserved when parsing XML. Set indent to false to correctly output the XML again. |
indent
(string) ar('xml')->indent( $content, $indent = null )
(string) |
$content |
The content to indent. |
(string) |
$indent |
Optional string to use instead of the default. |
This method indents the given content, if possible and if ar_xml
is configured to generate indented XML or if $indent
is set.
name
(string) ar('xml')->name( $name )
(string) |
$name |
The name to encode. |
Returns a string with a valid XML name. All characters except a-z, 0-9 and ':' will be stripped. The result is always lowercase.
el
Available from Ariadne > 2.7.3.
(object) ar('xml')->el( $tagName, ... )
(object) ar('xml')->element( $tagName, ... )
(string) |
$tagName |
The name of the XML tag. |
(array) |
$attributes |
A list of attributes. |
(string) |
$childNodes |
The child nodes as a string or as an ar_xmlNodes object. |
This method returns a new ar_xmlElement
object. You can add as many attributes or childNodes as you want after $tagName
, in any order. All atributes will be merged into one list.
nodes
(object) ar('xml')->nodes( $node, ... )
(string) |
$node |
An XML node. Optional. |
This method returns an ar_xmlNodes
object containing the list of nodes. This is usefull when you want to return a list of nodes without a single parent. You cannot simply use an array, as that will be seen as a list of attributes by ar_xml::tag
. So instead use this method, e.g:
<pinp>
$buttons = array('button1', 'button2', 'button3');
$content = ar('xml')->nodes();
foreach ( $buttons as $button ) {
$content[] = ar('xml')->node('button', $button);
}
return $content;
</pinp>
parse
(object) ar('xml')->parse( $xml )
(string) |
$xml |
The XML string to parse. |
This method parses a string of XML and returns an XML nodes list. If the XML input isn't well formed it will return an error with error code 109 - ILLEGAL_ARGUMENT. Using this method you can write a simple RSS parser like this:
<pinp>
$dom = ar('xml')->parse(
ar('http')->get(
'http://www.nytimes.com/services/xml/rss/nyt/GlobalHome.xml'
)
);
echo '<ul>';
foreach ( $dom->rss->channel->item as $item )
{
echo '<li><a href="' . $item->link->nodeValue . '">'
. $item->title->nodeValue . '</a></li>';
}
echo '</ul>';
</pinp>
Important: If you are only interested in the contents of a specific element, get the nodeValue
property of that element. Otherwist the result will include the entire element, including xml tags.
preamble
(object) ar('xml')->preamble( $version = '1.0', $encoding = 'UTF-8', $standalone = null )
(string) |
$version |
The XML version number. |
(string) |
$encoding |
The character encoding the XML will use. |
(mixed) |
$standalone |
Either true / 'yes' or false / 'no'. |
This method returns an ar_xmlNode
object containing a valid XML preamble string, like this:
<?xml version="1.0" encoding="UTF-8" ?>
tag
Deprecated in Ariadne > 2.7.3. Use ar_xml::el()
instead.
(object)
ar('xml')->tag( $tagName, ... )
(string) |
$tagName |
The name of the XML tag. |
(array) |
$attributes |
A list of attributes. |
(string) |
$childNodes |
The child nodes as a string or as an ar_xmlNodes object. |
This method returns a new ar_xmlElement
object. You can add as many attributes or childNodes as you want after $tagName
, in any order. All atributes will be merged into one list.
value
(string) ar('xml')->value( $value )
(string) |
$value |
The value to encode. |
Returns a valid XML value string. Special XML characters are encoded as xml entities, except when the value is a valid CDATA enclosure.