Subversion Repositories Web Services

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
119599 fvs 1
<?php
2
/**
3
 *
4
 * This file is part of Open Library System.
5
 * Copyright © 2009, Dansk Bibliotekscenter a/s,
6
 * Tempovej 7-11, DK-2750 Ballerup, Denmark. CVR: 15149043
7
 *
8
 * Open Library System is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Open Library System is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with Open Library System.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
 
22
 
23
/** \brief Convert ols-object to json, xml, php
24
 *
25
 * An OLS object contains the data in _value
26
 * It may have a namespace in _namespace
27
 * and it may have attributes in _attributes
28
 * and it may have a cdata-flag set in _cdata (only used in xml-output)
29
 *
30
 * Example:
31
 *   $obj->tagname->_value = "A&A";
32
 *   will convert to a xml doc like: <tagname>A&amp;A</tagname>
33
 *                   json like: {"tagname":{"$":"A&A"},"@namespaces":null}
34
 *
35
 * Example:
36
 *   $obj->tagname->_value = "A&A";
37
 *   $obj->tagname->_namespace = "http://some.namespace.com/";
38
 *   will convert to a xml doc like: <ns1:tagname xmlns:ns1="http://some.namespace.com/">A&amp;A</ns1:tagname>
39
 *                   json like: {"tagname":{"$":"A&A","@":"ns1"},"@namespaces":{"ns1":"http:\/\/some.namespace.com\/"}}
40
 *
41
 * Example:
42
 *   $obj->tagname->_value = "A&A";
43
 *   $obj->tagname->_attributes->attr->_value = "ATTR";
44
 *   will convert to a xml doc like: <tagname attr="ATTR">A&amp;A</tagname>
45
 *                   json like: {"tagname":{"$":"A&A","@attr":{"$":"ATTR"}},"@namespaces":null}
46
 *
47
 * Example:
48
 *   $obj->tagname->_value = "A&A";
49
 *   $obj->tagname->_attributes->attr->_value = "ATTR";
50
 *   $obj->tagname->_attributes->attr->_namespace = "http://some.namespace.com/";
51
 *   will convert to a xml doc like: <tagname ns1:attr="ATTR" xmlns:ns1="http://some.namespace.com/">A&amp;A</tagname>
52
 *                   json like: {"tagname":{"$":"A&A","@attr":{"$":"ATTR","@":"ns1"}},"@namespaces":{"ns1":"http:\/\/some.namespace.com\/"}}
53
 *
54
 * Example:
55
 *   $obj->tagname->_value = "A&A";
56
 *   $obj->tagname->_cdata = TRUE;
57
 *   will convert to a xml doc like: <tagname><![CDATA[A&A]]></tagname>
58
 *                   json like: {"tagname":{"$":"A&A"},"@namespaces":null}
59
 *
60
 * @author Finn Stausgaard - DBC
61
 */
62
 
63
define('NO_PREFIX', '_NO_PREFIX_');
64
 
65
/**
66
 * Class objconvert
67
 */
