0

I'm developing on a server using an old version of PHP (4.3.9), and I'm trying to convert an XML string into a JSON string. This is easy in PHP5, but a lot tougher with PHP4.

I've tried:

Zend JSON.php

require_once 'Zend/Json.php';
echo Zend_Json::encode($sxml);

Error:
PHP Parse error: parse error, unexpected T_CONST, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or '}'

simplexml44

$impl = new IsterXmlSimpleXMLImpl;
$NDFDxmltemp = $impl->load_file($NDFDstring);
$NDFDxml = $NDFDxmltemp->asXML();

Error:
WARNING isterxmlexpatnonvalid->parse(): nothing to read

xml_parse

$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, "_start_element", "_end_element");
xml_set_character_data_handler($xml_parser, "_character_data");  
xml_parse($xml_parser, $NDFDstring);

Error:
PHP Warning: xml_parse(): Unable to call handler _character_data() in ...
PHP Warning: xml_parse(): Unable to call handler _end_element() in ...

Does anyone have any other alternatives to simplexml_file_load() and new simpleXMLelement in PHP4?

Upgrading PHP is not an option in this particular case, so do not bother bringing it up. Yes, I know its old.

NOTE: This is the XML I'm trying to parse into a multidimensional array OR json. http://graphical.weather.gov/xml/sample_products/browser_interface/ndfdXMLclient.php?lat=40&lon=-120&product=time-series&begin=2013-10-30T00:00:00&end=2013-11-06T00:00:00&maxt=maxt&mint=mint&rh=rh&wx=wx&wspd=wspd&wdir=wdir&icons=icons&wgust=wgust&pop12=pop12&maxrh=maxrh&minrh=minrh&qpf=qpf&snow=snow&temp=temp&wwa=wwa

DrewP84
  • 383
  • 3
  • 16

2 Answers2

2

XML are quite easy to parse by yourself, anyway here is exists xml_parse in php 4 and domxml_open_file

and here is json for php4 and another one

according parsing xml:

if you know the structure of xml file, you can go even with RegExp, as XML is strict format (I mean all tags must be closed, all attributes in quotes, all special symbols always escaped)

if you parse arbitrary xml file, here is student sample, which works with php4, do not understand all XML features, but can give you "brute-force" like idea:

