1

In CakePHP I know the XML-class in cake.libs. What I like on this easy to use class is the fact that you can convert an array to xml with attributes.
On a current project I'm working with Zend Framework and I am missing this nice class.

Does anybody know how I can convert an PHP-array to XML with attributes easily?

I tried this one but unfortunately its not easy to handle result arrays from database cause you have to define the attributes inside the array.

Maybe I have missed something in ZF? Or does anybody know how to adapt the CakePHP class to ZF?

Many thanks for any helpful hints.

3

4 Answers 4

2

This function will allow you to create XML document with simple PHP array variable. Nodes are just stacked onto each other and naming it 'Attribute_XXX' will add atribute XXX to that parent node.

function to_xml(SimpleXMLElement $object, array $data)
{
    $attr = "Attribute_";
    foreach ($data as $key => $value) {
        if (is_array($value)) {
            $new_object = $object->addChild($key);
            to_xml($new_object, $value);
        } else {
            if(strpos($key, $attr) !== false){
                $object->addAttribute(substr($key, strlen($attr)), $value);
            }else{
                $object->addChild($key, $value);
            }
        }
    }
}

Usage:

$my_array = array (
    'TagN1' => array (
        'TagInsideOfIt' => array (
            'Atrribute_IDuser' => 'anything',
            'RegularTag' => 'whatever',
            'Address' => array(
                'Attribute_ID' => '111',
                'Attribute_key' => 'aaa',
                'Company' => 'Google Inc.'
            )
        )
    )
);

$xml = new SimpleXMLElement('<root/>');

to_xml($xml, $my_array);

Header('Content-type: text/xml');
print($xml->asXML());
Sign up to request clarification or add additional context in comments.

Comments

0

You can get some answers at this URL How to convert array to SimpleXML

An alternative/fast and easy approach would be to convert array data into JSON, that would be faster as well using Zend library. Converting array into JSON is very easy as using follows functions.

Zend_Json::encode() and Zend_Json_Encoder::encode()

Comments

0

Tanks, a using the code of @jezda159 and i modified for me, this is my code:

the array:

   $elements_array = array(
            "node" => array(
                "subnode" => array(
                    "[attribute]" => "valueOfAttribute",
                    "[second-attribute]" => "valueOfAttribute",
                    "second-subnode" => array(
                        "[attribute]" => "valueOfAttribute",
                        "[second-attribute]" => "valueOfAttribute",
                    ),
                    "ListOfElements" => array(
                        "one",
                        "two",
                        "tree"
                    )
                )
            ),
        );

The code:

    function array_to_xml($data, $object){
        foreach ($data as $key => $value) {
            $keyname = is_numeric( $key ) ? "item".$key : $key;
            if (is_array($value)) {
                $new_object = $object->addChild($keyname);
                array_to_xml($value, $new_object);
            } else {
                preg_match("#\[([a-z0-9-_]+)\]#i", $keyname, $attr);
                if( count($attr) ){
                    $object->addAttribute($attr[1], $value);
                }else{
                    $object->addChild($keyname, $value);
                }
            }
        }
    }
$xml_user_info = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" ?><Elements></Elements>');

//function call to convert array to xml
array_to_xml($elements_array,$xml_user_info);
header('Content-type: text/xml');
//show generated xml file
echo $xml_user_info->asXML();

The result:

<?xml version="1.0" encoding="UTF-8"?>
<Elements>
<node>
<subnode attribute="valueOfAttribute" second-attribute="valueOfAttribute">
<second-subnode attribute="valueOfAttribute" second-attribute="valueOfAttribute"/>
<ListOfElements>
<item0>one</item0>
<item1>two</item1>
<item2>tree</item2>
</ListOfElements>
</subnode>
</node>
</Elements>

Comments

0

I tried several answers from stackoverflow but all of they had problems with repeated tags which cannot be easily done within one array, and with attributes so I modified a class I got from PHP - XMLWriter write nested array to file

I did a little trick adding some special characters to they key or the array. ### for nested elements I need to place the same tag, and @@@ for attributes. Check the XML example below.

Here's the class:

<?php

/* Key of the arrays will be the tags of the XML
    It's allowed to place on the keys of the arrays structure like this:
        'foo attribute1=value1 attribute2=value2' => 'bar'

    And it will create the attributes for that tag
*/
class XmlConstruct extends XMLWriter
{

    /**
     * Constructor.
     * @param string $prm_rootElementName A root element's name of a current xml document
     * @param string $prm_xsltFilePath Path of a XSLT file.
     * @access public
     * @param null
     */
    public function __construct($prm_rootElementName, $prm_xsltFilePath = '')
    {
        $this->openMemory();
        $this->setIndent(true);
        $this->setIndentString("\t");
        $this->startDocument('1.0', 'UTF-8');

        if ($prm_xsltFilePath) {
            $this->writePi('xml-stylesheet', 'type="text/xsl" href="' . $prm_xsltFilePath . '"');
        }

        $this->startElementWithAttrs( $prm_rootElementName );       
    }

