ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

MY_Xml_Writer - Easy XML writer library

March 10, 2009 9:12pm

Subscribe [13]
  • #1 / Mar 10, 2009 9:12pm

    JoostV

    527 posts

    This is a very easy to use XML writer library I developed to write XLM for communication with a Flash app. But it can be used to generate any well-formed XML document. Thought I’d share. Any comments welcome, of course 😊

    EDIT: Most recent version is on Github: https://github.com/accent-interactive/xml_writer

    It can be used to create any XML, not matter how deep. Every branche and node can have one or more attributes, if needed. Need CDATA? Just set a parameter to true. The library prints XML directly to screen, setting XML headers first, or it can return the XML as a string. Just place the library in applications/library and you’re good to go.

    Basically, you can add two types of data:
    * branches - you need to start a new branch and end it before adding the next branch
    * nodes - nodes are children to a branch. You do not have to start and end a node, just add it.

    Example use: place this in your controller (of course you would normally collect the data from a database, making the code much cleaner than it is in this example)
    CONTROLLER

    function write_xml() {
        // Load XML writer library
        $this->load->library('MY_Xml_writer');
        
        // Initiate class
        $xml = new MY_Xml_writer;
        $xml->setRootName('my_store');
        $xml->initiate();
        
        // Start branch 1
        $xml->startBranch('cars');
        
        // Set branch 1-1 and its nodes
        $xml->startBranch('car', array('country' => 'usa')); // start branch 1-1
        $xml->addNode('make', 'Ford');
        $xml->addNode('model', 'T-Ford', array(), true);
        $xml->endBranch();
        
        // Set branch 1-2 and its nodes
        $xml->startBranch('car', array('country' => 'Japan')); // start branch
        $xml->addNode('make', 'Toyota');
        $xml->addNode('model', 'Corolla', array(), true);
        $xml->endBranch();
        
        // End branch 1
        $xml->endBranch();
        
        // Start branch 2
        $xml->startBranch('bikes'); // start branch
        
        // Set branch 2-1  and its nodes
        $xml->startBranch('bike', array('country' => 'usa')); // start branch
        $xml->addNode('make', 'Harley-Davidson');
        $xml->addNode('model', 'Soft tail', array(), true);
        $xml->endBranch();
        
        // End branch 2
        $xml->endBranch();
        
        // Print the XML to screen
        $xml->getXml(true);
    }

    This will produce the following XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <my_store>
        <cars>
            <car country="usa">
                <make>Ford</make>
                <model><![CDATA[T-Ford]]></model>
            </car>
            <car country="Japan">
                <make>Toyota</make>
                <model><![CDATA[Corolla]]></model>
            </car>
        </cars>
        <bikes>
            <bike country="usa">
                <make>Harley-Davidson</make>
                <model><![CDATA[Soft tail]]></model>
            </bike>
        </bikes>
    </my_store>

    EXTRA OPTIONS
    Before you call initiate() you can set some XML settings if you wish:

    $xml->setRootName($string); // Set the value of the root tag for this XML. Defaults to 'root'
    $xml->setXmlVersion($string); // Set the value of the XMl version for this XML. Defaults to '1.0'
    $xml->setCharSet($string); // Set the character set for this XML. Defaults to 'UTF-8'
    $xml->setIndentStr($string); // Set indenting for every new node in this XML. Defaults to '    '.
    $xml->setXsltFilePath($string); // Set the XSLT filepath for this XML. This should be an absolute URL. Defaults to '' (no XSL)

    USE A VIEW
    If you do not wish to print, but rather send the XML string to a view file:

    $data['xml'] = $xml->getXml();
    $this->load->view('xml_template', $data);

    LIBRARY SOURCE CODE
    The library code will be in the following post below.

  • #2 / Mar 10, 2009 9:33pm

    JoostV

    527 posts

    LIBRARY SOURCE CODE

    <?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
    /**
     * Class used to write XMl document.
     * Extends XMLWriter (PHP5 only!)
     * 
     * Initialize the class:
     * $this->load->library('MY_Xml_writer');
     * $xml = new MY_Xml_writer;
     * $xml->initiate();
     * 
     * Start a branch with attributes:
     * $xml->startBranch('car', array('country' => 'usa', 'type' => 'racecar'));
     * 
     * End (close) a branch
     * $xml->endBranch();
     * 
     * Add a CDATA node with attributes:
     * $xml->addNode('model', 'Corolla', array('year' => '2002'), true);
     * 
     * Print the XMl directly to screen:
     * $xml->getXml(true);
     * 
     * Pass the XMl to a view file:
     * $data['xml'] = $xml->getXml();
     * $this->load->view('xml_template', $data);
     * 
     * @name /library/Accent/Xml/Accent_Xml_Writer.php
     * @category Accent_application
     * @version 1.0
     * @author Joost van Veen
     * @copyright Accent Webdesign
     * @created: 10 mrt 2009
     */
    class MY_Xml_writer extends XMLWriter
    {
        
        /**
         * Name of the root element for this XMl. Defaults to root.
         */
        private $_rootName = '';
        
        /**
         * XML version. Defaults to 1.0
         */
        private $_xmlVersion = '1.0';
        
        /**
         * Character set. Defaukts to UTF-8.
         */
        private $_charSet = 'UTF-8';
        
        /**
         * Indent for every new tag. Defaults to spaces.  
         */
        private $_indentString = '    ';
        
        /**
         * Sets an xslt path for this XML. Defaults to ''. 
         * Xslt will only be included in the XML if $_xsltFilePath is not an 
         * empty string.
         */
        private $_xsltFilePath = '';
    
        public function __construct ()
        {}
    
        /**
         * Set the value of the root tag for this XML
         */
        public function setRootName ($rootName)
        {
            $this->_rootName = $rootName;
        }
    
        /**
         * Set the value of the XMl version for this XML.
         */
        public function setXmlVersion ($version)
        {
            $this->_xmlVersion = $version;
        }
    
        /**
         * Set the character set for this XML.
         */
        public function setCharSet ($charSet)
        {
            $this->_charSet = $charSet;
        }
    
        /**
         * Set indenting for every new node in this XML.
         */
        public function setIndentStr ($indentString)
        {
            $this->_indentString = $indentString;
        }
    
        /**
         * Set the XSLT filepath for this XML. This should be an absolute URL.
         */
        public function setXsltFilePath ($xsltFilePath)
        {
            $this->_xsltFilePath = $xsltFilePath;
        }
    
        public function initiate ()
        {
            // Create new xmlwriter using memory for string output.
            $this->openMemory();
            
            // Set indenting, if any.
            if ($this->_indentString) {
                $this->setIndent(true);
                $this->setIndentString($this->_indentString);
            }
            
            // Set DTD.
            $this->startDocument($this->_xmlVersion, $this->_charSet);
            
            // Set XSLT stylesheet path, if any.
            if ($this->_xsltFilePath) {
                $this->writePi('xml-stylesheet', 'type="text/xsl" href="' . $this->_xsltFilePath . '"');
            }
            
            // Set the root tag.
            $this->startElement($this->_rootName);
        }
    
        /**
         * Start a new branch that will contain nodes.
         */
        public function startBranch ($name, $attributes = array())
        {
            $this->startElement($name);
            $this->_addAttributes($attributes);
        }
    
        /**
         * End an open branch. A branch needs to be closed explicitely if the branch 
         * is followed directly by another branch.
         */
        public function endBranch ()
        {
            $this->endElement();
        }
    
        /**
         * Add a node, typically a child to a branch.
         * 
         * If you wish to create a simple text node, just set $name and $value.
         * If you wish to create a CDATA node, set $name, $value and $cdata.
         * You can set attributes for every node, passing a key=>value $attributes array
         * 
         * @param string $name
         * @param string $value
         * @param array attributes
         * @param boolean $cdata
         * @return void
         */
        public function addNode ($name, $value, $attributes = array(), $cdata = false)
        {
            /**
             * Set a CDATA element.
             */
            if ($cdata) {
                $this->startElement($name);
                $this->_addAttributes($attributes);
                $this->writeCdata($value);
                $this->endElement();
            }
            /**
             * Set a simple text element.
             */
            else {
                $this->startElement($name);
                $this->_addAttributes($attributes);
                $this->text($value);
                $this->endElement();
            }
        }
    
        /**
         * Close the XML document, print to screen if $echo == true, and return a 
         * string containing the full XML.
         * 
         * @param boolean echo - if true, print XML to screen. 
         * @return string - The full XML.
         */
        public function getXml ($echo = false)
        {
            
            /**
             * Set header.
             */
            if ($echo == true) {
                header('Content-type: text/xml');
            }
            
            /**
             * Close XMl document.
             */
            $this->endElement();
            $this->endDocument();
            
            /**
             * Return or echo output.
             */
            $output = $this->outputMemory();
            if ($echo == true) {
                // Print XML to screen.
                print $output;
            }
            
            return $output;
        }
    
        /**
         * Add attributes to an element.
         * 
         * @param array $attributes
         */
        private function _addAttributes ($attributes)
        {
            if (count($attributes) > 0) {
                // We have attributes, let's set them
                foreach ($attributes as $key => $value) {
                    $this->writeAttribute($key, $value);
                }
            }
        }
    }
  • #3 / Mar 10, 2009 9:46pm

    JoostV

    527 posts

  • #4 / Mar 23, 2009 1:40pm

    spheroid

    49 posts

    Great library. Any way to set an ID for the root element, like:

    <?xml version="1.0"?>
    <item id="Sample">
  • #5 / Mar 23, 2009 3:27pm

    JoostV

    527 posts

    Yep, You can use all the methods in XMLWriter, which is a standard PHP5 class.
    http://nl.php.net/manual/en/book.xmlwriter.php

    $xml->setRootName($string);
    $xml->setRootName('my_store');
    $xml->initiate(); // this basically opens a new branch, i.e. the root branch
    
    $xml->writeAttribute($key, $value); // this adds attributes to the new branch

    Did not have time to test it, but it should work.

  • #6 / Apr 02, 2009 11:17am

    spheroid

    49 posts

    @JoostV: Wanted to say this is a great libary! I’ve been learning AJAX and needed to get XML responses back. This has definitely helped out a great deal!

  • #7 / Apr 02, 2009 11:26am

    JoostV

    527 posts

    Glad to be of help 😊

    Actually, with Ajax, you might be better off using json output. It is not as verbose as XML and there are some great libraries out there to get you started writing json in a jiffy.

  • #8 / Apr 10, 2009 12:09pm

    Shimura

    12 posts

    Hello JoostV,

    I need help about this library, how to make a loop with when i recover data in a array like this $xml->startBranch(‘car’, array(‘country’ => ‘usa’));. 
    And too i need to communicate my XML / SWF with a JS in a flashvar how make this with codeigniter ?

    Thank you.
    (I’m sorry about my English because i’m french).

  • #9 / Apr 10, 2009 12:41pm

    JoostV

    527 posts

    I’m not quite sure what you mean, could you be more specific?

    Do you want to make a loop of cars? Producing something like

    <cars>
        <car country="usa">
            <make>Ford</make>
            <make>Buick</make>
            <make>Chrysler</make>
        </car>
    </cars>
  • #10 / Apr 10, 2009 1:12pm

    Shimura

    12 posts

    Yes like this,
    For example i have my data with the table student and the bases id_student, first_name, last_name, year.

    The xml result :

    <student_data>
        <student year="2009">
            <f_name>Dan</f_name>
            <l_name>Summers</l_name>
        </student >
        <student year="2009">
            ....
        </student >
    </student_data>

    But the problem is about the controller to produce this with $data.

    And always the second problem, how communicate XML/SWF with codeigniter & AS3 ? because i don’t see how i recover the file.xml ?

    Thank you, i appreciate your assistance.

  • #11 / Apr 11, 2009 7:23am

    JoostV

    527 posts

    That’s not too hard. Just fetch some data and loop through it.

    /*Fetch students from database*/
    $this->load->model('students');
    $students = $this->students->get();
    
    /*Initiate XML library*/
    $this->load->library('MY_Xml_writer');
    $xml = new MY_Xml_writer();
    $xml->setRootName('student_data');
    $xml->initiate();
    
    /*Construct XML*/
    foreach ($students as $student) {
        $xml->startBranch('student', array('year' => $student->year));
        $xml->addNode('f_name', $student->f_name);
        $xml->addNode('l_name', $student->l_name);
        $xml->endBranch();
    }
    
    /*Print the XML to screen*/
    $xml->getXml(true);


    As to your second question: just supply the URL that produces this XML to Flash, via Flashvar.

    Say the XML is produced by http://www.example.com/xml/students. Then you would put a Flashvar in your page, like so.

    <script type='text/javascript' src='jscripts/swfobject.js'></script>
    <script type='text/javascript'>
    var s1 = new SWFObject('flashfile.swf','myflashname','400','300','9');
    s1.addParam('flashvars','xml=xml/students');
    s1.write('flashdiv');
    </script>

    Pick up the FlashVar in Flash and load the XML.

  • #12 / Apr 14, 2009 9:59am

    Shimura

    12 posts

    Thank you JoostV, for you helping.

    But i have i little problem : The script return me an error (not with my AMP in local, that’s right but online, i have this : Parse error: syntax error, unexpected T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /.../system/application/libraries/MY_Xml_writer.php on line 40.

  • #13 / Apr 14, 2009 10:11am

    JoostV

    527 posts

    @Shimura: Did you check you have PHP 4.3.0 or higher? The parent class XML was not introduced until then.  http://nl2.php.net/xmlwriter

    EDIT: Also, XML writer needs to be enabled in your php.ini. This comes as default in many PHP installation, but you never know.

  • #14 / Apr 26, 2009 9:25am

    Shimura

    12 posts

    Hello JoostV,

    I need to count the number of node in a foreach :

    For example, i have :

    1</Projet_Graph>
    1</Projet_Graph>
    1</Projet_Graph>

    And i need this :

    3</Projet_Graph>


    PHP :

    foreach ($value as $value2) {

    $xml->addNode('Projet_Graph',count($total));

    }

    Thank you.

  • #15 / Apr 26, 2009 10:45am

    JoostV

    527 posts

    Add a counter and display its value.

    $iCounter = 0;
    foreach ($value as $value2) {
        $xml->addNode('Projet_Graph', $iCounter);
        $iCounter++;
    }

    Hope it helps you out.

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases