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 ']]&gt;'.

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.