Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
92.98% |
106 / 114 |
|
72.41% |
21 / 29 |
CRAP | |
0.00% |
0 / 1 |
RdfWriterBase | |
92.98% |
106 / 114 |
|
72.41% |
21 / 29 |
59.16 | |
0.00% |
0 / 1 |
__construct | |
85.71% |
6 / 7 |
|
0.00% |
0 / 1 |
3.03 | |||
newSubWriter | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
registerShorthand | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
prefix | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
isShorthand | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isPrefix | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getPrefixes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isValidLanguageCode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
sub | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getRole | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
write | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
expandShorthand | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
expandQName | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
4.13 | |||
blank | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
start | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
finish | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
drain | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
flattenBuffer | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
4.13 | |||
drainSubs | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
about | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
4 | |||
a | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
say | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
4 | |||
is | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
text | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
value | |
100.00% |
21 / 21 |
|
100.00% |
1 / 1 |
7 | |||
state | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
4.03 | |||
writeSubject | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
writePredicate | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
writeResource | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
writeText | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
writeValue | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
expandSubject | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
expandPredicate | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
expandResource | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
expandType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace Wikimedia\Purtle; |
4 | |
5 | use Closure; |
6 | use InvalidArgumentException; |
7 | use LogicException; |
8 | |
9 | /** |
10 | * Base class for RdfWriter implementations. |
11 | * |
12 | * Subclasses have to implement at least the writeXXX() methods to generate the desired output |
13 | * for the respective RDF constructs. Subclasses may override the startXXX() and finishXXX() |
14 | * methods to generate structural output, and override expandXXX() to transform identifiers. |
15 | * |
16 | * @license GPL-2.0-or-later |
17 | * @author Daniel Kinzler |
18 | */ |
19 | abstract class RdfWriterBase implements RdfWriter { |
20 | |
21 | /** |
22 | * @var array An array of strings, RdfWriters, or closures. |
23 | */ |
24 | private $buffer = []; |
25 | |
26 | /** |
27 | * @var RdfWriter[] sub-writers. |
28 | */ |
29 | private $subs = []; |
30 | |
31 | protected const STATE_START = 0; |
32 | protected const STATE_DOCUMENT = 5; |
33 | protected const STATE_SUBJECT = 10; |
34 | protected const STATE_PREDICATE = 11; |
35 | protected const STATE_OBJECT = 12; |
36 | protected const STATE_FINISH = 666; |
37 | |
38 | /** |
39 | * @var int the current state |
40 | */ |
41 | private $state = self::STATE_START; |
42 | |
43 | /** |
44 | * Shorthands that can be used in place of IRIs, e.g. ("a" to mean rdf:type). |
45 | * |
46 | * @var string[][] a map of shorthand names to [ $base, $local ] pairs. |
47 | * @todo Handle "a" as a special case directly. Use for custom "variables" like %currentValue |
48 | * instead. |
49 | */ |
50 | private $shorthands = []; |
51 | |
52 | /** |
53 | * @var string[] a map of prefixes to base IRIs |
54 | */ |
55 | protected $prefixes = []; |
56 | |
57 | /** |
58 | * @var array pair to store the current subject. |
59 | * Holds the $base and $local parameters passed to about(). |
60 | */ |
61 | protected $currentSubject = [ null, null ]; |
62 | |
63 | /** |
64 | * @var array pair to store the current predicate. |
65 | * Holds the $base and $local parameters passed to say(). |
66 | */ |
67 | protected $currentPredicate = [ null, null ]; |
68 | |
69 | /** |
70 | * @var BNodeLabeler |
71 | */ |
72 | private $labeler; |
73 | |
74 | /** |
75 | * Role ID for writers that will generate a full RDF document. |
76 | */ |
77 | public const DOCUMENT_ROLE = 'document'; |
78 | public const SUBDOCUMENT_ROLE = 'sub'; |
79 | |
80 | /** |
81 | * @var string The writer's role, see the XXX_ROLE constants. |
82 | */ |
83 | protected $role; |
84 | |
85 | /** |
86 | * Are prefixed locked against modification? |
87 | * @var bool |
88 | */ |
89 | private $prefixesLocked = false; |
90 | |
91 | /** |
92 | * @param string $role The writer's role, use the XXX_ROLE constants. |
93 | * @param BNodeLabeler|null $labeler |
94 | * |
95 | * @throws InvalidArgumentException |
96 | */ |
97 | public function __construct( $role, ?BNodeLabeler $labeler = null ) { |
98 | if ( !is_string( $role ) ) { |
99 | throw new InvalidArgumentException( '$role must be a string' ); |
100 | } |
101 | |
102 | $this->role = $role; |
103 | $this->labeler = $labeler ?: new BNodeLabeler(); |
104 | |
105 | $this->registerShorthand( 'a', 'rdf', 'type' ); |
106 | |
107 | $this->prefix( 'rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' ); |
108 | $this->prefix( 'xsd', 'http://www.w3.org/2001/XMLSchema#' ); |
109 | } |
110 | |
111 | /** |
112 | * @param string $role |
113 | * @param BNodeLabeler $labeler |
114 | * |
115 | * @return RdfWriterBase |
116 | */ |
117 | abstract protected function newSubWriter( $role, BNodeLabeler $labeler ); |
118 | |
119 | /** |
120 | * Registers a shorthand that can be used instead of a qname, |
121 | * like 'a' can be used instead of 'rdf:type'. |
122 | * |
123 | * @param string $shorthand |
124 | * @param string $prefix |
125 | * @param string $local |
126 | */ |
127 | protected function registerShorthand( $shorthand, $prefix, $local ) { |
128 | $this->shorthands[$shorthand] = [ $prefix, $local ]; |
129 | } |
130 | |
131 | /** |
132 | * Registers a prefix |
133 | * |
134 | * @param string $prefix |
135 | * @param string $iri The base IRI |
136 | * |
137 | * @throws LogicException |
138 | */ |
139 | public function prefix( $prefix, $iri ) { |
140 | if ( $this->prefixesLocked ) { |
141 | throw new LogicException( 'Prefixes can not be added after start()' ); |
142 | } |
143 | |
144 | $this->prefixes[$prefix] = $iri; |
145 | } |
146 | |
147 | /** |
148 | * Determines whether $shorthand can be used as a shorthand. |
149 | * |
150 | * @param string $shorthand |
151 | * |
152 | * @return bool |
153 | */ |
154 | protected function isShorthand( $shorthand ) { |
155 | return isset( $this->shorthands[$shorthand] ); |
156 | } |
157 | |
158 | /** |
159 | * Determines whether $shorthand can legally be used as a prefix. |
160 | * |
161 | * @param string $prefix |
162 | * |
163 | * @return bool |
164 | */ |
165 | protected function isPrefix( $prefix ) { |
166 | return isset( $this->prefixes[$prefix] ); |
167 | } |
168 | |
169 | /** |
170 | * Returns the prefix map. |
171 | * |
172 | * @return string[] An associative array mapping prefixes to base IRIs. |
173 | */ |
174 | public function getPrefixes() { |
175 | return $this->prefixes; |
176 | } |
177 | |
178 | /** |
179 | * @param string|null $languageCode |
180 | * |
181 | * @return bool |
182 | */ |
183 | protected function isValidLanguageCode( $languageCode ) { |
184 | // preg_match is somewhat (12%) slower than strspn but more readable |
185 | return $languageCode !== null && preg_match( '/^[\da-z-]{2,}$/i', $languageCode ); |
186 | } |
187 | |
188 | /** |
189 | * @return RdfWriter |
190 | */ |
191 | final public function sub() { |
192 | $writer = $this->newSubWriter( self::SUBDOCUMENT_ROLE, $this->labeler ); |
193 | $writer->state = self::STATE_DOCUMENT; |
194 | |
195 | // share registered prefixes |
196 | $writer->prefixes =& $this->prefixes; |
197 | |
198 | $this->subs[] = $writer; |
199 | return $writer; |
200 | } |
201 | |
202 | /** |
203 | * @return string A string corresponding to one of the the XXX_ROLE constants. |
204 | */ |
205 | final public function getRole() { |
206 | return $this->role; |
207 | } |
208 | |
209 | /** |
210 | * Appends string to the output buffer. |
211 | * @param string $w |
212 | */ |
213 | final protected function write( $w ) { |
214 | $this->buffer[] = $w; |
215 | } |
216 | |
217 | /** |
218 | * If $base is a shorthand, $base and $local are updated to hold whatever qname |
219 | * the shorthand was associated with. |
220 | * |
221 | * Otherwise, $base and $local remain unchanged. |
222 | * |
223 | * @param string &$base |
224 | * @param string|null &$local |
225 | */ |
226 | protected function expandShorthand( &$base, &$local ) { |
227 | if ( $local === null && isset( $this->shorthands[$base] ) ) { |
228 | [ $base, $local ] = $this->shorthands[$base]; |
229 | } |
230 | } |
231 | |
232 | /** |
233 | * If $base is a registered prefix, $base will be replaced by the base IRI associated with |
234 | * that prefix, with $local appended. $local will be set to null. |
235 | * |
236 | * Otherwise, $base and $local remain unchanged. |
237 | * |
238 | * @param string &$base |
239 | * @param string|null &$local |
240 | * |
241 | * @throws LogicException |
242 | */ |
243 | protected function expandQName( &$base, &$local ) { |
244 | if ( $local !== null && $base !== '_' ) { |
245 | if ( isset( $this->prefixes[$base] ) ) { |
246 | $base = $this->prefixes[$base] . $local; // XXX: can we avoid this concat? |
247 | $local = null; |
248 | } else { |
249 | throw new LogicException( 'Unknown prefix: ' . $base ); |
250 | } |
251 | } |
252 | } |
253 | |
254 | /** |
255 | * @see RdfWriter::blank() |
256 | * |
257 | * @param string|null $label node label; will be generated if not given. |
258 | * |
259 | * @return string |
260 | */ |
261 | final public function blank( $label = null ) { |
262 | return $this->labeler->getLabel( $label ); |
263 | } |
264 | |
265 | /** |
266 | * @see RdfWriter::start() |
267 | */ |
268 | final public function start() { |
269 | $this->state( self::STATE_DOCUMENT ); |
270 | $this->prefixesLocked = true; |
271 | } |
272 | |
273 | /** |
274 | * @see RdfWriter::finish() |
275 | */ |
276 | final public function finish() { |
277 | // close all unclosed states |
278 | $this->state( self::STATE_DOCUMENT ); |
279 | |
280 | // ...then insert output of sub-writers into the buffer, |
281 | // so it gets placed before the footer... |
282 | $this->drainSubs(); |
283 | |
284 | // and then finalize |
285 | $this->state( self::STATE_FINISH ); |
286 | |
287 | // Detaches all subs. |
288 | $this->subs = []; |
289 | } |
290 | |
291 | /** |
292 | * @see RdfWriter::drain() |
293 | * |
294 | * @return string RDF |
295 | */ |
296 | final public function drain() { |
297 | // we can drain after finish, but finish state is sticky |
298 | if ( $this->state !== self::STATE_FINISH ) { |
299 | $this->state( self::STATE_DOCUMENT ); |
300 | } |
301 | |
302 | $this->drainSubs(); |
303 | $this->flattenBuffer(); |
304 | |
305 | $rdf = implode( '', $this->buffer ); |
306 | $this->buffer = []; |
307 | |
308 | return $rdf; |
309 | } |
310 | |
311 | /** |
312 | * Calls drain() an any RdfWriter instances in $this->buffer, and replaces them |
313 | * in $this->buffer with the string returned by the drain() call. Any closures |
314 | * present in the $this->buffer will be called, and replaced by their return value. |
315 | */ |
316 | private function flattenBuffer() { |
317 | foreach ( $this->buffer as &$b ) { |
318 | if ( $b instanceof Closure ) { |
319 | $b = $b(); |
320 | } |
321 | if ( $b instanceof RdfWriter ) { |
322 | $b = $b->drain(); |
323 | } |
324 | } |
325 | } |
326 | |
327 | /** |
328 | * Drains all subwriters, and appends their output to this writer's buffer. |
329 | * Subwriters remain usable. |
330 | */ |
331 | private function drainSubs() { |
332 | foreach ( $this->subs as $sub ) { |
333 | $rdf = $sub->drain(); |
334 | $this->write( $rdf ); |
335 | } |
336 | } |
337 | |
338 | /** |
339 | * @see RdfWriter::about() |
340 | * |
341 | * @param string $base A QName prefix if $local is given, or an IRI if $local is null. |
342 | * @param string|null $local A QName suffix, or null if $base is an IRI. |
343 | * |
344 | * @return RdfWriter $this |
345 | */ |
346 | final public function about( $base, $local = null ) { |
347 | $this->expandSubject( $base, $local ); |
348 | |
349 | if ( $this->state === self::STATE_OBJECT |
350 | && $base === $this->currentSubject[0] |
351 | && $local === $this->currentSubject[1] |
352 | ) { |
353 | return $this; // redundant about() call |
354 | } |
355 | |
356 | $this->state( self::STATE_SUBJECT ); |
357 | |
358 | $this->currentSubject[0] = $base; |
359 | $this->currentSubject[1] = $local; |
360 | $this->currentPredicate[0] = null; |
361 | $this->currentPredicate[1] = null; |
362 | |
363 | $this->writeSubject( $base, $local ); |
364 | return $this; |
365 | } |
366 | |
367 | /** |
368 | * @see RdfWriter::a() |
369 | * Shorthand for say( 'a' )->is( $type ). |
370 | * |
371 | * @param string $typeBase The data type's QName prefix if $typeLocal is given, |
372 | * or an IRI or shorthand if $typeLocal is null. |
373 | * @param string|null $typeLocal The data type's QName suffix, |
374 | * or null if $typeBase is an IRI or shorthand. |
375 | * |
376 | * @return RdfWriter $this |
377 | */ |
378 | final public function a( $typeBase, $typeLocal = null ) { |
379 | return $this->say( 'a' )->is( $typeBase, $typeLocal ); |
380 | } |
381 | |
382 | /** |
383 | * @see RdfWriter::say() |
384 | * |
385 | * @param string $base A QName prefix. |
386 | * @param string|null $local A QName suffix. |
387 | * |
388 | * @return RdfWriter $this |
389 | */ |
390 | final public function say( $base, $local = null ) { |
391 | $this->expandPredicate( $base, $local ); |
392 | |
393 | if ( $this->state === self::STATE_OBJECT |
394 | && $base === $this->currentPredicate[0] |
395 | && $local === $this->currentPredicate[1] |
396 | ) { |
397 | return $this; // redundant about() call |
398 | } |
399 | |
400 | $this->state( self::STATE_PREDICATE ); |
401 | |
402 | $this->currentPredicate[0] = $base; |
403 | $this->currentPredicate[1] = $local; |
404 | |
405 | $this->writePredicate( $base, $local ); |
406 | return $this; |
407 | } |
408 | |
409 | /** |
410 | * @see RdfWriter::is() |
411 | * |
412 | * @param string $base A QName prefix if $local is given, or an IRI if $local is null. |
413 | * @param string|null $local A QName suffix, or null if $base is an IRI. |
414 | * |
415 | * @return RdfWriter $this |
416 | */ |
417 | final public function is( $base, $local = null ) { |
418 | $this->state( self::STATE_OBJECT ); |
419 | |
420 | $this->expandResource( $base, $local ); |
421 | $this->writeResource( $base, $local ); |
422 | return $this; |
423 | } |
424 | |
425 | /** |
426 | * @see RdfWriter::text() |
427 | * |
428 | * @param string $text the text to be placed in the output |
429 | * @param string|null $language the language the text is in |
430 | * |
431 | * @return $this |
432 | */ |
433 | final public function text( $text, $language = null ) { |
434 | $this->state( self::STATE_OBJECT ); |
435 | |
436 | $this->writeText( $text, $language ); |
437 | return $this; |
438 | } |
439 | |
440 | /** |
441 | * @see RdfWriter::value() |
442 | * |
443 | * @param string $value the value encoded as a string |
444 | * @param string|null $typeBase The data type's QName prefix if $typeLocal is given, |
445 | * or an IRI or shorthand if $typeLocal is null. |
446 | * @param string|null $typeLocal The data type's QName suffix, |
447 | * or null if $typeBase is an IRI or shorthand. |
448 | * |
449 | * @return $this |
450 | */ |
451 | final public function value( $value, $typeBase = null, $typeLocal = null ) { |
452 | $this->state( self::STATE_OBJECT ); |
453 | |
454 | if ( $typeBase === null && !is_string( $value ) ) { |
455 | $vtype = gettype( $value ); |
456 | switch ( $vtype ) { |
457 | case 'integer': |
458 | $typeBase = 'xsd'; |
459 | $typeLocal = 'integer'; |
460 | $value = "$value"; |
461 | break; |
462 | |
463 | case 'double': |
464 | $typeBase = 'xsd'; |
465 | $typeLocal = 'double'; |
466 | $value = "$value"; |
467 | break; |
468 | |
469 | case 'boolean': |
470 | $typeBase = 'xsd'; |
471 | $typeLocal = 'boolean'; |
472 | $value = $value ? 'true' : 'false'; |
473 | break; |
474 | } |
475 | } |
476 | |
477 | $this->expandType( $typeBase, $typeLocal ); |
478 | |
479 | $this->writeValue( $value, $typeBase, $typeLocal ); |
480 | return $this; |
481 | } |
482 | |
483 | /** |
484 | * State transition table |
485 | * First state is "from", second is "to" |
486 | * @var array |
487 | */ |
488 | protected $transitionTable = [ |
489 | self::STATE_START => [ |
490 | self::STATE_DOCUMENT => true, |
491 | ], |
492 | self::STATE_DOCUMENT => [ |
493 | self::STATE_DOCUMENT => true, |
494 | self::STATE_SUBJECT => true, |
495 | self::STATE_FINISH => true, |
496 | ], |
497 | self::STATE_SUBJECT => [ |
498 | self::STATE_PREDICATE => true, |
499 | ], |
500 | self::STATE_PREDICATE => [ |
501 | self::STATE_OBJECT => true, |
502 | ], |
503 | self::STATE_OBJECT => [ |
504 | self::STATE_DOCUMENT => true, |
505 | self::STATE_SUBJECT => true, |
506 | self::STATE_PREDICATE => true, |
507 | self::STATE_OBJECT => true, |
508 | ], |
509 | ]; |
510 | |
511 | /** |
512 | * Perform a state transition. Writer states roughly correspond to states in a naive |
513 | * regular parser for the respective syntax. State transitions may generate output, |
514 | * particularly of structural elements which correspond to terminals in a respective |
515 | * parser. |
516 | * |
517 | * @param int $newState one of the self::STATE_... constants |
518 | * |
519 | * @throws LogicException |
520 | */ |
521 | final protected function state( $newState ) { |
522 | if ( !isset( $this->transitionTable[$this->state][$newState] ) ) { |
523 | throw new LogicException( 'Bad transition: ' . $this->state . ' -> ' . $newState ); |
524 | } |
525 | |
526 | $action = $this->transitionTable[$this->state][$newState]; |
527 | if ( $action !== true ) { |
528 | if ( is_string( $action ) ) { |
529 | $this->write( $action ); |
530 | } else { |
531 | $action(); |
532 | } |
533 | } |
534 | |
535 | $this->state = $newState; |
536 | } |
537 | |
538 | /** |
539 | * Must be implemented to generate output that starts a statement (or set of statements) |
540 | * about a subject. Depending on the requirements of the output format, the implementation |
541 | * may be empty. |
542 | * |
543 | * @note $base and $local are given as passed to about() and processed by expandSubject(). |
544 | * |
545 | * @param string $base |
546 | * @param string|null $local |
547 | */ |
548 | abstract protected function writeSubject( $base, $local = null ); |
549 | |
550 | /** |
551 | * Must be implemented to generate output that represents the association of a predicate |
552 | * with a subject that was previously defined by a call to writeSubject(). |
553 | * |
554 | * @note $base and $local are given as passed to say() and processed by expandPredicate(). |
555 | * |
556 | * @param string $base |
557 | * @param string|null $local |
558 | */ |
559 | abstract protected function writePredicate( $base, $local = null ); |
560 | |
561 | /** |
562 | * Must be implemented to generate output that represents a resource used as the object |
563 | * of a statement. |
564 | * |
565 | * @note $base and $local are given as passed to is() and processed by expandObject(). |
566 | * |
567 | * @param string $base |
568 | * @param string|null $local |
569 | */ |
570 | abstract protected function writeResource( $base, $local = null ); |
571 | |
572 | /** |
573 | * Must be implemented to generate output that represents a text used as the object |
574 | * of a statement. |
575 | * |
576 | * @param string $text the text to be placed in the output |
577 | * @param string|null $language the language the text is in |
578 | */ |
579 | abstract protected function writeText( $text, $language ); |
580 | |
581 | /** |
582 | * Must be implemented to generate output that represents a (typed) literal used as the object |
583 | * of a statement. |
584 | * |
585 | * @note $typeBase and $typeLocal are given as passed to value() and processed by expandType(). |
586 | * |
587 | * @param string $value the value encoded as a string |
588 | * @param string|null $typeBase |
589 | * @param string|null $typeLocal |
590 | */ |
591 | abstract protected function writeValue( $value, $typeBase, $typeLocal = null ); |
592 | |
593 | /** |
594 | * Perform any expansion (shorthand to qname, qname to IRI) desired |
595 | * for subject identifiers. |
596 | * |
597 | * @param string &$base |
598 | * @param string|null &$local |
599 | */ |
600 | protected function expandSubject( &$base, &$local ) { |
601 | } |
602 | |
603 | /** |
604 | * Perform any expansion (shorthand to qname, qname to IRI) desired |
605 | * for predicate identifiers. |
606 | * |
607 | * @param string &$base |
608 | * @param string|null &$local |
609 | */ |
610 | protected function expandPredicate( &$base, &$local ) { |
611 | } |
612 | |
613 | /** |
614 | * Perform any expansion (shorthand to qname, qname to IRI) desired |
615 | * for resource identifiers. |
616 | * |
617 | * @param string &$base |
618 | * @param string|null &$local |
619 | */ |
620 | protected function expandResource( &$base, &$local ) { |
621 | } |
622 | |
623 | /** |
624 | * Perform any expansion (shorthand to qname, qname to IRI) desired |
625 | * for type identifiers. |
626 | * |
627 | * @param string|null &$base |
628 | * @param string|null &$local |
629 | */ |
630 | protected function expandType( &$base, &$local ) { |
631 | } |
632 | |
633 | } |