Documentation automatically generated from the source-code using phpDocumentor.
Official Homepage: xao-php.sourceforge.net
XAO
Official homepage | API home | class tree: XAO | index: XAO | all elements

Source for file XAO_DomDoc.php

Documentation is available at XAO_DomDoc.php


1 <?php
2 /**
3 * XAO_DomDoc.php
4 *
5 * This script provides the class definition for DomDoc. Since the
6 * DomDoc class provides the basis for XAO, all the requirements checks for XAO
7 * are done first up in this script. In general, however, all the code in XAO is
8 * object oriented. For more information on the DomDoc class itself, see the doc
9 * comment directly preceding the class declaration.
10 *
11 * @author Terence Kearns
12 * @version 1.0 alpha
13 * @copyright Terence Kearns 2003
14 * @license LGPL
15 * @link http://xao-php.sourceforge.net
16 * @package XAO
17 */
18
19
20 /**
21 * Import the root (base) XAO class.
22 *
23 * All classes in the XAO library should inherit this class. See documentation on
24 * the class itself for more details.
25 *
26 * @import XaoRoot
27 */
28 include_once "XAO_XaoRoot.php";
29
30 /**
31 * Import the Exceptions utility class.
32 *
33 * This is only instantiated if $this->Throw() is called. This object
34 * encapsulates error data management. It keeps all the error data on the
35 * referenced DOM doc rather than an internal stack.
36 *
37 * @import Exceptions
38 */
39 include_once "XAO_Exceptions.php";
40
41 /**
42 * Import Dom Factory for parsing/obtaining DOM objects.
43 *
44 * This is a general purpose class providing comprehensive parsing options when
45 * obtaining DOM object. Using this class provides centralised DOM object
46 * management across the whole library.
47 *
48 * @import Exceptions
49 */
50 include_once "XAO_DomFactory.php";
51
52 /**
53 * New dom document from from scratch
54 *
55 * This constant represents a mode of the DomDoc which causes it to create a
56 * new document on instatiation - using the starter as the name of the root
57 * element for the new document.
58 */
59 define("XAO_DOC_NEW",10);
60
61 /**
62 * Dom document from local file for reading only.
63 *
64 * This constant represents a mode of the DomDoc which causes it to use an
65 * existing XML file as the basis of the DomDoc document on instatiation -
66 * using the starter to determin the location of the local file. It treats
67 * the file as read-only so none of the write methods will work. It uses a
68 * non-exclusive read lock when opening the file.
69 */
70 define("XAO_DOC_READFILE",20);
71
72 /**
73 * Dom document from existing PHP DOM object instance.
74 *
75 * This constant represents a mode of the DomDoc which causes it to use an
76 * existing PHP DOM XML object instance for this DomDoc instance. This has the
77 * effect of adding functionality from this class to an existing DOM object.
78 */
79 define("XAO_DOC_REFERENCE",50);
80
81 /**
82 * Dom document from existing XML data in a variable.
83 *
84 * This constant represents a mode of the DomDoc which causes it to use
85 * existing XML data as the basis for a new DomDoc object. Obviously the
86 * XML data needs to be well-formed.
87 */
88 define("XAO_DOC_DATA",60);
89
90
91
92 /**
93 * General purpose DOM class
94 *
95 * This class provides three forms of functionality. 1) shortcut functions to
96 * operations made tedious by the DOM API. 2) additional features not supported
97 * by the DOM API. 3) a thread-safe way of interacting with files associated
98 * with the class' DOM document.
99 *
100 * @package XAO
101 */
102 class DomDoc extends XaoRoot {
103
104 /**
105 * Singleton instance of Exceptions object.
106 *
107 * This is only instantiated if $this->Throw() is called. This object
108 * encapsulates error data management. It keeps all the error data on the
109 * referenced DOM doc rather than a stack local to this class.
110 *
111 * @access public
112 * @var object
113 */
114 var $objErr;
115
116 /**
117 * Element containing the last(current) error message.
118 *
119 * This is populated by $this->Throw() and is always appended to the root
120 * node. in order for consumed DOM documents to have their errors displayed
121 * the consume function of the context DomDoc needs to search for these and
122 * copy them to the root node of itself.
123 *
124 * @access public
125 * @var node
126 */
127 var $ndErr;
128
129 /**
130 * An instance of the main DOM XML object.
131 *
132 * The native PHP DOM XML object is kept here. Any PHP DOM methods may
133 * be accessed directly from this object. For instance,
134 * $objMy->objDoc->get_element_by_id(); The user can also pass this member
135 * to functions requiring a native PHP DOM XML object. It is important to
136 * note that the XAO API in no way limits the user's access to PHP's built-in
137 * functions.
138 *
139 * @access public
140 * @var object
141 */
142 var $objDoc;
143
144 /**
145 * Document root node
146 *
147 * This object variable conains a reference to the root element node
148 * of this DomDoc. It's a handy shortcut to $this->objDoc->document_root()
149 * because it is used a lot.
150 *
151 * @access public
152 * @var node
153 */
154 var $ndRoot;
155
156 /**
157 * How has the document been instantiated.
158 *
159 * This attribute remembers the value of the mode constant that was
160 * used to instantiate this DomDoc object.
161 *
162 * @access private
163 * @var integer from constant
164 */
165 var $_intMode;
166
167 /**
168 * Queue of element objects to be procssed
169 *
170 * Users can use the SetCustomTagName() function to nominate elements by
171 * name to be kept in this list. The method also requires the name of a
172 * valid function to do the processing.
173 *
174 * @access private
175 * @var integer from constant
176 */
177 var $_arrCustomTagNames = array();
178
179 /**
180 * Queue of query result node objects to be procssed
181 *
182 * Users can use the SetCustomTagQuery() function to find nodes to be kept
183 * in this list. The method also requires the name of a valid function to do
184 * the processing.
185 *
186 * @access private
187 * @var integer from constant
188 */
189 var $_arrCustomTagQueries = array();
190
191 /**
192 * Constructor method
193 *
194 * Create the objDoc instance property and associated ndRoot property based
195 * on the user-selected mode of document creation.
196 *
197 * @param mixed information required to create a DOM document
198 * @param int constant specifying how the document is to be created
199 * @return void
200 * @access public
201 */
202 function DomDoc(&$mxdData,$intUse = XAO_DOC_NEW) {
203
204 $this->_intMode = $intUse;
205 // for more info on each case block, see
206 // comments in the constant definitions
207 // at the top of this file.
208 if($this->_intMode == XAO_DOC_NEW) {
209 $this->objDoc = domxml_new_doc("1.0");
210 $elRoot = $this->objDoc->create_element($mxdData);
211 $this->ndRoot = $this->objDoc->append_child($elRoot);
212 }
213 elseif(
214 $this->_intMode == XAO_DOC_READFILE
215 || $this->_intMode == XAO_DOC_DATA
216 ) {
217 $objDomFactory =& new DomFactory($mxdData);
218 if(strlen($objDomFactory->strErrorMsgFull)) {
219 $this->_AbortDocument($objDomFactory->strErrorMsgFull);
220 die($objDomFactory->strError);
221 }
222 else {
223 $this->objDoc = $objDomFactory->objGetObjDoc();
224 }
225 $this->ndRoot = $this->objDoc->document_element();
226 }
227 elseif($this->_intMode == XAO_DOC_REFERENCE) {
228 $this->objDoc =& $mxdData;
229 $this->ndRoot = @$mxdData->document_element()
230 OR $this->_AbortDocument(
231 "The reference document object is not a valid native
232 PHP DOM XML document."
233 );
234 }
235 else {
236 $this->_AbortDocument(
237 "The second argument to DomDoc constructor is invalid."
238 );
239 }
240 }
241
242 /**
243 * Abort document initialisation and instantiate an error document instead.
244 *
245 * If something goes wrong in the initialisation process, the creation of a
246 * document is aborted and a token error document is initialised instead.
247 * Ordinarily, the $this->Throw() method is used to raise errors, however
248 * if the initialisation process is not complete, then $this->Throw() will
249 * not work. This function ensures that a document is always created and
250 * then it calls the throw function.
251 *
252 * @param string Error message to be contained in the error root element
253 * @return void
254 * @access private
255 */
256 function _AbortDocument($strErrMsg) {
257 // produce a basic documemnt so that we
258 // have enough to throw an error.
259 $this->objDoc = domxml_new_doc("1,0");
260 $ndRoot = $this->objDoc->create_element("abortedDoc");
261 $this->ndRoot = $this->objDoc->append_child($ndRoot);
262
263 $arrErrAttribs = array("code" => "DomDocInit");
264 $this->Throw(
265 $strErrMsg,
266 $arrErrAttribs,
267 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
268 );
269 }
270
271 /**
272 * Base error logger
273 *
274 * All DomDoc based objects should use this method to raise errors. The
275 * method will not stop execution. It will create elements on the DomDoc
276 * tree containing all the error data available. It is up to the stylsheet
277 * to extract and render error information through an appropriate template.
278 * Users should note the ability to define a custom call-back function which
279 * may be created as a method in the child object. To do this, populate
280 * $this->strErrCallbackFunc with the name of your custom error method.
281 * To find out more about how the exception elements are populated, check
282 * out the documentation in the Exceptions class.
283 *
284 * @param string Main error message for display
285 * @param array A hash of attributes/values to include in error element
286 * @return void
287 * @access public
288 */
289 function Throw($strErrMsg,$arrAttribs = null) {
290 if(is_null($arrAttribs)) $arrAttribs = array();
291 parent::Throw($strErrMsg,$arrAttribs);
292 // obtain singleton error object if it
293 // does not already exist.
294 if(!is_object($this->objErr)){
295 // set up the error node to pass to the
296 // Exceptions constructor. Ensure that
297 // all the contents have a default
298 // namespace in XAO
299 $ndExceptions = $this->ndAppendToRoot("exceptions");
300 $ndExceptions->set_attribute("xmlns",$this->idXaoNamespace);
301 $this->objErr =
302 new Exceptions($this->objDoc, $ndExceptions, "exception");
303 }
304 // the Exceptions class is not much use
305 // without populating this.
306 $this->objErr->SetMessage($this->strError);
307 // optional extras go here.
308 $this->objErr->SetMsgAttribs($arrAttribs);
309 // This is where all the action occurs
310 // in the Exceptions class. See the Doc
311 // comments in that class for details.
312 $this->ndErr = $this->objErr->ndCreateError();
313 }
314
315 /**
316 * Serialise and return the entire document object as stand-alone XML.
317 *
318 * This is used when the entire XML document is required in ASCII format.
319 *
320 * @return xml document
321 * @access public
322 */
323 function xmlGetDoc() {
324 $this->_TestForConstuctor();
325 return $this->objDoc->dump_mem(true);
326 }
327
328 /**
329 * Serialise and return the entire document as an XML fragment.
330 *
331 * This is used when an ASCII version of the XML document is required
332 * _without_ any XML declaration or processing instructions. Everything
333 * below and including the root element is serialised.
334 *
335 * @return xml fragment
336 * @access public
337 */
338 function xmlGetFrag() {
339 $this->_TestForConstuctor();
340 return "\n\n".$this->objDoc->dump_node($this->ndRoot,true)."\n\n";
341 }
342
343 /**
344 * mass storage serialisation
345 *
346 * This function will dump the ASCII version of this XML document [in it's
347 * current state] to a specified file.
348 *
349 * @param uri path to destination file
350 * @return void
351 * @access public
352 */
353 function CommitToFile($uriDestination) {
354 $this->_TestForConstuctor();
355 if(!file_exists($uriDestination)) {
356 $this->Throw(
357 "CommitToFile: ".$uriDestination." was not found.",
358 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
359 );
360 return;
361 }
362 $fp = @fopen($uriDestination,"w+")
363 or $this->Throw(
364 "CommitToFile: could not open ".$uriDestination." for writing",
365 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
366 );
367 @flock($fp,LOCK_EX)
368 or $this->Throw(
369 "CommitToFile: Could not get an exclusive lock on "
370 .$uriDestination." for writing",
371 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
372 );
373 fwrite($fp,$this->xmlGetDoc())
374 or $this->Throw(
375 "CommitToFile: could write to ".$uriDestination,
376 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
377 );
378 flock($fp,LOCK_UN);
379 fclose($fp);
380 }
381
382 /**
383 * fetch a single element node by name
384 *
385 * A convenience function for fetching a node reference to an element by
386 * specifying only it's name.
387 *
388 * @param uri name of the element whose node is to be returned
389 * @param integer index of which node to return (0 for first)
390 * @return node
391 * @access public
392 */
393 function &ndGetOneEl($strName,$intIdx=0) {
394 $this->_TestForConstuctor();
395 $arrNds = $this->objDoc->get_elements_by_tagname($strName);
396 if(isset($arrNds[$intIdx])) return $arrNds[$intIdx];
397 return false;
398 }
399
400 /**
401 * quickly add a new element under the root element.
402 *
403 * This function is basically a shortcut for the common task of adding a new
404 * element with some content under the root element of the document.
405 *
406 * @param string the name of the new element
407 * @param string the content of the new element
408 * @return node the newly added element node object
409 * @access public
410 */
411 function &ndAppendToRoot($strElName,$strCont = "") {
412 $this->_TestForConstuctor();
413 if(!$this->blnTestXmlName($strElName)) {
414 $this->Throw(
415 "ndAppendToRoot: ".$strElName
416 ." Is not a valid element name.",
417 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
418 );
419 return false;
420 }
421 $elNew = $this->objDoc->create_element($strElName);
422 $ndNew = $this->ndRoot->append_child($elNew);
423 $ndNew->set_content($strCont);
424 return $ndNew;
425 }
426
427 /**
428 * quickly add a new element under an exising element node.
429 *
430 * This function is basically a shortcut for the common task of adding a new
431 * element with some content under an existing node of the document.
432 *
433 * @param node a reference to the exisitng element node
434 * @param string the name of the new element
435 * @param string the content of the new element
436 * @return node the newly added element node object
437 * @access public
438 */
439 function &ndAppendToNode(&$ndStub,$strElName,$strCont = "") {
440 $this->_TestForConstuctor();
441 if(!$this->blnTestElementNode($ndStub)) {
442 $this->Throw(
443 "ndAppendToNode: First argument is not a valid element node.",
444 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
445 );
446 return false;
447 }
448 if(!$this->blnTestXmlName($strElName)) {
449 $this->Throw(
450 "ndAppendToNode: ".$strElName
451 ." Is not a valid element name.",
452 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
453 );
454 return false;
455 }
456 $elNew = $this->objDoc->create_element($strElName);
457 $ndNew = $ndStub->append_child($elNew);
458 $ndNew->set_content($strCont);
459 return $ndNew;
460 }
461
462 /**
463 * Import a fragment from a foreign PHP DOM XML document
464 *
465 * This function will import a fragment from a foreign PHP DOM XML document
466 * below the node specified in the first parameter. This function is
467 * especially used by the other Consume methods in this class.
468 * At the moment it EXPLOITS the fact that node::replace_node() allows the
469 * use of foreign DOM XML objects - this is not in the spec.
470 * So this behaviour cannot be relied upon. It's worth noting that there
471 * is an xinclude() function which looks like it might be the way to go but
472 * documentation is vague http://www.xmlsoft.org/html/libxml-xinclude.html
473 * http://www.php.net/manual/en/function.domdocument-xinclude.php
474 * in any case, all maintenance for this functionality is centralised at this
475 * one point in the XAO api. If neccesary, it may eploy different techniques
476 * based on detecting which version of php/domxml is in use. Needless to say
477 * that this function is PIVOTAL to the XAO framework concept which uses
478 * aggregation to accumulate content through the CONSUME methods.
479 *
480 * @param node the node under which the fragment is to be grafted
481 * @param node foreign node containing the fragment to be imported
482 * @return node the newly added element node object
483 * @access public
484 */
485 function &ndImportChildFrag(&$ndStub,&$ndNew) {
486 $this->_TestForConstuctor();
487 if(!$this->blnTestElementNode($ndStub)) {
488 $this->Throw(
489 "ndImportChildFrag: First argument is not a valid element node."
490 ,$this->arrSetErrFnc(__FUNCTION__,__LINE__)
491 );
492 return false;
493 }
494 if(!$this->blnTestElementNode($ndNew)) {
495 $this->Throw(
496 "ndImportChildFrag: Second argument is not a valid element"
497 ." node.", $this->arrSetErrFnc(__FUNCTION__,__LINE__)
498 );
499 return false;
500 }
501 $ndTmp = $this->objDoc->create_element("tmp");
502 $ndTmp = $ndStub->append_child($ndTmp);
503 $ndTmp->replace_node($ndNew);
504 return $ndNew;
505 }
506
507 /**
508 * Import a foreign PHP DOM XML document and append it below $this->ndRoot
509 *
510 * This function will consume the contents of an entire DOM document and
511 * retain it below the root node of this DomDoc.
512 *
513 * @param DomDoc a reference to an exising PHP DOM XML document
514 * @param node an optional stub node to which the new data is grafted
515 * @access public
516 */
517 function &ndConsumeDoc(&$objDoc,$ndStub = null) {
518 $this->_TestForConstuctor();
519 if(!is_object($objDoc)) {
520 $this->Throw(
521 "ndConsumeDoc: No DomDoc object given",
522 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
523 );
524 }
525 elseif(!isset($objDoc->ndRoot)) {
526 $this->Throw(
527 "ndConsumeDoc: No root node. First param must be an XAO "
528 ."DomDoc, not just a basic PHP DOMXML object. Use the "
529 ."DomFactory class if you need to convert an existing PHP "
530 ."DOMXML object.",
531 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
532 );
533 }
534 else {
535 if(!$this->blnTestElementNode($ndStub)) $ndStub = $this->ndRoot;
536 return $this->ndImportChildFrag($ndStub,$objDoc->ndRoot);
537 }
538 return false;
539 }
540
541 /**
542 * Import an XML document from a file and append it below $this->ndRoot
543 *
544 * This function will consume the contents of an entire XML document from a
545 * file and retain it below the root node of this DomDoc.
546 *
547 * @param uri the location of the XML file
548 * @access public
549 */
550 function ndConsumeFile($uri,$ndStub = null) {
551 // If there are any parse errors, then
552 // they will be included in the object
553 // returned by DomDoc. It's up to the
554 // stylsheet to extract them.
555 $objDoc = new DomDoc($uri,XAO_DOC_READFILE);
556 // The new DomDoc is inevitably grafted
557 // on to this DomDoc - errors and all.
558 if(!$this->blnTestElementNode($ndStub)) $ndStub = $this->ndRoot;
559 return $this->ndImportChildFrag($ndStub,$objDoc->ndRoot);
560 }
561
562 /**
563 * Import well-balenced XML data to append below $this->ndRoot
564 *
565 * This function will consume the contents of some XML data after wrapping
566 * it in a root element whos name is specified in the second parameter. The
567 * content is then retained under $this->ndRoot
568 *
569 * @param xml Miscellaneous XML data
570 * @param string The name of the root element
571 * @access public
572 */
573 function ndConsumeFragData($str,$strRoot,$ndStub = null) {
574 $this->_TestForConstuctor();
575 // this regex needs to be tested!
576 if(!$this->blnTestXmlName($strRoot)) {
577 $this->Throw(
578 "ndConsumeFragData: ".$strRoot
579 ." is an invalid name for root element.",
580 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
581 );
582 }
583 else {
584 // wrap the fragment data in a basic
585 // XML envelope
586 $str = "<"."?xml version=\"1.0\"?".">\n<".$strRoot.">"
587 .$str."</".$strRoot.">";
588 // If there are any parse errors, then
589 // they will be included in the object
590 // returned by DomDoc. It's up to the
591 // stylsheet to extract them.
592 $objDoc = new DomDoc($str,XAO_DOC_DATA);
593 // The new DomDoc is inevitably grafted
594 // on to this DomDoc - errors and all.
595 if(!$this->blnTestElementNode($ndStub)) $ndStub = $this->ndRoot;
596 return $this->ndImportChildFrag($ndStub,$objDoc->ndRoot);
597 }
598 }
599
600 /**
601 * Import well-balenced XML data to append below $this->ndRoot
602 *
603 * This function will consume the contents of an XML document.The
604 * content is then retained under $this->ndRoot
605 *
606 * @param xml Miscellaneous XML data
607 * @access public
608 */
609 function ConsumeDocData($str) {
610 $objDoc = new DomDoc($str,XAO_DOC_DATA);
611 $this->ImportChildFrag($this->ndRoot,$objDoc->ndRoot);
612 }
613
614 /**
615 * Test to see if the DomDoc constructor has been run
616 *
617 * This needs to be done for the sake of developers who can't figure out why
618 * their script dies when inheriting from DomDoc. If $this->DomDoc is
619 * not executed somewhere before one of the other methods on this class is
620 * called, then most of them won't work - including $this->Throw()!!!!!!
621 * This function is designed to check that and broadcast a dirty great
622 * message announcing the fact. It's a bit of a hack but it's provided for
623 * "extra" safety which should make life easier for the absent-minded
624 * developer.
625 *
626 * @access private
627 * @return void
628 */
629 function _TestForConstuctor() {
630 // The existance of $this->objDoc is
631 // garenteed. Even if the constructor
632 // fails to initialise one, then
633 // $this->_AbortDocument should be
634 // called which provides a surrogate.
635 if(!is_object($this->objDoc)) {
636 $strThis = "DomDoc";
637 // try to find out the names of classes
638 // used to inherit DomDoc and use this
639 // information to produce a [hopefully]
640 // helpful warning.
641 $strParent = get_parent_class($this);
642 $strYoungest = get_class($this);
643 $msg = "
644 <h1>MASSAGEFORTHEPROGRAMMER: $strThisconstructornotcalled!</h1>
645 <p>Youaretryingtoaccessmethodson$strThiswithoutrunning
646 ".$strThis."->DomDoc()</p>
647 <p>The immediate parent to $strThis is $strParent . You probably
648 need to call ".$strThis."->DomDOc() in it's constructor. PHP
649 does not automatically call the constructor of the superclass
650 in a sub class's constructor.</p>
651 ";
652 if($strParent != $strYoungest) {
653 $msg .= "
654 <p>If you already called ".$strThis."->DomDOc() from the
655 constructor in $strParent, then you probably didn't call the
656 constructor for $strParent in $strYoungest. Assuming that
657 $strYoungest is indeed a child of $strParent.</p>
658 <p>You're getting this ugly message because $strThis
659 cannot handle exceptions nicely if it is not instantiated
660 properly.</p>
661 <p>Below is a debug_backtrace() which should help trace
662 where the problem (method call) originated from.</p>
663 ";
664 }
665 $arr = debug_backtrace();
666 echo $msg."<pre>";
667 var_dump($arr);
668 echo("</pre>");
669 die("<h3>Script execution terminated.</h3>");
670 }
671 }
672
673
674 /**
675 * Turn an associative array into attributes
676 *
677 * The hash keys are used for the attribute names and the values are used
678 * for the attribute values.
679 *
680 * @param node
681 * @param array
682 * @access public
683 */
684 function Arr2Atts(&$ndEl,$arrAttribs) {
685 if(!$this->blnTestElementNode($ndEl)) {
686 $this->Throw(
687 "Arr2Atts: First argument is not a valid element node.",
688 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
689 );
690 return false;
691 }
692
693 foreach($arrAttribs AS $strName => $strValue) {
694 $ndAttrib = @$ndEl->set_attribute($strName,$strValue);
695 if(!is_object($ndAttrib)) $this->Throw(
696 "Arr2Atts: Could not set attribute using "
697 ."NAME(\"".$strName."\") and VALUE(\"".$strValue."\").",
698 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
699 );
700 }
701 return true;
702 }
703
704 /**
705 * Use an XPath to nominate nodes for processing by a call-back function.
706 *
707 * This functionality is dubious when using namespaces. The experimental
708 * nature of PHP's DOMXML extension makes it impossible to guarentee safe
709 * usage.
710 *
711 * @param string XPath query
712 * @param string name of user-defined callback function
713 * @access public
714 */
715 function SetCustomTagQuery($strQuery,$fncName) {
716 if(method_exists($this,$fncName)) {
717 $this->_arrCustomTagQueries[] = array($strQuery,$fncName);
718 }
719 else {
720 $this->Throw(
721 "SetCustomTag: Method ".$fncName." is undefined.",
722 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
723 );
724 }
725 }
726
727 /**
728 * Have all elements of a specified name processed by a call-back function.
729 *
730 * This functionality is dubious when using namespaces. The experimental
731 * nature of PHP's DOMXML extension makes it impossible to guarentee safe
732 * usage.
733 *
734 * @param string name of element to be globally matched
735 * @param string name of user-defined callback function
736 * @access public
737 */
738 function SetCustomTagName($elName,$fncName) {
739 if(method_exists($this,$fncName)) {
740 if($this->blnTestXmlName($elName)) {
741 $this->_arrCustomTagNames[$elName] = $fncName;
742 }
743 else {
744 $this->Throw(
745 "SetCustomTag: ".$elName." is not a valid tag name",
746 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
747 );
748 }
749 }
750 else {
751 $this->Throw(
752 "SetCustomTag: Method ".$fncName." is undefined.",
753 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
754 );
755 }
756 }
757
758 /**
759 * Process all nodes (domelements) due for processing.
760 *
761 * When the user has finished nominating all the nodes for processing using
762 * either SetCustomTagName() or SetCustomTagQuery(), then this function can
763 * be called. It's a good idea to make sure this is only called as many times
764 * as it needs to be (once).
765 *
766 * @access public
767 */
768 function ProcessCustomTags() {
769 // process all tag-name call-backs
770 foreach($this->_arrCustomTagNames AS $elName => $fncName) {
771 $arrNd = $this->objDoc->get_elements_by_tagname($elName);
772 if(is_array($arrNd)) {
773 foreach ($arrNd AS $nd) $this->$fncName($nd);
774 }
775 else {
776 $this->Throw(
777 "ProcessCustomTags: there was an error searching for "
778 .$elName." in the document.",
779 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
780 );
781 }
782 }
783 // process all xpath query call-backs
784 foreach($this->_arrCustomTagQueries AS $arrQryFunc) {
785 $strQry = $arrQryFunc[0];
786 $fncName = $arrQryFunc[1];
787 $arrNd = $this->arrNdXPathGet($strQry);
788 if(is_array($arrNd)) {
789 foreach($arrNd AS $nd) $this->$fncName($nd);
790 }
791 else {
792 $this->Throw(
793 "XPath query ".$strQry." did not work. Unfortunately, the "
794 ."underlying DOMXML function does not give up any error "
795 ."information to pass on. Sorry.",
796 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
797 );
798 }
799 }
800 }
801
802 /**
803 * Return a list of nodes resulting from an XPath Query
804 *
805 * This function runs the XPath query and returns an array of nodes matching
806 * the results. Unfortunately, xpath_eval() never divulges any error
807 * information. I assume that $objRes->nodeset holds a false value if the
808 * query errored.
809 *
810 * @param string The XPath query
811 * @access public
812 */
813 function &arrNdXPath($strExpr) {
814 ob_start();
815 $objRes =& xpath_eval(xpath_new_context($this->objDoc),$strExpr);
816 $strDebugData = ob_get_contents();
817 ob_end_clean();
818 if(strlen($strDebugData) || is_array($objRes->nodeset)) {
819 $this->throw(
820 "XPath query ".$strExpr." returned errors:\n".$strDebugData
821 );
822 $this->strDebugData = $strDebugData;
823 return false;
824 }
825 return $objRes->nodeset;
826 }
827
828 /**
829 * Test if the supplied node is on object of type "domelement"
830 *
831 * This function is useful for testing variables that need to be accessed as
832 * domelement objects..
833 *
834 * @param string The name to test.
835 * @access public
836 */
837 function blnTestElementNode($ndEl) {
838 if(!is_object($ndEl)) return false;
839 (get_class($ndEl) == "domelement") ? $res = true : $res = false;
840 return $res;
841 }
842
843 /**
844 * Do a reliable test for a valid element name
845 *
846 * This function tries to create an element using the supplied name. If it
847 * fails, then the name is assumed to be invalid.
848 *
849 * @param string The name to test.
850 * @access public
851 */
852 function blnTestXmlName($strName) {
853 $ndTest = @$this->objDoc->create_element($strName);
854 (is_object($ndTest)) ? $res = true : $res = false;
855 return $res;
856 }
857 } // END CLASS
858 ?>

Documentation generated on Tue, 23 Sep 2003 18:33:58 +1000 by phpDocumentor 1.2.2