jsonpath-0.8.1.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <?php
  2. /* JSONPath 0.8.1 - XPath for JSON
  3. *
  4. * Copyright (c) 2007 Stefan Goessner (goessner.net)
  5. * Licensed under the MIT (MIT-LICENSE.txt) licence.
  6. */
  7. // API function
  8. function jsonPath($obj, $expr, $args=null) {
  9. $jsonpath = new JsonPath();
  10. $jsonpath->resultType = ($args ? $args['resultType'] : "VALUE");
  11. $x = $jsonpath->normalize($expr);
  12. $jsonpath->obj = $obj;
  13. if ($expr && $obj && ($jsonpath->resultType == "VALUE" || $jsonpath->resultType == "PATH")) {
  14. $jsonpath->trace(preg_replace("/^\\$;/", "", $x), $obj, "$");
  15. if (count($jsonpath->result))
  16. return $jsonpath->result;
  17. else
  18. return false;
  19. }
  20. }
  21. // JsonPath class (internal use only)
  22. class JsonPath {
  23. var $obj = null;
  24. var $resultType = "Value";
  25. var $result = array();
  26. var $subx = array();
  27. // normalize path expression
  28. function normalize($x) {
  29. $x = preg_replace_callback("/[\['](\??\(.*?\))[\]']/", array(&$this, "_callback_01"), $x);
  30. $x = preg_replace(array("/'?\.'?|\['?/", "/;;;|;;/", "/;$|'?\]|'$/"),
  31. array(";", ";..;", ""),
  32. $x);
  33. $x = preg_replace_callback("/#([0-9]+)/", array(&$this, "_callback_02"), $x);
  34. $this->result = array(); // result array was temporarily used as a buffer ..
  35. return $x;
  36. }
  37. function _callback_01($m) { return "[#".(array_push($this->result, $m[1])-1)."]"; }
  38. function _callback_02($m) { return $this->result[$m[1]]; }
  39. function asPath($path) {
  40. $x = explode(";", $path);
  41. $p = "$";
  42. for ($i=1,$n=count($x); $i<$n; $i++)
  43. $p .= preg_match("/^[0-9*]+$/", $x[$i]) ? ("[".$x[$i]."]") : ("['".$x[$i]."']");
  44. return $p;
  45. }
  46. function store($p, $v) {
  47. if ($p) array_push($this->result, ($this->resultType == "PATH" ? $this->asPath($p) : $v));
  48. return !!$p;
  49. }
  50. function trace($expr, $val, $path) {
  51. if ($expr) {
  52. $x = explode(";", $expr);
  53. $loc = array_shift($x);
  54. $x = implode(";", $x);
  55. if (is_array($val) && array_key_exists($loc, $val))
  56. $this->trace($x, $val[$loc], $path.";".$loc);
  57. else if ($loc == "*")
  58. $this->walk($loc, $x, $val, $path, array(&$this, "_callback_03"));
  59. else if ($loc === "..") {
  60. $this->trace($x, $val, $path);
  61. $this->walk($loc, $x, $val, $path, array(&$this, "_callback_04"));
  62. }
  63. else if (preg_match("/,/", $loc)) // [name1,name2,...]
  64. for ($s=preg_split("/'?,'?/", $loc),$i=0,$n=count($s); $i<$n; $i++)
  65. $this->trace($s[$i].";".$x, $val, $path);
  66. else if (preg_match("/^\(.*?\)$/", $loc)) // [(expr)]
  67. $this->trace($this->evalx($loc, $val, substr($path,strrpos($path,";")+1)).";".$x, $val, $path);
  68. else if (preg_match("/^\?\(.*?\)$/", $loc)) // [?(expr)]
  69. $this->walk($loc, $x, $val, $path, array(&$this, "_callback_05"));
  70. else if (preg_match("/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/", $loc)) // [start:end:step] phyton slice syntax
  71. $this->slice($loc, $x, $val, $path);
  72. }
  73. else
  74. $this->store($path, $val);
  75. }
  76. function _callback_03($m,$l,$x,$v,$p) { $this->trace($m.";".$x,$v,$p); }
  77. function _callback_04($m,$l,$x,$v,$p) { if (is_array($v[$m])) $this->trace("..;".$x,$v[$m],$p.";".$m); }
  78. function _callback_05($m,$l,$x,$v,$p) { if ($this->evalx(preg_replace("/^\?\((.*?)\)$/","$1",$l),$v[$m])) $this->trace($m.";".$x,$v,$p); }
  79. function walk($loc, $expr, $val, $path, $f) {
  80. foreach($val as $m => $v)
  81. call_user_func($f, $m, $loc, $expr, $val, $path);
  82. }
  83. function slice($loc, $expr, $v, $path) {
  84. $s = explode(":", preg_replace("/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/", "$1:$2:$3", $loc));
  85. $len=count($v);
  86. $start=(int)$s[0]?$s[0]:0;
  87. $end=(int)$s[1]?$s[1]:$len;
  88. $step=(int)$s[2]?$s[2]:1;
  89. $start = ($start < 0) ? max(0,$start+$len) : min($len,$start);
  90. $end = ($end < 0) ? max(0,$end+$len) : min($len,$end);
  91. for ($i=$start; $i<$end; $i+=$step)
  92. $this->trace($i.";".$expr, $v, $path);
  93. }
  94. function evalx($x, $v, $vname) {
  95. $name = "";
  96. $expr = preg_replace(array("/\\$/","/@/"), array("\$this->obj","\$v"), $x);
  97. $res = eval("\$name = $expr;");
  98. if ($res === FALSE)
  99. print("(jsonPath) SyntaxError: " . $expr);
  100. else
  101. return $name;
  102. }
  103. }
  104. ?>