]> git.mxchange.org Git - friendica.git/commitdiff
bring in the *much better* xml parser from the original zot branch
authorfriendica <info@friendica.com>
Thu, 17 May 2012 04:29:57 +0000 (21:29 -0700)
committerfriendica <info@friendica.com>
Thu, 17 May 2012 04:29:57 +0000 (21:29 -0700)
include/network.php

index 27a45ec407ddea095b070c59d7b63d4705ee8ca0..eeb2460d140a248d1faba41f414126ca84f36125 100644 (file)
@@ -876,3 +876,167 @@ function fix_contact_ssl_policy(&$contact,$new_policy) {
        }
 }
 
+
+
+/**
+ * xml2array() will convert the given XML text to an array in the XML structure.
+ * Link: http://www.bin-co.com/php/scripts/xml2array/
+ * Portions significantly re-written by mike@macgirvin.com for Friendica (namespaces, lowercase tags, get_attribute default changed, more...)
+ * Arguments : $contents - The XML text
+ *                $namespaces - true or false include namespace information in the returned array as array elements.
+ *                $get_attributes - 1 or 0. If this is 1 the function will get the attributes as well as the tag values - this results in a different array structure in the return value.
+ *                $priority - Can be 'tag' or 'attribute'. This will change the way the resulting array sturcture. For 'tag', the tags are given more importance.
+ * Return: The parsed XML in an array form. Use print_r() to see the resulting array structure.
+ * Examples: $array =  xml2array(file_get_contents('feed.xml'));
+ *              $array =  xml2array(file_get_contents('feed.xml', true, 1, 'attribute'));
+ */ 
+
+function xml2array($contents, $namespaces = true, $get_attributes=1, $priority = 'attribute') {
+    if(!$contents) return array();
+
+    if(!function_exists('xml_parser_create')) {
+        logger('xml2array: parser function missing');
+        return array();
+    }
+
+
+       libxml_use_internal_errors(true);
+       libxml_clear_errors();
+
+       if($namespaces)
+           $parser = @xml_parser_create_ns("UTF-8",':');
+       else
+           $parser = @xml_parser_create();
+
+       if(! $parser) {
+               logger('xml2array: xml_parser_create: no resource');
+               return array();
+       }
+
+    xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); 
+       // http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
+    xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+    xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
+    @xml_parse_into_struct($parser, trim($contents), $xml_values);
+    @xml_parser_free($parser);
+
+    if(! $xml_values) {
+               logger('xml2array: libxml: parse error: ' . $contents, LOGGER_DATA);
+               foreach(libxml_get_errors() as $err)
+                       logger('libxml: parse: ' . $err->code . " at " . $err->line . ":" . $err->column . " : " . $err->message, LOGGER_DATA);
+               libxml_clear_errors();
+               return;
+       }
+
+    //Initializations
+    $xml_array = array();
+    $parents = array();
+    $opened_tags = array();
+    $arr = array();
+
+    $current = &$xml_array; // Reference
+
+    // Go through the tags.
+    $repeated_tag_index = array(); // Multiple tags with same name will be turned into an array
+    foreach($xml_values as $data) {
+        unset($attributes,$value); // Remove existing values, or there will be trouble
+
+        // This command will extract these variables into the foreach scope
+        // tag(string), type(string), level(int), attributes(array).
+        extract($data); // We could use the array by itself, but this cooler.
+
+        $result = array();
+        $attributes_data = array();
+        
+        if(isset($value)) {
+            if($priority == 'tag') $result = $value;
+            else $result['value'] = $value; // Put the value in a assoc array if we are in the 'Attribute' mode
+        }
+
+        //Set the attributes too.
+        if(isset($attributes) and $get_attributes) {
+            foreach($attributes as $attr => $val) {
+                if($priority == 'tag') $attributes_data[$attr] = $val;
+                else $result['@attributes'][$attr] = $val; // Set all the attributes in a array called 'attr'
+            }
+        }
+
+        // See tag status and do the needed.
+               if($namespaces && strpos($tag,':')) {
+                       $namespc = substr($tag,0,strrpos($tag,':')); 
+                       $tag = strtolower(substr($tag,strlen($namespc)+1));
+                       $result['@namespace'] = $namespc;
+               }
+               $tag = strtolower($tag);
+
+               if($type == "open") {   // The starting of the tag '<tag>'
+            $parent[$level-1] = &$current;
+            if(!is_array($current) or (!in_array($tag, array_keys($current)))) { // Insert New tag
+                $current[$tag] = $result;
+                if($attributes_data) $current[$tag. '_attr'] = $attributes_data;
+                $repeated_tag_index[$tag.'_'.$level] = 1;
+
+                $current = &$current[$tag];
+
+            } else { // There was another element with the same tag name
+
+                if(isset($current[$tag][0])) { // If there is a 0th element it is already an array
+                    $current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;
+                    $repeated_tag_index[$tag.'_'.$level]++;
+                } else { // This section will make the value an array if multiple tags with the same name appear together
+                    $current[$tag] = array($current[$tag],$result); // This will combine the existing item and the new item together to make an array
+                    $repeated_tag_index[$tag.'_'.$level] = 2;
+                    
+                    if(isset($current[$tag.'_attr'])) { // The attribute of the last(0th) tag must be moved as well
+                        $current[$tag]['0_attr'] = $current[$tag.'_attr'];
+                        unset($current[$tag.'_attr']);
+                    }
+
+                }
+                $last_item_index = $repeated_tag_index[$tag.'_'.$level]-1;
+                $current = &$current[$tag][$last_item_index];
+            }
+
+        } elseif($type == "complete") { // Tags that ends in 1 line '<tag />'
+            //See if the key is already taken.
+            if(!isset($current[$tag])) { //New Key
+                $current[$tag] = $result;
+                $repeated_tag_index[$tag.'_'.$level] = 1;
+                if($priority == 'tag' and $attributes_data) $current[$tag. '_attr'] = $attributes_data;
+
+            } else { // If taken, put all things inside a list(array)
+                if(isset($current[$tag][0]) and is_array($current[$tag])) { // If it is already an array...
+
+                    // ...push the new element into that array.
+                    $current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;
+                    
+                    if($priority == 'tag' and $get_attributes and $attributes_data) {
+                        $current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
+                    }
+                    $repeated_tag_index[$tag.'_'.$level]++;
+
+                } else { // If it is not an array...
+                    $current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value
+                    $repeated_tag_index[$tag.'_'.$level] = 1;
+                    if($priority == 'tag' and $get_attributes) {
+                        if(isset($current[$tag.'_attr'])) { // The attribute of the last(0th) tag must be moved as well
+                            
+                            $current[$tag]['0_attr'] = $current[$tag.'_attr'];
+                            unset($current[$tag.'_attr']);
+                        }
+                        
+                        if($attributes_data) {
+                            $current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
+                        }
+                    }
+                    $repeated_tag_index[$tag.'_'.$level]++; // 0 and 1 indexes are already taken
+                }
+            }
+
+        } elseif($type == 'close') { // End of tag '</tag>'
+            $current = &$parent[$level-1];
+        }
+    }
+    
+    return($xml_array);
+}