<?php
    define("LWG_XML_ELEMENT_NULL", "0");
    define("LWG_XML_ELEMENT_NODE", "1");

    function EntitiesToString($str)
    {
        $s = $str;

        $s = eregi_replace("&quot;", "\"", $s);
        $s = eregi_replace("&lt;", "<", $s);
        $s = eregi_replace("&gt;", ">", $s);
        $s = eregi_replace("&amp;", "&", $s);

        return $s;
    }

    class CLWG_dom_attribute
    {
        var $name;
        var $value;

        function CLWG_dom_attribute()
        {
            $name = "";
            $value = "";
        }
    }

    class CLWG_dom_node
    {
        var $m_Attributes;
        var $m_Childs;

        var $m_nAttributesCount;
        var $m_nChildsCount;

        var $type;
        var $tagname;
        var $content;

        function CLWG_dom_node()
        {
            $this->m_Attributes = array();
            $this->m_Childs = array();

            $this->m_nAttributesCount = 0;
            $this->m_nChildsCount = 0;

            $this->type = LWG_XML_ELEMENT_NULL;
            $this->tagname = "";
            $this->content = "";
        }

        function get_attribute($attr_name)
        {
            //echo "<message>Get Attribute: ".$attr_name." ";
            for ($i=0; $i<sizeof($this->m_Attributes); $i++)
                if ($this->m_Attributes[$i]->name == $attr_name)
                {
                    //echo $this->m_Attributes[$i]->value . "</message>\n";
                    return $this->m_Attributes[$i]->value;
                }
            //echo "[empty]</message>\n";
            return "";
        }
        function get_content()
        {
            //echo "<message>Get Content: ".$this->content . "</message>\n";
            return $this->content;
        }

        function attributes()
        {
            return $this->m_Attributes;
        }
        function child_nodes()
        {
            return $this->m_Childs;
        }

        function loadXML($str, &$i)
        {
            //echo "<debug>DEBUG: LoadXML (".$i.": ".$str[$i].")</debug>\n";
            $str_len = strlen($str);

            //echo "<debug>DEBUG: start searching for tag (".$i.": ".$str[$i].")</debug>\n";
            while ( ($i<$str_len) && ($str[$i] != "<") )
                $i++;
            if ($i == $str_len) return FALSE;
            $i++;

            while ( ($i<strlen($str)) && ($str[$i] != " ") && ($str[$i] != "/") && ($str[$i] != ">") )
                $this->tagname .= $str[$i++];

            //echo "<debug>DEBUG: Tag: " . $this->tagname . "</debug>\n";

            if ($i == $str_len) return FALSE;
            switch ($str[$i])
            {
                case " ": // attributes comming
                {
                    //echo "<debug>DEBUG: Tag: start searching attributes</debug>\n";
                    $i++;
                    $cnt = sizeof($this->m_Attributes);
                    while ( ($i<strlen($str)) && ($str[$i] != "/") && ($str[$i] != ">") )
                    {
                        $this->m_Attributes[$cnt] = new CLWG_dom_attribute;
                        while ( ($i<strlen($str)) && ($str[$i] != "=") )
                            $this->m_Attributes[$cnt]->name .= $str[$i++];
                        if ($i == $str_len) return FALSE;
                        $i++;
                        while ( ($i<strlen($str)) && ($str[$i] != "\"") )
                            $i++;
                        if ($i == $str_len) return FALSE;
                        $i++;
                        while ( ($i<strlen($str)) && ($str[$i] != "\"") )
                            $this->m_Attributes[$cnt]->value .= $str[$i++];

                        $this->m_Attributes[$cnt]->value = EntitiesToString($this->m_Attributes[$cnt]->value);

                        //echo "<debug>DEBUG: Tag: Attribute: '".$this->m_Attributes[$cnt]->name."' = '".$this->m_Attributes[$cnt]->value."'</debug>\n";

                        if ($i == $str_len) return FALSE;
                        $i++;
                        if ($i == $str_len) return FALSE;
                        while ( ($i<strlen($str)) && ($str[$i] == " ") )
                            $i++;

                        $cnt++;
                    }
                    if ($i == $str_len) return FALSE;
                    switch ($str[$i])
                    {
                        case "/":
                        {
                            //echo "<debug>DEBUG: self closing tag with attributes (".$this->tagname.")</debug>\n";
                            $i++;
                            if ($i == $str_len) return FALSE;
                            if ($str[$i] != ">") return FALSE;
                            $i++;
                            return TRUE;
                            break;
                        }
                        case ">";
                        {
                            //echo "<debug>DEBUG: end of attributes (".$this->tagname.")</debug>\n";
                            $i++;
                            break;
                        }
                    }
                    break;
                }
                case "/": // self closing tag
                {
                    //echo "<debug>DEBUG: self closing tag (".$this->tagname.")</debug>\n";
                    $i++;
                    if ($i == $str_len) return FALSE;
                    if ($str[$i] != ">") return FALSE;
                    $i++;
                    return TRUE;
                    break;
                }
                case ">": // end of begin of node
                {
                    //echo "<debug>DEBUG: end of begin of node</debug>\n";
                    $i++;
                    break;
                }
            }
            if ($i == $str_len) return FALSE;

            $b = 1;

            while ( ($i<$str_len) && ($b) )
            {
                //echo "<debug>DEBUG: searching for content</debug>\n";
                while ( ($i<strlen($str)) && ($str[$i] != "<") )
                    $this->content .= $str[$i++];
                //echo "<debug>DEBUG: content: ".$this->content."</debug>\n";
                if ($i == $str_len) return FALSE;
                $i++;
                if ($i == $str_len) return FALSE;
                if ($str[$i] != "/") // new child
                {
                    $cnt = sizeof($this->m_Childs);
                    //echo "<debug>DEBUG: Create new child (" . $cnt . ")</debug>\n";

                    $this->m_Childs[$cnt] = new CLWG_dom_node;
                    $this->m_Childs[$cnt]->type = LWG_XML_ELEMENT_NODE;
                    $i--;
                    if ($this->m_Childs[$cnt]->loadXML($str, $i) === FALSE)
                        return FALSE;
                }
                else
                    $b = 0;
            }

            $i++;
            $close_tag = "";
            while ( ($i<strlen($str)) && ($str[$i] != ">") )
                $close_tag .= $str[$i++];
            //echo "<debug>DEBUG: close tag: ".$close_tag." - ".$this->tagname."</debug>\n";
            if ($i == $str_len) return FALSE;
            $i++;

            $this->content = EntitiesToString($this->content);
            //echo "<debug>DEBUG: content: ".$this->content."</debug>\n";

            return ($close_tag == $this->tagname);
        }
    }

    class CLWG_dom_xml
    {
        var $m_Root;

        function CLWG_dom_xml()
        {
            $this->m_Root = 0;
        }

        function document_element()
        {
            return $this->m_Root;
        }

        function loadXML($xml_string)
        {
            // check xml tag
            if (eregi("<\\?xml", $xml_string))
            {
                // check xml version
                $xml_version = array();
                if ( (eregi("<\\?xml version=\"([0-9\\.]+)\".*\\?>", $xml_string, $xml_version)) && ($xml_version[1] == 1.0) )
                {
                    // initialize root
                    $this->m_Root = new CLWG_dom_node;
                    $i = 0;
                    return $this->m_Root->loadXML(eregi_replace("<\\?xml.*\\?>", "", $xml_string), $i);
                }
                else
                {
                    echo "<error>Cannot find version attribute in xml tag</error>";
                    return FALSE;
                }
            }
            else
            {
                echo "<error>Cannot find xml tag</error>";
                return FALSE;
            }
        }
    }

    function lwg_domxml_open_mem($xml_string)
    {
        global $lwg_xml;
        $lwg_xml = new CLWG_dom_xml;

        if ($lwg_xml->loadXML($xml_string))
            return $lwg_xml;
        else
            return 0;
    }