    /**
     * Creates a XML element taking care if tye key of the array has attributes we should add to the XML
     * @access private
     * @param string $prm_elementName An element's name, which can contain attributes
     * @return null
     */
    function startElementWithAttrs( $prm_elementName )
    {
        // Checking if key of array has attributes
        $attrArray = explode('@@@', $prm_elementName);
        $tag = array_shift($attrArray);

        // Only numbers tags in XML are not allowed
        if ( is_numeric($tag) ) {
            $tag = 'num' . $tag;
        }

        if ( $pos = strpos($tag, '###') ) {
            // If tag has ### means we need to repeat that tag on the XML. Removing ### till the end.
            $tag = substr($tag, 0, $pos);
        }

        $this->startElement($tag);

        foreach ( $attrArray as $attr) {
            list($attr_name, $attr_value) = explode( '=', trim($attr) );
            $this->writeAttribute( $attr_name, $attr_value );
        }
    }

    /**
     * Set an element with a text to a current xml document.
     * @access public
     * @param string $prm_elementName An element's name
     * @param string $prm_ElementText An element's text
     * @return null
     */
    public function setElement($prm_elementName, $prm_ElementText)
    {
        $this->startElementWithAttrs($prm_elementName);
        $this->text($prm_ElementText);
        $this->endElement();
    }

    /**
     * Construct elements and texts from an array.
     * The array should contain an attribute's name in index part
     * and a attribute's text in value part.
     * @access public
     * @param array $prm_array Contains attributes and texts
     * @return null
     */
    public function fromArray($prm_array)
    {
        if ( is_array($prm_array) ) {
            foreach ($prm_array as $index=>$element) {
                if ( is_array($element) ) {
                    $this->startElementWithAttrs($index);
                    $this->fromArray($element);
                    $this->endElement();
                } else {
                    $this->setElement($index, $element);
                }
            }
        }
    }

    /**
     * Return the content of a current xml document.
     * @access public
     * @param null
     * @return string Xml document
     */

    public function getDocument()
    {
        $this->endElement();
        $this->endDocument();
        return $this->outputMemory();
    }

    /**
     * Output the content of a current xml document.
     * @access public
     * @param null
     */

    public function output()
    {
        header('Content-type: text/xml');
        echo $this->getDocument();
    }
}

Here's a full example:

$arr['catalog@@@name=Catalog Name@@@tag=One tag'] = array(
    'cd###1'=>array(
        'title'=>'Empire Burlesque',
        'ARTIST'=>'Bob Dylan',
        'COUNTRY'=>'USA',
        'COMPANY'=>'Columbia',
        'PRICE'=>'10.90',
        'YEAR'=>'1985'
    ),
    'cd###2'=>array(
        'title'=>'Hide your heart',
        'ARTIST'=>'Bonnie Tyler',
        'COUNTRY'=>'USA',
        'COMPANY'=>'CBS Records',
        'PRICE'=>'9.90',
        'YEAR'=>'1988'
    ),
    'cd###3@@@active=yes'=>array(
        'title'=>'Greatest Hits',
        'ARTIST'=>'Dolly Parton',
        'COUNTRY'=>'USA',
        'COMPANY'=>'RCA',
        'PRICE'=>'9.90',
        'YEAR'=>'1982'
    ),
    'cd###4'=>array(
        'title'=>'Still got the blues',
        'ARTIST'=>'Gary Moore',
        'COUNTRY'=>'UK',
        'COMPANY'=>'Virgin records',
        'PRICE'=>'10.20',
        'YEAR'=>'1990'
    ),
    'lastUpdate'=>'2024-01-01 12:30'
);


$XmlConstruct = new XmlConstruct('root');
$XmlConstruct->fromArray($arr);
echo $XmlConstruct->getDocument();

This it's the result:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <catalog name="Catalog Name" tag="One tag">
        <cd>
            <title>Empire Burlesque</title>
            <ARTIST>Bob Dylan</ARTIST>
            <COUNTRY>USA</COUNTRY>
            <COMPANY>Columbia</COMPANY>
            <PRICE>10.90</PRICE>
            <YEAR>1985</YEAR>
        </cd>
        <cd>
            <title>Hide your heart</title>
            <ARTIST>Bonnie Tyler</ARTIST>
            <COUNTRY>USA</COUNTRY>
            <COMPANY>CBS Records</COMPANY>
            <PRICE>9.90</PRICE>
            <YEAR>1988</YEAR>
        </cd>
        <cd active="yes">
            <title>Greatest Hits</title>
            <ARTIST>Dolly Parton</ARTIST>
            <COUNTRY>USA</COUNTRY>
            <COMPANY>RCA</COMPANY>
            <PRICE>9.90</PRICE>
            <YEAR>1982</YEAR>
        </cd>
        <cd>
            <title>Still got the blues</title>
            <ARTIST>Gary Moore</ARTIST>
            <COUNTRY>UK</COUNTRY>
            <COMPANY>Virgin records</COMPANY>
            <PRICE>10.20</PRICE>
            <YEAR>1990</YEAR>
        </cd>
        <lastUpdate>2024-01-01 12:30</lastUpdate>
    </catalog>
</root>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.