JsonRef.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. /* Copyright (c) 2014-2019 Geert Bergman (geert@scrivo.nl), highlight.php
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * 1. Redistributions of source code must retain the above copyright notice,
  8. * this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright notice,
  10. * this list of conditions and the following disclaimer in the documentation
  11. * and/or other materials provided with the distribution.
  12. * 3. Neither the name of "highlight.js", "highlight.php", nor the names of its
  13. * contributors may be used to endorse or promote products derived from this
  14. * software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  20. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  23. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26. * POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. /**
  29. * Implementation of the \Highlight\JsonRef class.
  30. */
  31. namespace Highlight;
  32. /**
  33. * Class to decode JSON data that contains path-based references.
  34. *
  35. * The language data file for highlight.js are written as JavaScript classes
  36. * and therefore may contain variables. This allows for inner references in
  37. * the language data. This kind of data can be converterd to JSON using the
  38. * path based references. This class can be used to decode such JSON
  39. * structures. It follows the conventions for path based referencing as
  40. * used in dojox.json.ref form the Dojo toolkit (Javascript). A typical
  41. * example of such a structure is as follows:
  42. *
  43. * ```json
  44. * {
  45. * "name":"Kris Zyp",
  46. * "children":[{"name":"Jennika Zyp"},{"name":"Korban Zyp"}],
  47. * "spouse":{
  48. * "name":"Nicole Zyp",
  49. * "spouse":{"$ref":"#"},
  50. * "children":{"$ref":"#children"}
  51. * },
  52. * "oldestChild":{"$ref":"#children.0"}
  53. * }
  54. * ```
  55. *
  56. * Usage example:
  57. *
  58. * ```php
  59. * $jr = new JsonRef();
  60. * $data = $jr->decode(file_get_contents("data.json"));
  61. * echo $data->spouse->spouse->name; // echos 'Kris Zyp'
  62. * echo $data->oldestChild->name; // echos 'Jennika Zyp'
  63. * ```
  64. *
  65. * @todo In Highlight.php 10.x, mark this class final with a keyword.
  66. *
  67. * @since 9.16.0.0 Class has been marked as final
  68. *
  69. * @final
  70. *
  71. * @internal
  72. */
  73. class JsonRef
  74. {
  75. /**
  76. * Array to hold all data paths in the given JSON data.
  77. *
  78. * @var array
  79. */
  80. private $paths = null;
  81. /**
  82. * Recurse through the data tree and fill an array of paths that reference
  83. * the nodes in the decoded JSON data structure.
  84. *
  85. * @param mixed $s Decoded JSON data (decoded with json_decode)
  86. * @param string $r The current path key (for example: '#children.0').
  87. */
  88. private function getPaths(&$s, $r = "#")
  89. {
  90. $this->paths[$r] = &$s;
  91. if (is_array($s) || is_object($s)) {
  92. foreach ($s as $k => &$v) {
  93. if ($k !== "\$ref") {
  94. $this->getPaths($v, $r == "#" ? "#{$k}" : "{$r}.{$k}");
  95. }
  96. }
  97. }
  98. }
  99. /**
  100. * Recurse through the data tree and resolve all path references.
  101. *
  102. * @param mixed $s Decoded JSON data (decoded with json_decode)
  103. * @param int $limit
  104. * @param int $depth
  105. */
  106. private function resolvePathReferences(&$s, $limit = 20, $depth = 1)
  107. {
  108. if ($depth >= $limit) {
  109. return;
  110. }
  111. ++$depth;
  112. if (is_array($s) || is_object($s)) {
  113. foreach ($s as $k => &$v) {
  114. if ($k === "\$ref") {
  115. $s = $this->paths[$v];
  116. } else {
  117. $this->resolvePathReferences($v, $limit, $depth);
  118. }
  119. }
  120. }
  121. }
  122. /**
  123. * Decode JSON data that may contain path based references.
  124. *
  125. * @deprecated 9.16.0.0 This method will be removed in Highlight.php. Make use of `decodeRef` instead.
  126. *
  127. * @param string|object $json JSON data string or JSON data object
  128. *
  129. * @return mixed The decoded JSON data
  130. */
  131. public function decode($json)
  132. {
  133. // Clear the path array.
  134. $this->paths = array();
  135. // Decode the given JSON data if necessary.
  136. $x = is_string($json) ? json_decode($json) : $json;
  137. // Get all data paths.
  138. $this->getPaths($x);
  139. // Resolve all path references.
  140. $this->resolvePathReferences($x);
  141. // Return the data.
  142. return $x;
  143. }
  144. /**
  145. * Decode JSON data that may contain path based references.
  146. *
  147. * @param object $json JSON data string or JSON data object
  148. */
  149. public function decodeRef(&$json)
  150. {
  151. // Clear the path array.
  152. $this->paths = array();
  153. // Get all data paths.
  154. $this->getPaths($json);
  155. // Resolve all path references.
  156. $this->resolvePathReferences($json);
  157. }
  158. }