?>
Iłya Bursov
  • 23,342
  • 4
  • 33
  • 57
  • +1 for the link to `xml_parse`, but -1 for "quite easy to parse by yourself" - no way should you be using anything other than a proper XML parser. Unless you just meant "easy to use a lower-level parser to build your own object/array structure"? – IMSoP Oct 30 '13 at 20:55
  • @IMSoP I mean that you can write your own XML parser with php, which will not depend on any modules, just pure finite-state machine – Iłya Bursov Oct 30 '13 at 20:58
  • I'm not sure I'd call that "easy". Possible, maybe, but you'd need to really know what you were doing. – IMSoP Oct 30 '13 at 21:02
  • 1
    @IMSoP Yea, I'm not sure I'd pull that off flawlessly. – DrewP84 Oct 30 '13 at 21:07
  • @IMSoP XML is very strict format, back in 2005 I gave my students task to write such parser, usually takes 1-4 hours – Iłya Bursov Oct 30 '13 at 21:08
  • 4
    How complex were the test cases that your students had to pass? CDATA? Comments? Processing Instructions? Namespaces? Character encoding of input files? I can certainly imagine a parser being written in that short a time, but I'm not sure I'd want to rely on it for more than a very constrained purpose. – IMSoP Oct 30 '13 at 21:14
  • @IMSoP it is not right place to discuss it, but parsing of proper XML file is very easy task, no matter is it cdata/comments/etc in it, as they all under same or similar format, maybe you're mistaken with xml/xlst processing? – Iłya Bursov Oct 30 '13 at 21:34
  • @IlyaBursov I've never written an XML parser. Does the XML I linked look difficult to parse? – DrewP84 Oct 30 '13 at 21:36
  • 1
    OK, fair enough - it's certainly simple *as parsers go*, but not everybody has written a finite state machine before, nor has the experience to make a robust set of test cases so that future input won't trip up the parser. Perhaps your answer could include some tips on good approaches to take and pitfalls to look out for? – IMSoP Oct 30 '13 at 21:41
  • @IMSoP I've posted code of sample parser, not sure how much time was spend, but about 2 hours – Iłya Bursov Oct 30 '13 at 21:53
1

PHP4 has no support for ArrayAccess nor does it have the needed __get(), __set() and __toString() magic methods which effectively prevents you from creating an object mimicking that feature of SimpleXMLElement.

Also I'd say creating an in-memory structure yourself which is done by Simplexml is not going to work out well with PHP 4 because of it's limitation of the OOP-object-model and garbage collection. Especially as I would prefer something like the Flyweight pattern here.

Which brings me to the point that you're probably more looking for an event or pull-based XML parser.

Take a look at the XML Parser Functions which are the PHP 4 way to parse XML with PHP. You find it well explained in years old PHP training materials also with examples and what not.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • 1
    Also left some code on the duplicate question: http://stackoverflow.com/a/19740953/367456 – hakre Nov 02 '13 at 10:38