206 } |
213 } |
207 return $value; |
214 return $value; |
208 } |
215 } |
209 |
216 |
210 /** |
217 /** |
211 * fromXml - Converts XML to JSON |
218 * Return the value of an XML attribute text or the text between |
212 * |
219 * the XML tags |
213 * Converts a XML formatted string into a JSON formatted string. |
220 * |
214 * The value returned will be a string in JSON format. |
221 * In order to allow Zend_Json_Expr from xml, we check if the node |
215 * |
222 * matchs the pattern that try to detect if it is a new Zend_Json_Expr |
216 * The caller of this function needs to provide only the first parameter, |
223 * if it matches, we return a new Zend_Json_Expr instead of a text node |
217 * which is an XML formatted String. The second parameter is optional, which |
224 * |
218 * lets the user to select if the XML attributes in the input XML string |
225 * @param SimpleXMLElement $simpleXmlElementObject |
219 * should be included or ignored in xml2json conversion. |
226 * @return Zend_Json_Expr|string |
220 * |
227 */ |
221 * This function converts the XML formatted string into a PHP array by |
228 protected static function _getXmlValue($simpleXmlElementObject) { |
222 * calling a recursive (protected static) function in this class. Then, it |
229 $pattern = '/^[\s]*new Zend_Json_Expr[\s]*\([\s]*[\"\']{1}(.*)[\"\']{1}[\s]*\)[\s]*$/'; |
223 * converts that PHP array into JSON by calling the "encode" static funcion. |
230 $matchings = array(); |
224 * |
231 $match = preg_match ($pattern, $simpleXmlElementObject, $matchings); |
225 * Throws a Zend_Json_Exception if the input not a XML formatted string. |
232 if ($match) { |
226 * NOTE: Encoding native javascript expressions via Zend_Json_Expr is not possible. |
233 return new Zend_Json_Expr($matchings[1]); |
227 * |
234 } else { |
228 * @static |
235 return (trim(strval($simpleXmlElementObject))); |
229 * @access public |
236 } |
230 * @param string $xmlStringContents XML String to be converted |
237 } |
231 * @param boolean $ignoreXmlAttributes Include or exclude XML attributes in |
|
232 * the xml2json conversion process. |
|
233 * @return mixed - JSON formatted string on success |
|
234 * @throws Zend_Json_Exception |
|
235 */ |
|
236 public static function fromXml ($xmlStringContents, $ignoreXmlAttributes=true) { |
|
237 // Load the XML formatted string into a Simple XML Element object. |
|
238 $simpleXmlElementObject = simplexml_load_string($xmlStringContents); |
|
239 |
|
240 // If it is not a valid XML content, throw an exception. |
|
241 if ($simpleXmlElementObject == null) { |
|
242 require_once 'Zend/Json/Exception.php'; |
|
243 throw new Zend_Json_Exception('Function fromXml was called with an invalid XML formatted string.'); |
|
244 } // End of if ($simpleXmlElementObject == null) |
|
245 |
|
246 $resultArray = null; |
|
247 |
|
248 // Call the recursive function to convert the XML into a PHP array. |
|
249 $resultArray = self::_processXml($simpleXmlElementObject, $ignoreXmlAttributes); |
|
250 |
|
251 // Convert the PHP array to JSON using Zend_Json encode method. |
|
252 // It is just that simple. |
|
253 $jsonStringOutput = self::encode($resultArray); |
|
254 return($jsonStringOutput); |
|
255 } // End of function fromXml. |
|
256 |
|
257 /** |
238 /** |
258 * _processXml - Contains the logic for xml2json |
239 * _processXml - Contains the logic for xml2json |
259 * |
240 * |
260 * The logic in this function is a recursive one. |
241 * The logic in this function is a recursive one. |
261 * |
242 * |
268 * calling a recursive (protected static) function in this class. Once all |
249 * calling a recursive (protected static) function in this class. Once all |
269 * the XML elements are stored in the PHP array, it is returned to the caller. |
250 * the XML elements are stored in the PHP array, it is returned to the caller. |
270 * |
251 * |
271 * Throws a Zend_Json_Exception if the XML tree is deeper than the allowed limit. |
252 * Throws a Zend_Json_Exception if the XML tree is deeper than the allowed limit. |
272 * |
253 * |
273 * @static |
254 * @param SimpleXMLElement $simpleXmlElementObject |
274 * @access protected |
255 * @param boolean $ignoreXmlAttributes |
275 * @param SimpleXMLElement $simpleXmlElementObject XML element to be converted |
256 * @param integer $recursionDepth |
276 * @param boolean $ignoreXmlAttributes Include or exclude XML attributes in |
257 * @return array |
277 * the xml2json conversion process. |
258 */ |
278 * @param int $recursionDepth Current recursion depth of this function |
259 protected static function _processXml($simpleXmlElementObject, $ignoreXmlAttributes, $recursionDepth=0) |
279 * @return mixed - On success, a PHP associative array of traversed XML elements |
260 { |
280 * @throws Zend_Json_Exception |
|
281 */ |
|
282 protected static function _processXml ($simpleXmlElementObject, $ignoreXmlAttributes, $recursionDepth=0) { |
|
283 // Keep an eye on how deeply we are involved in recursion. |
261 // Keep an eye on how deeply we are involved in recursion. |
284 if ($recursionDepth > self::$maxRecursionDepthAllowed) { |
262 if ($recursionDepth > self::$maxRecursionDepthAllowed) { |
285 // XML tree is too deep. Exit now by throwing an exception. |
263 // XML tree is too deep. Exit now by throwing an exception. |
286 require_once 'Zend/Json/Exception.php'; |
264 require_once 'Zend/Json/Exception.php'; |
287 throw new Zend_Json_Exception( |
265 throw new Zend_Json_Exception( |
288 "Function _processXml exceeded the allowed recursion depth of " . |
266 "Function _processXml exceeded the allowed recursion depth of " . |
289 self::$maxRecursionDepthAllowed); |
267 self::$maxRecursionDepthAllowed); |
290 } // End of if ($recursionDepth > self::$maxRecursionDepthAllowed) |
268 } // End of if ($recursionDepth > self::$maxRecursionDepthAllowed) |
291 |
269 |
292 if ($recursionDepth == 0) { |
270 $children = $simpleXmlElementObject->children(); |
293 // Store the original SimpleXmlElementObject sent by the caller. |
271 $name = $simpleXmlElementObject->getName(); |
294 // We will need it at the very end when we return from here for good. |
272 $value = self::_getXmlValue($simpleXmlElementObject); |
295 $callerProvidedSimpleXmlElementObject = $simpleXmlElementObject; |
273 $attributes = (array) $simpleXmlElementObject->attributes(); |
296 } // End of if ($recursionDepth == 0) |
274 |
297 |
275 if (count($children) == 0) { |
298 if ($simpleXmlElementObject instanceof SimpleXMLElement) { |
276 if (!empty($attributes) && !$ignoreXmlAttributes) { |
299 // Get a copy of the simpleXmlElementObject |
277 foreach ($attributes['@attributes'] as $k => $v) { |
300 $copyOfSimpleXmlElementObject = $simpleXmlElementObject; |
278 $attributes['@attributes'][$k]= self::_getXmlValue($v); |
301 // Get the object variables in the SimpleXmlElement object for us to iterate. |
279 } |
302 $simpleXmlElementObject = get_object_vars($simpleXmlElementObject); |
280 if (!empty($value)) { |
303 } // End of if (get_class($simpleXmlElementObject) == "SimpleXMLElement") |
281 $attributes['@text'] = $value; |
304 |
282 } |
305 // It needs to be an array of object variables. |
283 return array($name => $attributes); |
306 if (is_array($simpleXmlElementObject)) { |
284 } else { |
307 // Initialize a result array. |
285 return array($name => $value); |
308 $resultArray = array(); |
286 } |
309 // Is the input array size 0? Then, we reached the rare CDATA text if any. |
|
310 if (count($simpleXmlElementObject) <= 0) { |
|
311 // Let us return the lonely CDATA. It could even be |
|
312 // an empty element or just filled with whitespaces. |
|
313 return (trim(strval($copyOfSimpleXmlElementObject))); |
|
314 } // End of if (count($simpleXmlElementObject) <= 0) |
|
315 |
|
316 // Let us walk through the child elements now. |
|
317 foreach($simpleXmlElementObject as $key=>$value) { |
|
318 // Check if we need to ignore the XML attributes. |
|
319 // If yes, you can skip processing the XML attributes. |
|
320 // Otherwise, add the XML attributes to the result array. |
|
321 if(($ignoreXmlAttributes == true) && (is_string($key)) && ($key == "@attributes")) { |
|
322 continue; |
|
323 } // End of if(($ignoreXmlAttributes == true) && ($key == "@attributes")) |
|
324 |
|
325 // Let us recursively process the current XML element we just visited. |
|
326 // Increase the recursion depth by one. |
|
327 $recursionDepth++; |
|
328 $resultArray[$key] = self::_processXml ($value, $ignoreXmlAttributes, $recursionDepth); |
|
329 |
|
330 // Decrease the recursion depth by one. |
|
331 $recursionDepth--; |
|
332 } // End of foreach($simpleXmlElementObject as $key=>$value) { |
|
333 |
|
334 if ($recursionDepth == 0) { |
|
335 // That is it. We are heading to the exit now. |
|
336 // Set the XML root element name as the root [top-level] key of |
|
337 // the associative array that we are going to return to the original |
|
338 // caller of this recursive function. |
|
339 $tempArray = $resultArray; |
|
340 $resultArray = array(); |
|
341 $resultArray[$callerProvidedSimpleXmlElementObject->getName()] = $tempArray; |
|
342 } // End of if ($recursionDepth == 0) |
|
343 |
|
344 return($resultArray); |
|
345 } else { |
287 } else { |
346 // We are now looking at either the XML attribute text or |
288 $childArray= array(); |
347 // the text between the XML tags. |
289 foreach ($children as $child) { |
348 |
290 $childname = $child->getName(); |
349 // In order to allow Zend_Json_Expr from xml, we check if the node |
291 $element = self::_processXml($child,$ignoreXmlAttributes,$recursionDepth+1); |
350 // matchs the pattern that try to detect if it is a new Zend_Json_Expr |
292 if (array_key_exists($childname, $childArray)) { |
351 // if it matches, we return a new Zend_Json_Expr instead of a text node |
293 if (empty($subChild[$childname])) { |
352 $pattern = '/^[\s]*new Zend_Json_Expr[\s]*\([\s]*[\"\']{1}(.*)[\"\']{1}[\s]*\)[\s]*$/'; |
294 $childArray[$childname] = array($childArray[$childname]); |
353 $matchings = array(); |
295 $subChild[$childname] = true; |
354 $match = preg_match ($pattern, $simpleXmlElementObject, $matchings); |
296 } |
355 if ($match) { |
297 $childArray[$childname][] = $element[$childname]; |
356 return new Zend_Json_Expr($matchings[1]); |
298 } else { |
357 } else { |
299 $childArray[$childname] = $element[$childname]; |
358 return (trim(strval($simpleXmlElementObject))); |
300 } |
359 } |
301 } |
360 |
302 if (!empty($attributes) && !$ignoreXmlAttributes) { |
361 } // End of if (is_array($simpleXmlElementObject)) |
303 foreach ($attributes['@attributes'] as $k => $v) { |
362 } // End of function _processXml. |
304 $attributes['@attributes'][$k] = self::_getXmlValue($v); |
|
305 } |
|
306 $childArray['@attributes'] = $attributes['@attributes']; |
|
307 } |
|
308 if (!empty($value)) { |
|
309 $childArray['@text'] = $value; |
|
310 } |
|
311 return array($name => $childArray); |
|
312 } |
|
313 } |
|
314 |
|
315 /** |
|
316 * fromXml - Converts XML to JSON |
|
317 * |
|
318 * Converts a XML formatted string into a JSON formatted string. |
|
319 * The value returned will be a string in JSON format. |
|
320 * |
|
321 * The caller of this function needs to provide only the first parameter, |
|
322 * which is an XML formatted String. The second parameter is optional, which |
|
323 * lets the user to select if the XML attributes in the input XML string |
|
324 * should be included or ignored in xml2json conversion. |
|
325 * |
|
326 * This function converts the XML formatted string into a PHP array by |
|
327 * calling a recursive (protected static) function in this class. Then, it |
|
328 * converts that PHP array into JSON by calling the "encode" static funcion. |
|
329 * |
|
330 * Throws a Zend_Json_Exception if the input not a XML formatted string. |
|
331 * NOTE: Encoding native javascript expressions via Zend_Json_Expr is not possible. |
|
332 * |
|
333 * @static |
|
334 * @access public |
|
335 * @param string $xmlStringContents XML String to be converted |
|
336 * @param boolean $ignoreXmlAttributes Include or exclude XML attributes in |
|
337 * the xml2json conversion process. |
|
338 * @return mixed - JSON formatted string on success |
|
339 * @throws Zend_Json_Exception |
|
340 */ |
|
341 public static function fromXml($xmlStringContents, $ignoreXmlAttributes=true) |
|
342 { |
|
343 // Load the XML formatted string into a Simple XML Element object. |
|
344 $simpleXmlElementObject = simplexml_load_string($xmlStringContents); |
|
345 |
|
346 // If it is not a valid XML content, throw an exception. |
|
347 if ($simpleXmlElementObject == null) { |
|
348 require_once 'Zend/Json/Exception.php'; |
|
349 throw new Zend_Json_Exception('Function fromXml was called with an invalid XML formatted string.'); |
|
350 } // End of if ($simpleXmlElementObject == null) |
|
351 |
|
352 $resultArray = null; |
|
353 |
|
354 // Call the recursive function to convert the XML into a PHP array. |
|
355 $resultArray = self::_processXml($simpleXmlElementObject, $ignoreXmlAttributes); |
|
356 |
|
357 // Convert the PHP array to JSON using Zend_Json encode method. |
|
358 // It is just that simple. |
|
359 $jsonStringOutput = self::encode($resultArray); |
|
360 return($jsonStringOutput); |
|
361 } |
|
362 |
363 |
363 |
|
364 |
364 /** |
365 /** |
365 * Pretty-print JSON string |
366 * Pretty-print JSON string |
366 * |
367 * |
367 * Use 'indent' option to select indentation string - by default it's a tab |
368 * Use 'format' option to select output format - currently html and txt supported, txt is default |
368 * |
369 * Use 'indent' option to override the indentation string set in the format - by default for the 'txt' format it's a tab |
|
370 * |
369 * @param string $json Original JSON string |
371 * @param string $json Original JSON string |
370 * @param array $options Encoding options |
372 * @param array $options Encoding options |
371 * @return string |
373 * @return string |
372 */ |
374 */ |
373 public static function prettyPrint($json, $options = array()) |
375 public static function prettyPrint($json, $options = array()) |
374 { |
376 { |
375 $tokens = preg_split('|([\{\}\]\[,])|', $json, -1, PREG_SPLIT_DELIM_CAPTURE); |
377 $tokens = preg_split('|([\{\}\]\[,])|', $json, -1, PREG_SPLIT_DELIM_CAPTURE); |
376 $result = ""; |
378 $result = ''; |
377 $indent = 0; |
379 $indent = 0; |
378 |
380 |
|
381 $format= 'txt'; |
|
382 |
379 $ind = "\t"; |
383 $ind = "\t"; |
380 if(isset($options['indent'])) { |
384 |
|
385 if (isset($options['format'])) { |
|
386 $format = $options['format']; |
|
387 } |
|
388 |
|
389 switch ($format) { |
|
390 case 'html': |
|
391 $lineBreak = '<br />'; |
|
392 $ind = ' '; |
|
393 break; |
|
394 default: |
|
395 case 'txt': |
|
396 $lineBreak = "\n"; |
|
397 $ind = "\t"; |
|
398 break; |
|
399 } |
|
400 |
|
401 // override the defined indent setting with the supplied option |
|
402 if (isset($options['indent'])) { |
381 $ind = $options['indent']; |
403 $ind = $options['indent']; |
382 } |
404 } |
383 |
405 |
|
406 $inLiteral = false; |
384 foreach($tokens as $token) { |
407 foreach($tokens as $token) { |
385 if($token == "") continue; |
408 if($token == '') { |
386 |
409 continue; |
|
410 } |
|
411 |
387 $prefix = str_repeat($ind, $indent); |
412 $prefix = str_repeat($ind, $indent); |
388 if($token == "{" || $token == "[") { |
413 if (!$inLiteral && ($token == '{' || $token == '[')) { |
389 $indent++; |
414 $indent++; |
390 if($result != "" && $result[strlen($result)-1] == "\n") { |
415 if (($result != '') && ($result[(strlen($result)-1)] == $lineBreak)) { |
391 $result .= $prefix; |
416 $result .= $prefix; |
392 } |
417 } |
393 $result .= "$token\n"; |
418 $result .= $token . $lineBreak; |
394 } else if($token == "}" || $token == "]") { |
419 } elseif (!$inLiteral && ($token == '}' || $token == ']')) { |
395 $indent--; |
420 $indent--; |
396 $prefix = str_repeat($ind, $indent); |
421 $prefix = str_repeat($ind, $indent); |
397 $result .= "\n$prefix$token"; |
422 $result .= $lineBreak . $prefix . $token; |
398 } else if($token == ",") { |
423 } elseif (!$inLiteral && $token == ',') { |
399 $result .= "$token\n"; |
424 $result .= $token . $lineBreak; |
400 } else { |
425 } else { |
401 $result .= $prefix.$token; |
426 $result .= ( $inLiteral ? '' : $prefix ) . $token; |
|
427 |
|
428 // Count # of unescaped double-quotes in token, subtract # of |
|
429 // escaped double-quotes and if the result is odd then we are |
|
430 // inside a string literal |
|
431 if ((substr_count($token, "\"")-substr_count($token, "\\\"")) % 2 != 0) { |
|
432 $inLiteral = !$inLiteral; |
|
433 } |
402 } |
434 } |
403 } |
435 } |
404 return $result; |
436 return $result; |
405 } |
437 } |
406 } |
438 } |