3 * ARC2 RDF/XML Serializer
5 * @author Benjamin Nowack
6 * @license <http://arc.semsol.org/license>
7 * @homepage <http://arc.semsol.org/>
13 ARC2::inc('RDFSerializer');
15 class ARC2_RDFXMLSerializer extends ARC2_RDFSerializer {
17 function __construct($a = '', &$caller) {
18 parent::__construct($a, $caller);
21 function ARC2_RDFXMLSerializer($a = '', &$caller) {
22 $this->__construct($a, $caller);
27 $this->content_header = 'application/rdf+xml';
28 $this->pp_containers = $this->v('serializer_prettyprint_containers', 0, $this->a);
29 $this->default_ns = $this->v('serializer_default_ns', '', $this->a);
30 $this->type_nodes = $this->v('serializer_type_nodes', 0, $this->a);
35 function getTerm($v, $type) {
36 if (!is_array($v)) {/* uri or bnode */
37 if (preg_match('/^\_\:(.*)$/', $v, $m)) {
38 return ' rdf:nodeID="' . $m[1] . '"';
41 return ' rdf:about="' . htmlspecialchars($v) . '"';
44 if ($pn = $this->getPName($v)) {
50 $v = $this->expandPName($v);
51 if (!preg_match('/^[a-z0-9]{2,}\:[^\s]+$/is', $v)) return $this->getTerm(array('value' => $v, 'type' => 'literal'), $type);
52 return ' rdf:resource="' . htmlspecialchars($v) . '"';
54 if ($type == 'datatype') {
55 $v = $this->expandPName($v);
56 return ' rdf:datatype="' . htmlspecialchars($v) . '"';
58 if ($type == 'lang') {
59 return ' xml:lang="' . htmlspecialchars($v) . '"';
62 if ($v['type'] != 'literal') {
63 return $this->getTerm($v['value'], 'o');
66 $dt = isset($v['datatype']) ? $v['datatype'] : '';
67 $lang = isset($v['lang']) ? $v['lang'] : '';
68 if ($dt == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') {
69 return ' rdf:parseType="Literal">' . $v['value'];
72 return $this->getTerm($dt, 'datatype') . '>' . htmlspecialchars($v['value']);
75 return $this->getTerm($lang, 'lang') . '>' . htmlspecialchars($v['value']);
77 return '>' . htmlspecialchars($v['value']);
80 function getPName($v, $connector = ':') {
81 if ($this->default_ns && (strpos($v, $this->default_ns) === 0)) {
82 $pname = substr($v, strlen($this->default_ns));
83 if (!preg_match('/\//', $pname)) return $pname;
85 return parent::getPName($v, $connector);
91 $r .= '<?xml version="1.0" encoding="UTF-8"?>';
92 $r .= $nl . '<rdf:RDF';
94 foreach ($this->used_ns as $v) {
95 $r .= $first_ns ? ' ' : $nl . ' ';
96 $r .= 'xmlns:' . $this->nsp[$v] . '="' .$v. '"';
99 if ($this->default_ns) {
100 $r .= $first_ns ? ' ' : $nl . ' ';
101 $r .= 'xmlns="' . $this->default_ns . '"';
107 function getFooter() {
110 $r .= $nl . $nl . '</rdf:RDF>';
114 function getSerializedIndex($index, $raw = 0) {
117 foreach ($index as $raw_s => $ps) {
118 $r .= $r ? $nl . $nl : '';
119 $s = $this->getTerm($raw_s, 's');
120 $tag = 'rdf:Description';
121 list($tag, $ps) = $this->getNodeTag($ps);
123 /* pretty containers */
124 if ($this->pp_containers && ($ctag = $this->getContainerTag($ps))) {
125 $tag = 'rdf:' . $ctag;
126 list($ps, $sub_ps) = $this->splitContainerEntries($ps);
128 $r .= ' <' . $tag . '' .$s . '>';
130 foreach ($ps as $p => $os) {
132 if ($p = $this->getTerm($p, 'p')) {
133 $r .= $nl . str_pad('', 4);
135 if (!is_array($os)) {/* single literal o */
136 $os = array(array('value' => $os, 'type' => 'literal'));
138 foreach ($os as $o) {
139 $o = $this->getTerm($o, 'o');
140 $r .= $first_o ? '' : $nl . ' ';
143 $r .= preg_match('/\>/', $o) ? '</' . $p . '>' : '/>';
149 $r .= $r ? $nl . ' </' . $tag . '>' : '';
150 if ($sub_ps) $r .= $nl . $nl . $this->getSerializedIndex(array($raw_s => $sub_ps), 1);
155 return $this->getHead() . $nl . $nl . $r . $this->getFooter();
158 function getNodeTag($ps) {
159 if (!$this->type_nodes) return array('rdf:Description', $ps);
160 $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
161 $types = $this->v($rdf . 'type', array(), $ps);
162 if (!$types) return array('rdf:Description', $ps);
163 $type = array_shift($types);
164 $ps[$rdf . 'type'] = $types;
165 if (!is_array($type)) $type = array('value' => $type);
166 return array($this->getPName($type['value']), $ps);
171 function getContainerTag($ps) {
172 $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
173 if (!isset($ps[$rdf . 'type'])) return '';
174 $types = $ps[$rdf . 'type'];
175 foreach ($types as $type) {
176 if (!in_array($type['value'], array($rdf . 'Bag', $rdf . 'Seq', $rdf . 'Alt'))) return '';
177 return str_replace($rdf, '', $type['value']);
181 function splitContainerEntries($ps) {
182 $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
185 foreach ($ps as $p => $os) {
186 $p_short = str_replace($rdf, '', $p);
187 if ($p_short === 'type') continue;
188 if (preg_match('/^\_([0-9]+)$/', $p_short, $m)) {
189 $items = array_merge($items, $os);
195 if ($items) return array(array($rdf . 'li' => $items), $rest);
196 return array($rest, 0);