68
class objconvert {
69
 
70
  private $tag_sequence = array();
71
  private $namespaces = array();
72
  private $used_namespaces = array();
73
  private $default_namespace;
74
  private $timer;
75
 
76
  /** \brief -
77
   * @param $xmlns string|array -
78
   * @param $tag_seq string -
79
   * @param $timer string -
80
   */
81
  public function __construct($xmlns = '', $tag_seq = '', $timer = NULL) {
82
    if ($xmlns) {
83
      foreach ($xmlns as $prefix => $ns) {
84
        if ($prefix == 'NONE' || $prefix == '0')
85
          $prefix = '';
86
        $this->add_namespace($ns, $prefix);
87
      }
88
    }
89
    $this->tag_sequence = $tag_seq;
90
    $this->timer = $timer;
91
  }
92
 
93
  /** \brief -
94
   * @param $ns string -
95
   */
96
  public function set_default_namespace($ns) {
97
    $this->default_namespace = $ns;
98
    if ($this->namespaces[$ns] == '') {
99
      unset($this->namespaces[$ns]);         // remove deprecated setup
100
    }
101
  }
102
 
103
  /** \brief Convert ols-object to json
104
   * @param $obj object -
105
   * @return string
106
   */
107
  public function obj2json($obj) {
108
    if ($this->timer) $this->timer->start('obj2json');
109
    foreach ($this->namespaces as $ns => $prefix) {
110
      if ($prefix)
111
        self::set_object_value($o_ns, $prefix, $ns);
112
      else
113
        self::set_object_value($o_ns, '$', $ns);
114
    }
115
    $json_obj = $this->obj2badgerfish_obj($obj);
116
    self::set_object_value($json_obj, '@namespaces', $o_ns);
117
    if ($this->timer) $this->timer->stop('obj2json');
118
    return json_encode($json_obj);
119
  }
120
 
121
  /** \brief compress ols object to badgerfish-inspired object
122
   * @param $obj object -
123
   * @return object
124
   */
125
  private function obj2badgerfish_obj($obj) {
126
    if ($obj) {
127
      foreach ($obj as $key => $o) {
128
        if (is_array($o)) {
129
          foreach ($o as $o_i) {
130
            $ret->{$key}[] = $this->build_json_obj($o_i);
131
          }
132
        }
133
        else
134
          self::set_object_value($ret, $key, $this->build_json_obj($o));
135
      }
136
    }
137
    return $ret;
138
  }
139
 
140
  /** \brief convert one object
141
   * @param $obj object -
142
   * @return object
143
   */
144
  private function build_json_obj($obj) {
145
    if (is_scalar($obj->_value))
146
      self::set_object_value($ret, '$', html_entity_decode($obj->_value));
147
    else
148
      $ret = $this->obj2badgerfish_obj($obj->_value);
149
    if (isset($obj->_attributes)) {
150
      foreach ($obj->_attributes as $aname => $aval) {
151
        self::set_object_value($ret, '@' . $aname, $this->build_json_obj($aval));
152
      }
153
    }
154
    if (isset($obj->_namespace))
155
      self::set_object_value($ret, '@', $this->get_namespace_prefix($obj->_namespace));
156
    return $ret;
157
  }
158
 
159
  /** \brief experimental php serialized
160
   * @param $obj object -
161
   * @return string
162
   */
163
  public function obj2phps($obj) {
164
    return serialize($obj);
165
  }
166
 
167
  /** \brief Convert ols-object to xml with namespaces
168
   * @param $obj object -
169
   * @return string
170
   */
171
  public function obj2xmlNs($obj) {
172
    $this->used_namespaces = array();
173
    $xml = $this->obj2xml($obj);
174
    $used_ns = $this->get_used_namespaces_as_header();
175
    if ($used_ns && $i = strpos($xml, '>'))
176
      $xml = substr($xml, 0, $i) . $used_ns . substr($xml, $i);
177
    return $this->xml_header() . $xml;
178
  }
179
 
180
  /** \brief Convert ols-object to soap
181
   * @param $obj object -
182
   * @param $soap_ns string
183
   * @return string
184
   */
185
  public function obj2soap($obj, $soap_ns = 'http://schemas.xmlsoap.org/soap/envelope/') {
186
    $this->used_namespaces = array();
187
    $xml = $this->obj2xml($obj);
188
    return $this->xml_header() .
189
    '<SOAP-ENV:Envelope xmlns:SOAP-ENV="' . $soap_ns . '"' .
190
    $this->get_used_namespaces_as_header() . '><SOAP-ENV:Body>' .
191
    $xml . '</SOAP-ENV:Body></SOAP-ENV:Envelope>';
192
  }
193
 
194
  /** \brief
195
   * @return string
196
   */
197
  private function get_used_namespaces_as_header() {
198
    $used_ns = '';
199
    foreach ($this->namespaces as $ns => $prefix) {
200
      if (isset($this->used_namespaces[$ns]) || empty($prefix))
201
        $used_ns .= ' xmlns' . ($prefix ? ':' . $prefix : '') . '="' . $ns . '"';
202
    }
203
    if ($this->default_namespace && $this->used_namespaces[NO_PREFIX]) {
204
      $used_ns .= ' xmlns="' . $this->default_namespace . '"';
205
    }
206
    return $used_ns;
207
  }
208
 
209
  /** \brief UTF-8 header
210
   * @return string
211
   */
212
  private function xml_header() {
213
    return '<?xml version="1.0" encoding="UTF-8"?>';
214
  }
215
 
216
  /** \brief Convert ols-object to xml
217
   *
218
   * used namespaces are returned in this->namespaces
219
   * namespaces can be preset with add_namespace()
220
   *
221
   * @param $obj object -
222
   * @return string
223
   */
224
  public function obj2xml($obj) {
225
    if ($this->timer) $this->timer->start('obj2xml');
226
    $this->check_tag_sequence();
227
    $ret = '';
228
    if ($obj) {
229
      foreach ($obj as $tag => $o) {
230
        if (is_array($o)) {
231
          foreach ($o as $o_i) {
232
            $ret .= $this->build_xml($tag, $o_i);
233
          }
234
        }
235
        else
236
          $ret .= $this->build_xml($tag, $o);
237
      }
238
    }
239
    if ($this->timer) $this->timer->stop('obj2xml');
240
    return $ret;
241
  }
242
 
243
  /** \brief handles one node
244
   * @param $tag string -
245
   * @param $obj object -
246
   * @return string
247
   */
248
  private function build_xml($tag, $obj) {
249
    $attr = $prefix = $ret = '';
250
    if (isset($obj->_attributes)) {
251
      foreach ($obj->_attributes as $a_name => $a_val) {
252
        if (isset($a_val->_namespace))
253
          $a_prefix = $this->set_prefix_separator($this->get_namespace_prefix($a_val->_namespace));
254
        else {
255
          $this->used_namespaces[NO_PREFIX] = TRUE;
256
          $a_prefix = '';
257
        }
258
        $attr .= ' ' . $a_prefix . $a_name . '="' . htmlspecialchars($a_val->_value) . '"';
259
// prefix in value hack
260
        $this->set_used_prefix($a_val->_value);
261
      }
262
    }
263
    if (isset($obj->_namespace))
264
      $prefix = $this->set_prefix_separator($this->get_namespace_prefix($obj->_namespace));
265
    else
266
      $this->used_namespaces[NO_PREFIX] = TRUE;
267
    if (is_scalar($obj->_value))
268
      if (isset($obj->_cdata))
269
        return $this->tag_me($prefix . $tag, $attr, '<![CDATA[' . $obj->_value . ']]>');
270
      else
271
        return $this->tag_me($prefix . $tag, $attr, htmlspecialchars($obj->_value));
272
    else
273
      return $this->tag_me($prefix . $tag, $attr, $this->obj2xml($obj->_value));
274
  }
275
 
276
  /** \brief Updates used_namespaces from prefix in $val
277
   * @param $val string -
278
   */
279
  private function set_used_prefix($val) {
280
    if ($p = strpos($val, ':')) {
281
      foreach ($this->namespaces as $ns => $prefix) {
282
        if ($prefix == substr($val, 0, $p)) {
283
          $this->used_namespaces[$ns] = TRUE;
284
          break;
285
        }
286
      }
287
    }
288
    else {
289
      $this->used_namespaces[NO_PREFIX] = TRUE;
290
    }
291
  }
292
 
293
  /** \brief returns prefixes and store namespaces
294
   * @param $ns string -
295
   * @return string
296
   */
297
  private function get_namespace_prefix($ns) {
298
    if (empty($this->namespaces[$ns])) {
299
      $i = 1;
300
      while (in_array('ns' . $i, $this->namespaces)) $i++;
301
      $this->namespaces[$ns] = 'ns' . $i;
302
    }
303
    $this->used_namespaces[$ns] = TRUE;
304
    return $this->namespaces[$ns];
305
  }
306
 
307
  /** \brief Separator between prefix and tag-name in xml
308
   * @param $prefix string -
309
   * @return string
310
   */
311
  private function set_prefix_separator($prefix) {
312
    if ($prefix) return $prefix . ':';
313
    else return $prefix;
314
  }
315
 
316
  /** \brief get or use tag_sequence
317
   */
318
  private function check_tag_sequence() {
319
    if ($this->tag_sequence && is_scalar($this->tag_sequence)) {
320
      require_once('OLS_class_lib/schema_class.php');
321
      $schema_parser = new schema_something();
322
      $this->tag_sequence = $schema_parser->parse($this->tag_sequence);
323
    }
324
  }
325
 
326
  /** \brief Adds known namespaces
327
   * @param $namespace string -
328
   * @param $prefix string -
329
   */
330
  public function add_namespace($namespace, $prefix) {
331
    $this->namespaces[$namespace] = $prefix;
332
    asort($this->namespaces);
333
  }
334
 
335
  /** \brief Returns used namespaces
336
   * @return array
337
   */
338
  public function get_namespaces() {
339
    return $this->namespaces;
340
  }
341
 
342
  /** \brief Set namespace on all object nodes
343
   * @param $obj mixed -
344
   * @param $ns string -
345
   * @return mixed
346
   */
347
  public function set_obj_namespace($obj, $ns) {
348
    if (empty($obj) || is_scalar($obj))
349
      return $obj;
350
    if (is_array($obj)) {
351
      $ret = array();
352
      foreach ($obj as $key => $val) {
353
        $ret[$key] = $this->set_obj_namespace($val, $ns);
354
      }
355
    }
356
    else {
357
      $ret = new stdClass();
358
      foreach ($obj as $key => $val) {
359
        $ret->$key = $this->set_obj_namespace($val, $ns);
360
        if ($key === '_value')
361
          $ret->_namespace = $ns;
362
      }
363
    }
364
    return $ret;
365
  }
366
 
367
  /** \brief Set namespace on all object nodes but attributes
368
   * @param $obj mixed -
369
   * @param $ns string -
370
   * @param $in_attribute boolean -
371
   * @return mixed
372
   */
373
  public function set_obj_namespace_on_tags($obj, $ns, $in_attribute = FALSE) {
374
    if (empty($obj) || is_scalar($obj))
375
      return $obj;
376
    if (is_array($obj)) {
377
      $ret = array();
378
      foreach ($obj as $key => $val) {
379
        $ret[$key] = $this->set_obj_namespace_on_tags($val, $ns, $in_attribute);
380
      }
381
    }
382
    else {
383
      $ret = new stdClass();
384
      foreach ($obj as $key => $val) {
385
        $ret->$key = $this->set_obj_namespace_on_tags($val, $ns, $in_attribute || $key == '_attributes');
386
        if ($key === '_value' && !$in_attribute)
387
          $ret->_namespace = $ns;
388
      }
389
    }
390
    return $ret;
391
  }
392
 
393
  /** \brief produce balanced xml
394
   * @param $tag string -
395
   * @param $attr string -
396
   * @param $val string -
397
   * @return string
398
   */
399
  public function tag_me($tag, $attr, $val) {
400
    if ($tag == '#text') {
401
      return $val;
402
    }
403
    else {
404
      $space = ($attr && $attr[0] <> ' ') ? ' ' : '';
405
      return '<' . $tag . $space . $attr . '>' . $val . '</' . $tag . '>';
406
    }
407
  }
408
 
409
  /** \brief makes sure the object is defined and set value
410
   * @param obj (object) - the object to set
411
   * @param name (string)
412
   * @param $val string -
413
   **/
414
  private function set_object_value(&$obj, $name, $val) {
415
    self::ensure_object_set($obj);
416
    self::ensure_object_set($obj->$name);
417
    $obj->$name = $val;
418
  }
419
 
420
  /** \brief makes sure the object is defined
421
   * @param obj (object) - the object to set
422
   **/
423
   private function ensure_object_set(&$obj) {
424
    if (!isset($obj)) $obj = new stdClass();
425
  }
426
 
427
}
428