1: /**
   2:   **********************************************************************
   3: 
   4:   Copyright (c) 2011-2015 Ruurd J. Idenburg. All rights reserved.                                             
   5: 
   6:   This program and the accompanying materials are made available under
   7:   the terms of the Common Public License v1.0 which accompanies this
   8:   distribution. A copy is also available at the following address:
   9:   
  10:   http://www.opensource.org/licenses/cpl1.0.php                         
  11: 
  12:   Redistribution and use in source and binary forms, with or without
  13:   modification, are permitted provided that the following conditions
  14:   are met:                                                              
  15: 
  16:   Redistributions of source code must retain the above copyright
  17:   notice, this list of conditions and the following disclaimer.         
  18: 
  19:   Redistributions in binary form must reproduce the above copyright
  20:   notice, this list of conditions and the following disclaimer in the
  21:   documentation and/or other materials provided with the distribution.  
  22:  
  23:   Neither the name or trademarks of Ruurd J. Idenburg nor the names
  24:   of any  contributors may be used to endorse or promote products
  25:   derived from this software without specific prior written permission. 
  26:  
  27:   DISCLAIMER                                                            
  28: 
  29:   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  30:   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  31:   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  32:   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  33:   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  34:   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  35:   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  36:   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  37:   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38:   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  39:   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40:   
  41:   ********************************************************************** 
  42: */
  43: /* CLASS: xmlUtil */
  44: /**
  45:   xmlDom basic types and other useful things
  46: */
  47: 
  48: /**
  49:   XML name valid characters. For (oo)Rexx, which only supports ASCII at the moment the valid range is alpha (lower and
  50:   upper) and digits, plus '.', '-', '_' and' :' (this last one for qualified names (i.e. namespace:tag)). 
  51:   @return valid - A string containing the valid characters for a XML name
  52: */
  53: ::routine xmlValidName public
  54: valid = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_:'
  55: return valid
  56: /**
  57:   Generates a "under construction" message for things not yet operational.
  58:   @param name - The name of the thing the message is about
  59:   @return message - The message text
  60: */
  61: ::routine isUnderConstruction public
  62:   use strict arg name
  63:   message = name "is currently under construction!"
  64: return message 
  65: /**
  66:   xmlDomString is a subclass of String, for the time being without any modifications.
  67: */  
  68: ::class xmlDomString public subclass string
  69: /**
  70:   xmlDomTimeStamp represents a number of milliseconds
  71: */
  72: ::class xmlDomTimeStamp public subclass string
  73: /**
  74:   xmlDomUserData represents a reference to application data.
  75: */
  76: ::class xmlDomUserData public
  77: /**
  78:   xmlDomObject represents an object reference. 
  79: */
  80: ::class xmlDomObject public
  81: 
  82: /**
  83:   domExceptions and their codes.
  84: 
  85:   DOM operations only raise exceptions in "exceptional" circumstances, i.e., when an operation is impossible to perform
  86:   (either for logical reasons, because data is lost, or because the implementation has become unstable). In general, DOM
  87:   methods return specific error values in ordinary processing situations, such as out-of-bound errors when using 
  88:   NodeList.
  89: 
  90:   Implementations should raise other exceptions under other circumstances. For example, implementations should raise an 
  91:   implementation-dependent exception if a .nil argument is passed when null was not expected.
  92: 
  93:   Some languages and object systems do not support the concept of exceptions. For such systems, error conditions may be
  94:   indicated using native error reporting mechanisms. For some bindings, for example, methods may return error codes 
  95:   similar to those listed in the corresponding method descriptions. 
  96: 
  97: */
  98: ::class domException public
  99: /**
 100:   INDEX_SIZE_ERR - If index or size is negative, or greater than the allowed 
 101:   value.
 102: */
 103: ::method index_size_err class
 104: return 1
 105: /**
 106:   DOMSTRING_SIZE_ERR - If the specified range of text does not fit into a 
 107:   DOMString.
 108: */
 109: ::method domstring_size_err class
 110: return 2
 111: /**
 112:   HIERARCHY_REQUEST_ERR - If any Node is inserted somewhere it doesn't belong.
 113: */
 114: ::method hierarchy_request_err class
 115: return 3
 116: /**
 117:   WRONG_DOCUMENT_ERR - If a Node is used in a different document than the one 
 118:   that created it (that doesn't support it).
 119: */
 120: ::method wrong_document_err class
 121: return 4
 122: /**
 123:   INVALID_CHARACTER_ERR - If an invalid or illegal character is specified, such 
 124:   as in an XML name.
 125: */
 126: ::method invalid_character_err class
 127: return 5
 128: /**
 129:   NO_DATA_ALLOWED_ERR - If data is specified for a Node which does not support 
 130:   data
 131: */
 132: ::method no_data_allowed_err class
 133: return 6
 134: /**
 135:  NO_MODIFICATION_ALLOWED_ERR - If an attempt is made to modify an object where 
 136:  modifications are not allowed.
 137: */
 138: ::method no_modification_allowed_err class
 139: return 7
 140: /**
 141:   NOT_FOUND_ERR - If an attempt is made to reference a Node in a context where 
 142:   it does not exist.
 143: */
 144: ::method not_found_err class
 145: return 8
 146: /**
 147:   NOT_SUPPORTED_ERR - If the implementation does not support the requested type of object or operation.
 148: */
 149: ::method not_supported_err class
 150: return 9
 151: /**
 152:   INUSE_method_ERR - If an attempt is made to add an method that is already in use elsewhere.
 153: */
 154: ::method inuse_method_err class
 155: return 10
 156: /**
 157:   INVALID_STATE_ERR - If an attempt is made to use an object that is not, or is no longer, usable.
 158: */
 159: ::method invalid_state_err class
 160: return 11
 161: /**
 162:   SYNTAX_ERR - If an invalid or illegal string is specified.
 163: */
 164: ::method syntax_err class
 165: return 12
 166: /**
 167:   INVALID_MODIFICATION_ERR - If an attempt is made to modify the type of the underlying object.
 168: */
 169: ::method invalid_modification_err class
 170: return 13
 171: /**
 172:   NAMESPACE_ERR - If an attempt is made to create or change an object in a way which is incorrect with regard to
 173:   namespaces.
 174: */
 175: ::method namespace_err class
 176: return 14
 177: /**
 178:  INVALID_ACCESS_ERR - If a parameter or an operation is not supported by the underlying object.
 179: */
 180: ::method invalid_access_err class
 181: return 15
 182: /**
 183:   VALIDATION_ERR - If a call to a method such as insertBefore or removeChild would make the Node invalid with respect to
 184:   "partial validity", this exception would be raised and the operation would not be done. This code is used in [DOM 
 185:   Level 3 Validation]. Refer to this specification for further information.
 186: */
 187: ::method validation_err class
 188: return 16
 189: /**
 190:   TYPE_MISMATCH_ERR - If the type of an object is incompatible with the expected type of the parameter associated to the
 191:   object. 
 192: */
 193: ::method type_mismatch_err class
 194: return 17
 195: /* :end */
 196: 
 197: /* CLASS: xmlNodeList */ 
 198: /**
 199:   The xmlNodeList interface provides the abstraction of an ordered collection of xmlNodes, without defining or 
 200:   constraining how this collection is implemented. xmlNodeList objects in the DOM are live.
 201:   
 202:   For this ooRexx implementation a xmlNodeLIst is defined as a resticted array, whose members must be an instance of
 203:   xmLNode.
 204:   
 205:   The items in the xmlNodeList are accessible via an integral index, starting from 0. 
 206: */
 207: ::class xmlNodeList public 
 208: /**
 209:   Provide the number of xmlNodes in the xmlNodeList.
 210:   @return count - The number of items (xmlNodes) in the xmlNodeList.
 211: */
 212: ::method length 
 213: return self~nodeList~items
 214: /**
 215:   The nodeList array can only be set by the xmlNodeList self
 216: */
 217: ::attribute nodeList get
 218: ::attribute nodeList set
 219: /**
 220:   xmlNodeList instance constructor.
 221:   
 222:   As the creation of the xmlNodeList is left to the implementer, for ooRexx the constructor expects to get the
 223:   representation of the complete xmlNodeList as an ooRexx array.
 224:   @param nodeList=(.array~new) - an ooRexx array of xmlNodes.
 225: */
 226: ::method init
 227:   use strict arg nodeList=(.array~new)
 228:   if \nodeList~isA(.array) 
 229:     then raise syntax 93.914 array (nodeList, .Array)
 230:   self~nodeList = nodeList
 231: exit
 232: /**
 233:   Retrieve the xmlNode at index position.
 234:   @param index - The index (base 0) of the wanted Node. 
 235:   @return node - The xmlNode at the index in the xmlNodeList, or .nil if not a valid index.
 236: */
 237: ::method item 
 238:   use strict arg index
 239:   node = .nil
 240:   if index>=0 
 241:     then node = self~nodeList[index+1]
 242: return node
 243: /**
 244:   Add a xmlNode to the xmlNodeList.
 245:   @param node - The xmlNode to be added to the xmlNodeList.
 246:   @raises user domException - HIERARCHY_REQUEST_ERR
 247:   
 248: */
 249: ::method append
 250:   use strict arg node
 251:   if \node~isA(.xmlNode)
 252:     then raise syntax 88.914 array (node, .xmlNode)
 253:   self~nodeList~append(node)
 254: return
 255: /**
 256:   Removes a xmlNode from the xmlNodeList.
 257:   @param node - The xmlNode to be removed.
 258:   @return node - The removed xmlNode or .nil, if not present.
 259: 
 260:   Note: On hold for possible future use
 261: */
 262: ::method remove private protected
 263:   use strict arg node
 264:   node = self~nodelist~remove(node)
 265: return node
 266: /**
 267:   @return array - A native ooRexx array representing the xmlNodeList.
 268: */
 269: ::method toOorexxArray
 270: return self~nodeList
 271: /**
 272:   Sets the xmlNodeList from a native ooRexx array.
 273:   @param nodeArray - the native ooRexx array to replace an existing xmlNodeList.
 274: */
 275: ::method fromOorexxArray
 276:   use strict arg nodeArray
 277:   do i=1 to nodeArray~items
 278:     if \nodeArray[i]~isA(.xmlNode)
 279:       then raise syntax 88.914 array (nodeArray[i], .xmlNode)
 280:   end
 281:   self~nodeList = nodeArray
 282: return
 283: /* :end */
 284: 
 285: /* CLASS: xmlNode */
 286: /**
 287:   The xmlNode class is the base class for real nodetypes such as elementNode and textNode. 
 288:   
 289:   Methods that make no sense or that are just plain impossible to implement in this base class, because the
 290:   implementation is only possible in a subclass will raise syntax error 93.963 - Unsupported or not implented method.
 291:   
 292:   Methods that have a default value (e.g. .nil) will be intialized to that default value and need to be overridden in
 293:   the appropiate subclass.
 294: */
 295: ::class xmlNode public
 296: /**
 297:   A convenience constant to implement null
 298: */
 299: ::constant null .nil
 300: /**
 301:   Constants that define the type of nodes that are possible.
 302: */
 303: ::constant elementNode 1 
 304: ::constant attributeNode 2
 305: ::constant textNode 3
 306: ::constant cdataSectionNode 4
 307: ::constant entityReferenceNode 5
 308: ::constant entityNode 6
 309: ::constant processingInstructionNode 7
 310: ::constant commentNode 8
 311: ::constant documentNode 9
 312: ::constant documentTypeNode 10
 313: ::constant documentFragmentNode 11
 314: ::constant notationNode 12
 315: /**
 316:   instances is a private class attribute (property) that is used to
 317:   keep track of the node instances being created and to provide a unique 
 318:   identifier for each node.
 319: */
 320: ::attribute instances class private
 321: /**
 322:   Gets a unique identifier for each (subclass) node being created.
 323:   @return number - unique identifier for the new xmlNode
 324:   
 325:   The use of use strict arg makes sure there are no parameters.
 326: */
 327: ::method getId class
 328:   use strict arg
 329:   if instances~dataType('U') then instances = 0
 330:   instances += 1
 331: return instances
 332: /**
 333:   The unique node identification
 334: */
 335: ::attribute id private
 336: /**
 337:   A NamedNodeMap representing the attributes in an elementNode.
 338: */  
 339: ::attribute attributes get
 340: ::attribute attributes set
 341: /**
 342:   The absolute base URI of this node or null if the implementation was not able to obtain an absolute URI. 
 343: */
 344: ::attribute baseURI get
 345: ::attribute baseURI set
 346: /**
 347:   A nodeList containing the childNodes of a node. If there are no children, this is a NodeList containing no
 348:   nodes.
 349: */
 350: ::attribute childNodes get
 351: ::attribute childNodes set
 352: /**
 353:   The local part of the qualified name of this node.
 354:   
 355:   For nodes of any type other than ELEMENT_NODE and ATTRIBUTE_NODE and nodes created with a DOM Level 1 method, such as
 356:   xmlDocument~createElement, this is always .nil.
 357: */
 358: ::attribute localName get
 359: ::attribute localName set
 360: /**
 361:   The namespace URI of this node, or null if it is unspecified. This is not a computed value that is the result of a
 362:   namespace lookup based on an examination of the namespace declarations in scope. It is merely the namespace URI given
 363:   at creation time.
 364:   
 365:   For nodes of any type other than ELEMENT_NODE and ATTRIBUTE_NODE and nodes created with a DOM Level 1 method, such as
 366:   xmlDocument~createElement, this is always .nil.
 367: */
 368: ::attribute namespaceURI get
 369: ::attribute namespaceURI set
 370: /**
 371: 
 372: */
 373: ::attribute nextSibling 
 374: /**
 375:   The following nodeName values are valid for a particular type of node:
 376:   
 377:   - Attr - xmlAttr~name (i.e. the name part of the name-value attribute pair).
 
 378:   - CDATASection - literal "#cdata-section".
 
 379:   - Comment - literal "#comment".
 
 380:   - Document - literal "#document".
 
 381:   - DocumentFragment - literal "#document-fragment".
 
 382:   - DocumentType - xmlDocumentType~name.
 
 383:   - Element - xmlElement~tagName.
 
 384:   - Entity - xmlEntity name (e.g. ?????).
 
 385:   - EntityReference - name of entity referenced (e.g. ?????).
 
 386:   - Notation - notation name (e.g. ?????).
 
 387:   - ProcessingInstruction - xmlProcessingInstruction~target.
 
 388:   - Text - literal "#text".
 
 389:   
 390: */
 391: ::attribute nodeName get 
 392: ::attribute nodeName set
 393: /**
 394:   An integer indicating which type of node this is. See above.
 395: */
 396: ::attribute nodeType get
 397: ::attribute nodeType set 
 398: /**
 399:   The following nodeName values are valid for a particular type of node:
 400:   
 401:   - Attr - xmlAttr~value (i.e. the value part of the name-value attribute pair).
 
 402:   - CDATASection -  xmlCharacterData~data (i.e. the content of the CDATA Section).
 
 403:   - Comment - xmlCharacterData.data (i.e. the content of the comment).
 
 404:   - Document - .nil
 
 405:   - DocumentFragment - .nil
 
 406:   - DocumentType - .nil
 
 407:   - Element - .nil
 
 408:   - Entity - .nil
  
 409:   - EntityReference - .nil
 
 410:   - Notation - .nil
 
 411:   - ProcessingInstruction - xmlProcessingInstruction~data
 
 412:   - Text - xmlCharacter~data (i.e. the content of the text node).
 
 413:   
 414: */
 415: ::attribute nodeValue get 
 416: ::attribute nodeValue set
 417: /**
 418:   The xmlDocument object associated with this node. This is also the xmlDocument object used to create new nodes. When
 419:   this node is a xmlDocument or a xmlDocumentType which is not used with any xmlDocument yet, this is 
.nil.
 420: */
 421: ::attribute ownerDocument get
 422: ::attribute ownerDocument set
 423: /**
 424:   The parent of this node. All nodes, except xmlAttr, xmlDocument, xmlDocumentFragment, xmlEntity, and xmlNotation may
 425:   have a parent. However, if a node has just been created and not yet added to the tree, or if it has been removed from
 426:   the tree, this is 
.nil. 
 427: */
 428: ::attribute parentNode get 
 429: ::attribute parentNode set
 430: /**
 431:   The namespace prefix of this node, or null if it is unspecified. When it is defined to be 
.nil, setting it has
 432:   no effect, including if the node is read-only. 
 433:   
 434:   Note that setting this attribute, when permitted, changes the nodeName attribute, which holds the qualified name, as
 435:   well as the tagName and name attributes of the xmlElement and xmlAttr interfaces, when applicable.
 436:   
 437:   Setting the prefix to null makes it unspecified, setting it to an empty string is implementation dependent. Note also
 438:   that changing the prefix of an attribute that is known to have a default value, does not make a new attribute with the
 439:   default value and the original prefix appear, since the namespaceURI and localName do not change.
 440:   
 441:   For nodes of any type other than ELEMENT_NODE and ATTRIBUTE_NODE and nodes created with a DOM Level 1 method, such as
 442:   createElement from the xmlDocument interface, this is always 
.nil.
 443: */
 444: ::attribute prefix get 
 445: ::attribute prefix set 
 446: /**
 447: 
 448: */
 449: ::attribute previousSibling
 450: /**
 451:   This attribute returns the text content of this node and its descendants. When it is defined to be .nil, setting it
 452:   has no effect. On setting, any possible children this node may have are removed and, if it the new string is not empty
 453:   or null, replaced by a single xmlText node containing the string this attribute is set to. 
 454: */
 455: ::method textContent
 456:   raise syntax 93.960
 457: exit
 458: ::attribute textContent set
 459: /**
 460:   Method to initially set read-only attributes
 461:   @param attrName - the name of the Attribute.
 462:   @param attrValue - the value of the attribute.
 463:   @raises syntax 93.900 - Attribute value cannot be set twice
 464:   
 465:   If the attribute has been set already a syntx error will be raised
 466: */
 467: ::method setReadOnly
 468: --trace i
 469:   use strict arg attrName,attrValue
 470:   if self~send(attrName)<>attrName~upper
 471:     then raise syntax 93.900 array ("Attribute:" attrName "is read only, once set")
 472:     else self~send(attrName'=',attrValue)
 473: return
 474: /**
 475:   The instance constructor
 476: */
 477: ::method init
 478:   self~id = self~class~getId
 479:   self~attributes = .nil
 480:   self~baseURI = .nil
 481:   self~childNodes = .xmlNodeList~new(.array~new)
 482:   self~localName = .nil
 483:   self~namespaceURI = .nil
 484:   self~nodeName = ''
 485:   self~nodeValue = ''
 486:   self~nodeType = .nil
 487:   self~ownerDocument = .nil
 488:   self~parentNode = .nil
 489:   self~prefix = .nil
 490: return
 491: /**
 492:   Adds the node 
child to the end of the list of children of this node. If the 
child is already in the
 493:   tree, it is first removed.
 494:   @param child - the node to be appended. 
 495:   @return node - the node appended
 496:   
 497:   If 
child is a xmlDocumentFragment object, the entire contents of the document fragment are moved into the child
 498:   list of this node.
 499: */
 500: ::method appendChild
 501:   use strict arg child
 502:   appended = .nil
 503:   if (child<>.nil) then do
 504:     child~parentNode = self
 505:     self~childNodes~append(child)
 506:     appended = child
 507:   end
 508: return appended
 509: /**
 510:   @return nodes - A xmlNodeList that contains all the children of this node. 
 511:   
 512:   If there are no children, then this is a xmlNodeList containing no nodes.
 513: */
 514: ::method children
 515:   use strict arg 
 516: return self~childNodes
 517: /**
 518:   Returns a duplicate of this node, i.e., serves as a generic copy constructor for nodes. The duplicate node has no
 519:   parent (parentNode is 
.nil) and no user data. User data associated to the imported node is not carried over.
 520:   However, if any UserDataHandlers has been specified along with the associated data these handlers will be called with
 521:   the appropriate parameters before this method returns.
 522:   @param deep=.false - optional 
.true or 
.false (= default)
 523:   @return node - the duplicated node
 524: 
 525:   If 
 deep is 
.true, recursively clone the subtree under the specified node; if 
.false, clone only
 526:   the node itself (and its attributes, if it is an xmlElement).
 527:   Cloning an xmlElement copies all attributes and their values, including those generated by the XML processor to
 528:   represent defaulted attributes, but this method does not copy any children it contains unless it is a 
deep
 529:   clone. This includes text contained in the xmlElement since the text is contained in a child xmlText node. 
 530:   
 531:   Cloning an xmlAttr directly, as opposed to be cloned as part of an xmlElement cloning operation, returns a specified
 532:   attribute (specified is true). Cloning an xmlAttr always clones its children, since they represent its value, no
 533:   matter whether this is a 
deep clone or not. 
 534:   
 535:   Cloning an xmlEntityReference automatically constructs its subtree if a corresponding xmlEntity is available, no
 536:   matter whether this is a 
deep clone or not.
 537:   
 538:   Cloning any other type of node simply returns a copy of this node.
 539:   
 540:   Note that cloning an immutable subtree results in a mutable copy, but the children of an xmlEntityReference clone are
 541:   readonly. In addition, clones of unspecified xmlAttr nodes are specified. And, cloning xmlDocument, xmlDocumentType,
 542:   xmlEntity, and xmlNotation nodes is implementation dependent.
 543: */
 544: ::method cloneNode
 545:   use strict arg deep=.false
 546:   clone = self~copy
 547:   clone~parentNode = .nil
 548:   if deep = .true then do
 549:      raise syntax 93.963
 550:   end
 551: return clone
 552: /**
 553:   Compares the reference node, i.e. the node on which this method is being called, with a node, i.e. the one passed as a
 554:   parameter, with regard to their position in the document and according to the document order.
 555:   @param other - The node to compare with 
 556:   @return number - Position relatively to the reference node 
 557: */
 558: ::method compareDocumentPosition
 559:   use strict arg other
 560:   raise syntax 93.963
 561: exit
 562: /**
 563:   @return child - The first child of this node
 564: 
 565:   If there is no such node, this returns 
.nil
 566: */
 567: ::method firstChild
 568:   use strict arg
 569:   child = .nil
 570:   if (self~childNodes~length>0) then child = self~Childnodes~item(0)
 571: return child
 572: /**
 573:   @param feature - The name of the feature requested 
 574:   @param version - The version number of the feature to test 
 575:   @return domObject - An object which implements the specialized APIs or 
.nil
 576:    
 577:   This method returns a specialized object which implements the specialized APIs of the specified feature and version,
 578:   as specified in DOM Features. The specialized object may also be obtained by using binding-specific casting methods
 579:   but is not necessarily expected to. 
 580:   
 581:   This method also allows the implementation to provide specialized objects which do not support the xmlNode interface. 
 582: */
 583: ::method getFeature
 584:   use strict arg feature, version
 585:   raise syntax 93.963
 586: exit
 587: /**
 588:   Retrieves the object associated to a key on a this node. The object must first have been set to this node by calling
 589:   
setUserData with the same key.
 590:   @param key - The key the object is associated to.
 591:   @return userdata - the DOMUserData associated, or 
.nil if there was none
 592: */
 593: ::method getUserData
 594:   use strict arg key
 595:   raise syntax 93.963 
 596: exit
 597: /**
 598:   @return boolean - 
.true if this node has any attributes, 
.false otherwise
 599: */
 600: ::method hasAttributes
 601:   use strict arg
 602: return .false
 603: /**
 604:   @return boolean - 
.true if this node has any children, 
.false otherwise
 605: */
 606: ::method hasChildNodes
 607:   use strict arg
 608:   hasChildren = .false
 609:   if (self~children~items>0) then hasChildren = .true
 610: return hasChildren
 611: /**
 612:   Inserts the node 
child before the existing child node 
where.
 613:   @param child - the node to be inserted
 614:   @param where - the node before which the new node needs to be inserted.
 615:   @return node - the node being inserted
 616: 
 617:   If 
where is .nil, insert 
child at the end of the list of children.
 618:   
 619:   If 
child is a xmlDocumentFragment object, all of its children are inserted, in the same order, before
 620:   
where. 
 621:   
 622:   If the 
child is already in the tree, it is first removed.
 623:   
 624:   Note: Inserting a node before itself is implementation dependent. 
 625: */
 626: ::method insertBefore
 627:   use strict arg child, where
 628:   if (where==.nil) then do
 629:      self~childNodes~append(child)
 630:   end
 631:   -- find the where node
 632:   else do
 633:     newList = .xmlNodeList~new
 634:     do i=0 to self~childNodes~length-1
 635:      if self~childNodes~item(i) == where then newList~append(child)
 636:      newList~append(self~childNodes~item(i))
 637:     end
 638:     self~childNodes = newList
 639:   end
 640:   child~parentNode = self
 641: return child
 642: /**
 643:   This method checks if the specified 
namespaceURI is the default namespace or not.
 644:   @param uri - The 
namespaceURI to look for
 645:   @return boolean - 
.true if default, 
.false otherwise
 646: */
 647: ::method isDefaultNamespace
 648:   use strict arg uri
 649:   raise syntax 93.963
 650: exit  
 651: /**
 652:   Tests whether two nodes are equal.
 653:   @param other - The node to compare equality with
 654:   @return boolean - 
.true if equal, 
.false otherwise
 655: 
 656:   
 657:   This method tests for equality of nodes, not sameness (i.e., whether the two nodes are references to the same object)
 658:   which can be tested with xmlNode~isSameNode. All nodes that are the same will also be equal, though the reverse may
 659:   not be true.
 660:   
 661:   Two nodes are equal if and only if the following conditions are satisfied: 
 662:   
 663:   - The two nodes are of the same type.
 
 664:   - The following string attributes are equal: nodeName, localName, namespaceURI, prefix, nodeValue. This is: they are
 665:   both null, or they have the same length and are character for character identical.
 
 666:   - The attributes xmlNamedNodeMaps are equal. This is: they are both null, or they have the same length and for each
 667:   node that exists in one map there is a node that exists in the other map and is equal, although not necessarily at the
 668:   same index.
 - 
 669:   
 - The childNodes xmlNodeLists are equal. This is: they are both null, or they have the same length and contain equal
 670:   nodes at the same index. 
 671:   
Note that normalization can affect equality; to avoid this, nodes should be normalized before being compared. 
 672:   
 673:   For two xmlDocumentType nodes to be equal, the following conditions must also be satisfied: 
 674:   
 675:   - The following string attributes are equal: publicId, systemId, internalSubset.
 
 676:   - The entities xmlNamedNodeMaps are equal.
 
 677:   - The notations NamedNodeMaps are equal.
 
 678:   
 679:   On the other hand, the following do not affect equality: the ownerDocument, baseURI, and parentNode attributes, the
 680:   specified attribute for xmlAttr nodes, the schemaTypeInfo attribute for xmlAttr and xmlElement nodes, the
 681:   xmlText~isElementContentWhitespace attribute for xmlText nodes, as well as any user data or event listeners registered
 682:   on the nodes. 
 683: */
 684: ::method isEqualNode
 685:   use strict arg other
 686:   raise syntax 93.963
 687: exit
 688: /**
 689:   Tests whether this node is the same node as the given one.
 690:   @param other - The node to test against.
 691:   @return boolean - 
.true if the nodes are the same, 
.false otherwise. 
 692: 
 693:   This method provides a way to determine whether two xmlNode references returned by the implementation reference the
 694:   same object. When two xmlNode references are references to the same object, even if through a proxy, the references
 695:   may be used completely interchangeably, such that all attributes have the same values and calling the same DOM method
 696:   on either reference always has exactly the same effect.
 697: */
 698: ::method isSameNode
 699:   use strict arg other
 700:   raise syntax 93.963
 701: exit
 702: /**
 703:   Tests whether the DOM implementation implements a specific feature and that feature is supported by this node, as
 704:   specified in DOM Features. 
 705:   @param feature - The name of the feature to test. 
 706:   @param version - This is the version number of the feature to test. 
 707:   @return boolean - 
.true if supported on this node, 
.false otherwise.
 708: */  
 709: ::method isSupported
 710:   use strict arg feature, version
 711: return .false
 712: /**
 713:   @return aNode - The last child of this node. 
 714:   
 715:   If there is no such node, this returns 
.nil.
 716: */
 717: ::method lastChild
 718:   use strict arg
 719:   child = .nil
 720:   if (self~children~items>0) then child = self~children[self~children~items]
 721: return child
 722: /**
 723:   Look up the 
namespaceURI associated to the given prefix, starting from this node.
 724:   
 725:   See Namespace URI Lookup for details on the algorithm used by this method.
 726:   @param prefix - The prefix to look for. 
 727:   @return aString - The associated 
namespaceURI or 
.nil if none is found.
 728:   
 729:   If 
prefix is null, the method will return the default 
namespaceURI if any.
 730: */
 731: ::method lookupNamespaceURI
 732:   use strict arg prefix
 733:   raise syntax 93.963
 734: exit
 735: /**
 736:   Look up the prefix associated to the given 
namespaceURI, starting from this node. 
 737:   @param uri - A string specifying the 
namespaceURI to look for
 738:   @return aString - An associated namespace prefix or 
.nil if none is found
 739:   
 740:   The default namespace declarations are ignored by this method. See Namespace Prefix Lookup for details on the
 741:   algorithm used by this method. 
 742:   
 743:   If more than one prefix are associated to the namespace prefix, the returned namespace prefix is implementation
 744:   dependent.
 745: */
 746: ::method lookupPrefix
 747:   use strict arg uri
 748:   raise syntax 93.963 
 749: exit
 750: /**
 751:   Finds the next sibling.
 752:   @return aNode - The node immediately following this node. 
 753:   
 754:   If there is no such node, this returns 
.nil.
 755: */
 756: /*::method nextSibling
 757:   use strict arg
 758:   sibling = .nil
 759:   if (self~parentNode<>.nil) then do
 760:     siblings = self~parentNode~childNodes
 761:     do label next i=1 to siblings~items
 762:       if (siblings[i]==self) then do
 763:         if (i
 779:   If the parameter "normalize-characters" of the DOMConfiguration object attached to the xmlNode~ownerDocument is
 780:   .true, this method will also fully normalize the characters of the xmlText nodes.
 781:   
 782:   Note: In cases where the document contains CDATASections, the normalize operation alone may not be sufficient, since
 783:   XPointers do not differentiate between xmlText nodes and xmlCDATASection nodes.
 784: */
 785: ::method normalize
 786:   use strict arg
 787:   raise syntax 93.963
 788: exit
 789: /**
 790:   Finds the preceding node.
 791:   @return aNode - The node immediately preceding this node. 
 792:   
 793:   If there is no such node, this returns .nil
 794: */
 795: /**
 796: ::method previousSibling
 797:   use strict arg
 798:   sibling = .nil
 799:   if (self~parentNode<>.nil) then do
 800:     siblings = self~parentNode~childNodes
 801:     do labl prev i=1 to siblings~items
 802:       if (siblings[i]==self) then do
 803:         if (i>1) then do
 804:           sibling = siblings[i-1]
 805:           leave prev
 806:         end
 807:       end
 808:     end
 809:   end
 810: return sibling
 811: */
 812: /**
 813:   Removes the child node indicated by aNode from the list of children, and returns it.
 814:   @param child - The node being removed.
 815:   @return aNode - The node removed.
 816: */
 817: ::method removeChild
 818:   use strict arg child
 819:   removed = .nil
 820:   if (child<>.nil) then do
 821:     -- find the reference node
 822:     do i=1 to self~children~items
 823:       if (children[i]==child) then leave
 824:     end
 825:     removed = self~children~remove(i)
 826:     removed~parentNode = .nil
 827:   end
 828: return removed
 829: /**
 830:   Replaces the child node old with new in the list of children, and returns the old child node.
 831:   @param new - The new node to put in the child list.
 832:   @param old - The node being replaced in the list.
 833:   @return aNode - The node replaced.
 834:   
 835:   If new is a xmlDocumentFragment object, old is replaced by all of the
 836:   xmlDocumentFragment children, which are inserted in the same order. If the new 
 837:   is already in the tree, it is first removed.
 838:   
 839:   Note: Replacing a node with itself is implementation dependent. 
 840: */
 841: ::method replaceChild
 842:   use strict arg new, old
 843:   replaced = .nil
 844:   if (old<>.nil) then do
 845:   -- find the reference node
 846:     do i=1 to self~children~items
 847:        if (self~children[i]==old) then leave
 848:     end
 849:     replaced = self~children[i]
 850:     self~children[i] = new
 851:     self~children[i]~parentNode = self
 852:     replaced~parentNode = .nil
 853:   end
 854: return replaced
 855: /**
 856:   Associate an object to a key on this node. The object can later be retrieved from this node by invoking the
 857:   getUserData method with the same key.
 858:   @param key - The key to associate the object to.
 859:   @param data - A DOMUserData object to associate to the key, or null to remove any existing association to that key.
 860:   @param handler - An UserDataHandler, a handler to associate to that key, or null.
 861:   @return userData - The DOMUserData previously associated to the given key on this node, or null if there was none.
 862: */
 863: ::method setUserData
 864:   use strict arg key, data, handler
 865:   raise syntax 93.963 
 866: exit
 867: /**
 868:   Convenience method to walk thru a (sub)nodes tree
 869:   @param nodes - The sibling xmlNodeList to start the walk.
 870:   @param name - The name of the tag being searched for.
 871:   @param nl - The xmlNodeList containing the selected result nodes.
 872: */
 873: ::method treeWalk private
 874:   use strict arg nodes, name, nl
 875:   do n=0 to nodes~length-1
 876:     if name<>'*' then do
 877:       if nodes~item(n)~nodeName==name then nl~append(nodes~item(n))
 878:     end
 879:     else do
 880:       nl~append(nodes~item(n))
 881:     end
 882:     if nodes~item(n)~childNodes~length>0 then do
 883:       self~treewalk(nodes~item(n)~childNodes, name, nl)
 884:     end
 885:   end
 886: return
 887: /* :end */
 888: 
 889: /* CLASS: xmlNamedNodeMap */
 890: /**
 891:   Objects implementing the xmlNamedNodeMap interface are used to represent collections of nodes that can be accessed by
 892:   name. Note that xmlNamedNodeMap does not inherit from NodeList; NamedNodeMaps are not maintained in any particular
 893:   order. Objects contained in an object implementing xmlNamedNodeMap may also be accessed by an ordinal index, but this
 894:   is simply to allow convenient enumeration of the contents of a xmlNamedNodeMap, and does not imply that the DOM
 895:   specifies an order to these xmlNodes. xmlNamedNodeMap objects in the DOM are live. 
 896: */
 897: ::class xmlNamedNodeMap public 
 898: /**
 899:   A private array with directory entries, that have a (possibly qualified) name as index and xmlNodes as items.
 900: */
 901: ::attribute namedMap private
 902: /**
 903:   xmlNamedNodeMap instance constructor.
 904: */
 905: ::method init
 906:   self~namedMap = .directory~new
 907:   self~init:super
 908: exit
 909: /**
 910:   The number of xmlNodes in this map. 
 911:   @return - The number of nodes in the xmlNamedNodeMap.
 912: */
 913: ::method length 
 914: return self~namedMap~items
 915: /**
 916:   Retrieves a node specified by name.
 917:   @param name - The nodeName of a node to retrieve.
 918:   @return node - The xmlNode with the specified name, or .nil.
 919: */ 
 920: ::method getNamedItem
 921:   use strict arg name
 922:   node = .nil
 923:   if name~isA(.string) then do
 924:     node = self~namedMap[name]
 925:   end
 926: return node
 927: /**
 928:   Retrieves a node specified by local name and namespace URI.
 929:   @param namespaceURI - The namespace URI of the node to retrieve.
 930:   @param localName - The local name of the node to retrieve.
 931:   @return node - A xmlNode(of any type) with the specified local name and namespace URI, or null.
 932:   
 933:   Per [XML Namespaces], applications must use the value .nil, as the namespaceURI parameter for methods if they
 934:   wish to have no namespace.
 935: */
 936: ::method getNamedItemNS
 937:   use strict arg namespaceURI, localName
 938:   node = .nil
 939:   if (localName)~isA(.string) then do 
 940:     node = self~namedMap[localName]
 941:     if namespaceURI<>.nil then do
 942:       if node~namespaceURI<>namespaceURI then node = .nil
 943:     end
 944:   end
 945: return node
 946: /**
 947:   Returns the indexth item in the map. If index is greater than or equal to the number of nodes in this map, this
 948:   returns .nil.
 949:   @param index - Index into this map.
 950:   @return node - The node at the indexth position in the map, or .nil if not a valid index.
 951: */
 952: ::method item
 953:   use strict arg index
 954:   node = .nil 
 955:   if index>=0 then do  
 956:     node = self~namedMap~allItems[index+1]
 957:   end  
 958: return node
 959: /**
 960:   Removes a node specified by name. 
 961:   @param name - The nodeName of the node to remove.
 962:   @return node - The node removed from this map if a node with such a name exists.
 963:   @raises user domException - NOT_FOUND_ERR 
 964:   
 965:   When this map contains the attributes attached to an element, if the removed attribute is known to have a default
 966:   value, an attribute immediately appears containing the default value as well as the corresponding namespace URI,
 967:   local name, and prefix when applicable.
 968:   
 969:   This ooRexx implementation does not process a DTD, thus has no way to determine if a default value has to be provided.
 970:   The node is only removed, no additional checks for default value are made.
 971: */
 972: ::method removeNamedItem
 973:   use strict arg name
 974:   node = .nil
 975:   if name~isA(.string) then do
 976:     node = self~namedMap~remove(name)
 977:   end
 978:   if node==.nil then raise user domException description(.domException~not_found_err)
 979: return node
 980: /**
 981:   Removes a node specified by local name and namespace URI. A removed attribute may be known to have a default value
 982:   when this map contains the attributes attached to an element, as returned by the attributes attribute of the xmlNode
 983:   interface. If so, an attribute immediately appears containing the default value as well as the corresponding
 984:   namespace URI, local name, and prefix when applicable.
 985:   @param namespaceURI=.nil - The namespace URI of the node to remove.
 986:   @param localName - The local name of the node to remove.
 987:   @return node - The node removed from this map if a node with such a name exists.
 988:   @raises user domException - NOT_FOUND_ERR 
 989:   
 990:   Per [XML Namespaces], applications must use the value .nil as the namespaceURI parameter for methods if they
 991:   wish to have no namespace.
 992:   @see #removeNamedItem for behaviour concerning default values. 
 993: */
 994: ::method removeNamedItemNS
 995:   use strict arg namespaceURI=.nil, localName
 996:   node = .nil
 997:   if (localName)~isA(.string) then do
 998:     if node~namespaceURI==namespaceURI 
 999:       then node = self~namedMap~remove(localName)
1000:       else node = .nil
1001:   end
1002: return node
1003: /**
1004:   Adds a xmlNode using its nodeName attribute. If a node with that name is already present in this map, it is
1005:   replaced by the new one. Replacing a node by itself has no effect.
1006:   @param arg - A xmlNode to store in this map, accessible using its nodeName attribute.
1007:   @return node - The replaced xmlNode or .nil if no replacement.
1008:   @raises user domException - WRONG_DOCUMENT_ERR
1009:   @raises user domException - INUSE_ATTRIBUTE_ERR
1010: */  
1011: ::method setNamedItem
1012:   use strict arg arg
1013:   --if arg~ownerDocument<>self~ownerDocument
1014:   --  then raise user domException description (.domException~wrong_document_err)
1015:   if arg~nodeType==.xmlNode~attributeNode then do
1016:     if arg~ownerElement<>.nil 
1017:       then raise user domException description (.domException~inuse_attribute_err)
1018:   end
1019:   node = .nil
1020:   if arg~isA(.xmlNode) then do
1021:     name = arg~nodeName
1022:     node = self~namedMap[name]
1023:     self~namedMap[name] = arg
1024:   end
1025: return node
1026: /**
1027:   Adds a node using its namespaceURI and localName. If a node with that namespace URI and that local name is already
1028:   present in this map, it is replaced by the new one. Replacing a node by itself has no effect.
1029:   @param arg - A node to add to the map, subsequently accessible via namespaceURI and localName. 
1030:   @return node - The replaced xmlNode or .nil if no replacement.
1031:   @raises user domException - WRONG_DOCUMENT_ERR
1032:   @raises user domException - INUSE_ATTRIBUTE_ERR
1033: */
1034: ::method setNamedItemNS
1035:   use strict arg arg
1036:   if arg~ownerDocument<>self~ownerDocument
1037:     then raise user domException description (.domException~wrong_document_err)
1038:   if arg~nodeType==.attributeElement then do
1039:     if arg~ownerElement<>.nil 
1040:       then raise user domException description (.domException~inuse_attribute_err)
1041:   end
1042:   node = .nil
1043:   if arg~isA(.xmlNode) then do
1044:     name = arg~localName 
1045:     node = self~namedMap[name]
1046:     -- the following replaces also a node from a different namespace
1047:     -- probably need a directory with name indexes and items of a directory with namespace indexes and node items
1048:     if node~namespaceURI<>arg~namespaceURI
1049:       then node = .nil
1050:       else self~namedMap[name] = arg
1051:   end
1052: return node
1053: /**
1054:   Provides a xmlNamedNodeMap as a native ooRexx directory
1055:   @return directory - A native ooRexx directory representing the NamedNodeMap.
1056: */
1057: ::method toOorexxDirectory
1058: return self~namedMap
1059: /**
1060:   Sets a NamedNodeMap from a native ooRexx directory
1061:   @param nodeDirectory - The native ooRexx directory to replace an existing xmlNamedNodeMap.
1062:   @raises syntax 93.914 - Named item is not a proper xmlNode 
1063: */
1064: ::method fromOorexxDirectory
1065:   use strict arg nodeDirectory
1066:   s = nodeDirectory~supplier
1067:   do while s~available
1068:     if \s~item~isA(.xmlNode) then do
1069:       raise syntax 93.914 array (nodeDirectory, .xmlNode)
1070:     end
1071:     s~next
1072:   end
1073:   self~namedMap = nodeDirectory
1074: return
1075: /* :end */
1076: 
1077: /* CLASS: xmlAttr */
1078: /**
1079:   The xmlAttr interface represents an attribute in an xmlElement object. Typically the allowable values for the
1080:   attribute are defined in a schema associated with the document.
1081: 
1082:   xmlAttr objects inherit the xmlNode interface, but since they are not actually child nodes of the element they
1083:   describe, the DOM does not consider them part of the document tree. Thus, the xmlNode attributes parentNode,
1084:   previousSibling, and nextSibling have a .nil value for xmlAttr objects. The DOM takes the view
1085:   that attributes are properties of elements rather than having a separate identity from the elements they are
1086:   associated with; this should make it more efficient to implement such features as default attributes associated with
1087:   all elements of a given type. Furthermore, xmlAttr nodes may not be immediate children of a xmlDocumentFragment.
1088:   However, they can be associated with xmlElement nodes contained within a xmlDocumentFragment. In short, users and
1089:   implementors of the DOM need to be aware that xmlAttr nodes have some things in common with other objects inheriting
1090:   the Node interface, but they also are quite distinct.
1091: 
1092:   The attribute's effective value is determined as follows: if this attribute has been explicitly assigned any value,
1093:   that value is the attribute's effective value; otherwise, if there is a declaration for this attribute, and that
1094:   declaration includes a default value, then that default value is the attribute's effective value; otherwise, the
1095:   attribute does not exist on this element in the structure model until it has been explicitly added. Note that the
1096:   xmlNode nodeValue attribute on the xmlAttr instance can also be used to retrieve the string version of the
1097:   attribute's value(s).
1098: 
1099:   If the attribute was not explicitly given a value in the instance document but has a default value provided by the
1100:   schema associated with the document, an attribute node will be created with specified set to false. Removing attribute
1101:   nodes for which a default value is defined in the schema generates a new attribute node with the default value and
1102:   specified set to false. If validation occurred while invoking the xmlDocument normalizeDocument, attribute
1103:   nodes with specified equals to false are recomputed according to the default attribute values provided by the schema.
1104:   If no default value is associate with this attribute in the schema, the attribute node is discarded. 
1105: 
1106:   In XML, where the value of an attribute can contain entity references, the child nodes of the xmlAttr node may be
1107:   either xmlText or xmlEntityReference nodes (when these are in use; see the description ofxml EntityReference for
1108:   discussion). 
1109: */
1110: 
1111: ::class xmlAttr public subclass xmlNode
1112: /**
1113:   Returns whether this attribute is known to be of type ID (i.e. to contain an identifier for its owner element) or not.
1114:   When it is and its value is unique, the ownerElement of this attribute can be retrieved using the  xmlDocument
1115:   getElementById method. The implementation could use several ways to determine if an attribute node is known to
1116:   contain an identifier:
1117:   
1118:   - If validation occurred using an XML Schema [XML Schema Part 1] while loading the document or while invoking the
1119:   xmlDocument normalizeDocument method, the post-schema-validation infoset contributions (PSVI contributions)
1120:   values are used to determine if this attribute is a schema-determined ID attribute using the schema-determined ID 
1121:   definition in [XPointer].
 
1122:   - If validation occurred using a DTD while loading the document or while invoking  the xmlDocument
1123:   normalizeDocument method, the infoset [type definition] value is used to determine if this attribute is a
1124:   DTD-determined ID attribute using the DTD-determined ID definition in [XPointer].
 
1125:   - From the use of the xmlElement setIdAttribute, setIdAttributeNS, or setIdAttributeNode, i.e.
1126:   it is an user-determined ID attribute;
 
1127:   - Using mechanisms that are outside the scope of this specification, it is then an externally-determined ID
1128:   attribute. This includes using schema languages different from XML schema and DTD.
  
1129: 
1130:   If validation occurred while invoking the xmlDocument normalizeDocument method, all user-determined ID
1131:   attributes are reset and all attribute nodes ID information are then reevaluated in accordance to the schema used. As
1132:   a consequence, if the xmlAttr schemaTypeInfo attribute contains an ID type, isId will always return
1133:   .true. 
1134: */
1135: ::attribute isId get
1136: ::attribute isId set
1137: /**
1138:   Returns the name of this attribute. If the xmlNode localName is different from .nil, this attribute is a
1139:   qualified name.
1140: */
1141: ::method name
1142: return self~nodeName
1143: /**
1144:   The xmlElement node this attribute is attached to or .nil if this attribute is not in use.
1145: */
1146: ::attribute ownerElement get
1147: ::attribute ownerElement set
1148: /**
1149:   The type information associated with this attribute. While the type information contained in this attribute is
1150:   guarantee to be correct after loading the document or invoking the xmlDocument normalizeDocument method,
1151:   schemaTypeInfo may not be reliable if the node was moved. 
1152: */
1153: ::attribute schemaTypeInfo get
1154: ::attribute schemaTypeInfo set
1155: /**
1156:   .true if this attribute was explicitly given a value in the instance document, false otherwise. If the
1157:   application changed the value of this attribute node (even if it ends up having the same value as the default value)
1158:   then it is set to .true. The implementation may handle attributes with default values from other schemas
1159:   similarly but applications should use the xmlDocument normalizeDocument method to guarantee this information is
1160:   up-to-date. 
1161: */
1162: ::attribute specified get
1163: ::attribute specified set
1164: /**
1165:   On retrieval, the value of the attribute is returned as a string. Character and general entity references are replaced
1166:   with their values. See also the method getAttribute on the xmlElement interface.
1167: 
1168:    On setting, this creates a xmlText node with the unparsed contents of the string, i.e. any characters that an XML
1169:    processor would recognize as markup are instead treated as literal text. See also the xmlElement setAttribute
1170:    method.
1171: */
1172: ::method value
1173: return self~nodeValue
1174: /**
1175:   xmlAttr instance creation method
1176: */
1177: ::method init
1178:   self~isId = .false
1179:   self~ownerElement = .nil
1180:   self~schemaTypeInfo = .nil  -- not supported/implemented
1181:   self~specified = .false
1182:   self~init:super
1183: return
1184: /* :end */
1185: 
1186: /* CLASS: xmlCharacterData */
1187: /**
1188:   The CharacterData interface extends xmlNode with a set of attributes and methods for accessing character data in the
1189:   DOM. For clarity this set is defined here rather than on each object that uses these attributes and methods. No DOM
1190:   objects correspond directly to CharacterData, though Text and others do inherit the interface from it. All offsets in
1191:   this interface start from 0.
1192: 
1193:   The following DOES NOT APPLY FOR this ooRexx xmlDOM implementation. Characters are ASCII 8-bit.
1194:   As explained in the DOMString interface, text strings in the DOM are represented in UTF-16, i.e. as a sequence of
1195:   16-bit units. In the following, the term 16-bit units is used whenever necessary to indicate that indexing on
1196:   CharacterData is done in 16-bit units. 
1197: */
1198: ::class xmlCharacterData public mixinclass xmlNode
1199: /**
1200:   The data contained in a xmlNode
1201: */
1202: ::method data 
1203: return self~nodeValue
1204: /**
1205: */
1206: ::method length 
1207: return self~data~length
1208: /**
1209:   xmlCharacterData instance constructor
1210:   @param data - The character data
1211: */
1212: ::method init
1213:   use strict arg data
1214:   self~init:super
1215:   if arg~isA(.string) 
1216:     then self~nodeValue = data
1217:     else raise user domException description (.domException~invalid_modification_err)
1218: exit
1219: /**
1220:   Append the string to the end of the character data. Upon success, data and length reflect the change.   
1221:   @param arg - The data to be appended
1222: */
1223: ::method appendData
1224:   use strict arg arg
1225:   if arg~isA(.string) 
1226:     then self~data ||= arg
1227:     else raise user domException description (.domException~invalid_modification_err)
1228: return
1229: /**
1230:   Remove a range of characters from the node. Upon success, data and length reflect the change.
1231:   @param offset - The index(base 0) where to start deleting data
1232:   @param count - The number of characters to delete
1233: */
1234: ::method deleteData
1235:   use strict arg offset, count
1236:   self~data = self~data~delStr(offset+1,count)
1237: return
1238: /**
1239:   Insert a string at the specified offset.
1240:   @param offset - The index where to start inserting data
1241:   @param string - The character data to insert
1242: */
1243: ::method insertData
1244:   use strict arg offset, string
1245:   if offset>self~data~length | count<0 
1246:     then raise user domException description (.domException~index_size_err)   
1247:   self~data = self~data~substr(1,offset) || string || self~data~substr(offset+1)
1248: return
1249: /**
1250:   Replace the characters starting at the specified offset with the specified string.
1251:   @param offset - The offset from which to start replacing.
1252:   @param count - The number of characters to replace. 
1253:   @param string - The string with which the range must be replaced.
1254: 
1255:   If the sum of offset and count exceeds length, then all data to the end of the data are replaced; (i.e., the effect is
1256:   the same as a remove method call with the same range, followed by an append method invocation).
1257:   */
1258: ::method replaceData
1259:   use strict arg offset, count, string
1260:   if offset<0 | offset>self~data~length | count<0 
1261:     then raise user domException description (.domException~index_size_err)
1262:   self~data = self~data~overlay(string,offset+1,count)
1263: return
1264: /**
1265:   Extracts a range of data from the node.
1266:   @param offset - The index where to start retrieving data
1267:   @param count - The number of characters to retrieve
1268:   @return string - The specified substring. If the sum of offset and count exceeds the length, then all characters to
1269:   the end of the data are returned.
1270: */
1271: ::method substringData
1272:   use strict arg offset, count
1273:   if offset<0 | offset>self~data~length | count<0
1274:     then raise user domException description (.domException~index_size_error)
1275: return self~data~substr(offset+1,count)
1276: /* :end */
1277: 
1278: /* CLASS: xmlComment */
1279: /**
1280:   This interface inherits from xmlCharacterData and represents the content of a comment, i.e., all the characters
1281:   between the starting ''. Note that this is the definition of a comment in XML, and, in practice,
1282:   HTML, although some HTML tools may implement the full SGML comment structure. 
1283: 
1284:   No lexical check is done on the content of a comment and it is therefore possible to have the character sequence "--"
1285:   (double-hyphen) in the content, which is illegal in a comment per section 2.5 of [XML 1.0]. The presence of this
1286:   character sequence must generate a fatal error during serialization. 
1287: */
1288: ::class xmlComment public subclass xmlNode inherit xmlCharacterData
1289: /**
1290:   commentNode instance constructor.
1291:   @param data - The string representing the XML comment
1292: */
1293: ::method init
1294:   use strict arg data
1295:   self~init:super(data)
1296: return
1297: /* :end */
1298: 
1299: /* CLASS: xmlText */
1300: /**
1301:   The XMLText interface inherits from XMLCharacterData and represents the textual content (termed character data in XML)
1302:   of an xmlElement or xmlAttr. If there is no markup inside an element's content, the text is contained in a single
1303:   object implementing the xmlText interface that is the only child of the element. If there is markup, it is parsed into
1304:   the information items (elements, comments, etc.) and xmlText nodes that form the list of children of the element.
1305: 
1306:   When a document is first made available via the DOM, there is only one xmlText node for each block of text. Users may
1307:   create adjacent xmlText nodes that represent the contents of a given element without any intervening markup, but
1308:   should be aware that there is no way to represent the separations between these nodes in XML or HTML, so they will not
1309:   (in general) persist between DOM editing sessions. The xmlNode normalize method merges any such adjacent
1310:   xmlText objects into a single node for each block of text.
1311: 
1312:   No lexical check is done on the content of a xmlText node and, depending on its position in the document, some
1313:   characters must be escaped during serialization using character references; e.g. the characters "<&" if the textual
1314:   content is part of an element or of an attribute, the character sequence "]]>" when part of an element, the quotation
1315:   mark character " or the apostrophe character ' when part of an attribute. 
1316: */
1317: ::class xmlText public subclass xmlNode inherit xmlCharacterData
1318: /**
1319:   Returns whether this text node contains element content whitespace, often abusively called "ignorable whitespace". The
1320:   text node is determined to contain whitespace in element content during the load of the document or if validation
1321:   occurs while using the xmlDocument normalizeDocument method.
1322: */
1323: ::attribute isElementContentWhitespace get
1324: ::attribute isElementContentWhitespace set private
1325: /**
1326:   Returns all text of xmlText nodes logically-adjacent text nodes to this node, concatenated in document order.
1327:   
1328:   For instance, in the example below wholeText on the xmlText node that contains "bar" returns "barfoo", and also
1329:   on the xmlText node that contains "foo" it returns "barfoo". 
1330: */
1331: ::method wholeText
1332:   siblings = self~parentNode~childNodes
1333:   wholeText = ''
1334:   do s=0 to siblings~length-1
1335:     wholeText = wholeText || s~data' '
1336:   end
1337: return wholeText~strip('T')
1338: /**
1339:   xmlText instance constructor
1340:   @param content - The text string representing the content
1341: */
1342: ::method init
1343:   use strict arg content
1344:   self~init:super(content)
1345:   if self~class==.xmlText
1346:     then do
1347:       self~nodeType = .xmlNode~textNode
1348:       self~nodeName = "#text"
1349:     end
1350:     else do
1351:       self~nodeType = .xmlNode~CDATASectionNode
1352:       self~nodeName = "#cdata-section"
1353:     end
1354:   --self~nodeValue = content
1355: return
1356:   
1357: /**
1358:   Replaces the text of the current node and all logically-adjacent text nodes with the specified text. All
1359:   logically-adjacent text nodes are removed including the current node unless it was the recipient of the replacement
1360:   text.
1361:   This method returns the node which received the replacement text. The returned node is: 
1362:   
1363:   - .nil, when the replacement text is the empty string;
 
1364:   - the current node, except when the current node is read-only;
 
1365:   - a new xmlText node of the same type (xmlText or xmlCDATASection) as the current node inserted at the location of
1366:   the replacement.
 
1367:   
1368:   @param content - The content of the replacing xmlText node.
1369:   @return text - The xmlText node created with the specified content.
1370:   
1371:   Assumption: Text and CDATASections are the only ones within Element nodes (and possibly within Attr nodes).
1372: */
1373: ::method replaceWholeText
1374:   use strict arg content
1375:   text = .nil
1376:   if content<>'' then do
1377:     text = self~class~new(content)
1378:     nodeList = .xmlNodeList~new(.array~of(text))
1379:     self~parentNode~childNodes = nodeList
1380:   end
1381: return text
1382: /**
1383:   Breaks this node into two nodes at the specified offset, keeping both in the tree as siblings. After being split, this
1384:   node will contain all the content up to the offset point. A new node of the same type, which contains all the content
1385:   at and after the offset point, is returned. If the original node had a parent node, the new node is inserted as the
1386:   next sibling of the original node. When the offset is equal to the length of this node, the new node has no data.
1387:   @param offset - The offset at which to split, starting from 0.
1388:   @return text - The new node, of the same type as this node.
1389:   @raises user domException - INDEX_SIZE_ERR
1390: */    
1391:  ::method splitText
1392:   use strict arg offset
1393:   if offset+1>self~data~length then do
1394:     raise user domException additional (.domException~index_size_err) description ("Offset" offset "is larger than length" self~data~length "of text")
1395:   end
1396:   text = self~class~new(self~data~substr(offset+1))
1397:   self~data = self~data~substr(1,offset)
1398:   siblings = .array~new
1399:   do c=0 to self~parentNode~childNodes-1
1400:     child = self~parentNode~childNodes~item(c)
1401:     siblings~append(child)
1402:     if child==self then do
1403:       siblings~append(text)
1404:     end
1405:   end
1406:   children = .xmlNodelist~new(siblings)
1407:   self~parentNode~childNodes = children
1408: return text
1409: /* :end */
1410: 
1411: /* CLASS: xmlCDATASection */
1412: /**
1413:   CDATA sections are used to escape blocks of text containing characters that would otherwise be regarded as markup.
1414:   The only delimiter that is recognized in a CDATA section is the "]]>" string that ends the CDATA section. CDATA
1415:   sections cannot be nested. Their primary purpose is for including material such as XML fragments, without needing to
1416:   escape all the delimiters.
1417: 
1418:   The xmlCharacterData data attribute holds the text that is contained by the CDATA section. Note that this may
1419:   contain characters that need to be escaped outside of CDATA sections and that, depending on the character encoding
1420:   ("charset") chosen for serialization, it may be impossible to write out some characters as part of a CDATA section.
1421: 
1422:   The CDATASection interface inherits from the xmlCharacterData interface through the xmlText interface. Adjacent
1423:   xmlCDATASection nodes are not merged by use of the normalize method of the xmlNode interface.
1424: 
1425:   No lexical check is done on the content of a CDATA section and it is therefore possible to have the character sequence
1426:   "]]>" in the content, which is illegal in a CDATA section per section 2.7 of [XML 1.0]. The presence of this character
1427:   sequence must generate a fatal error during serialization.
1428: 
1429:   Note: Because no markup is recognized within a xmlCDATASection, character numeric references cannot be used as an
1430:   escape mechanism when serializing. Therefore, action needs to be taken when serializing a CDATASection with a
1431:   character encoding where some of the contained characters cannot be represented. Failure to do so would not produce
1432:   well-formed XML.
1433:   
1434:   One potential solution in the serialization process is to end the CDATA section before the character, output the
1435:   character using a character reference or entity reference, and open a new CDATA section for any further characters in
1436:   the text node. Note, however, that some code conversion libraries at the time of writing do not return an error or
1437:   exception when a character is missing from the encoding, making the task of ensuring that data is not corrupted on
1438:   serialization more difficult.
1439: */  
1440: ::class xmlCDATASection public subclass xmlText
1441: /**
1442:   The CDATASection instance constructot
1443:   @param content - The unparsed string representing the contents of the CDATASection.
1444: */
1445: ::method init
1446:   use strict arg content
1447:   self~init:super(content)
1448: return
1449: /* :end */
1450: 
1451: /* CLASS: xmlPI */
1452: /**
1453:   The ProcessingInstruction interface represents a "processing instruction", used in XML as a way to keep
1454:   processor-specific information in the text of the document.
1455: 
1456:   No lexical check is done on the content of a processing instruction and it is therefore possible to have the character
1457:   sequence "?>" in the content, which is illegal a processing instruction per section 2.6 of [XML 1.0]. The presence of
1458:   this character sequence must generate a fatal error during serialization. 
1459: */
1460: ::class xmlPI public subclass xmlNode
1461: /**
1462:   The content of this processing instruction. This is from the first non white space character after the target to the
1463:   character immediately preceding the ?>.
1464: */
1465: ::method data 
1466: return self~nodeValue
1467: /**
1468:   The target of this processing instruction. XML defines this as being the first token following the markup that begins
1469:   the processing instruction. 
1470: */
1471: ::method target 
1472: return self~nodeName
1473: /**
1474:   The xmlProcessingInstruction instance constructor
1475:   @param target - The target for the processing instruction
1476:   @param data - The unparsed string representing the content of the processing instruction.
1477: */
1478: ::method init
1479:   use strict arg target, data
1480:   self~init:super
1481:   self~nodeType = .xmlNode~processingInstructionNode
1482:   self~nodeName = target
1483:   self~nodeValue = data
1484: return
1485: /* :end */
1486: 
1487: /* CLASS: xmlDocumentType */
1488: /**
1489:   Information about the notations and entities declared by a document (including the external subset if the parser uses
1490:   it and can provide the information) is available from a xmlDocumentType object. The xmlDocumentType for a document is
1491:   available from the xmlDocument object’s doctype attribute; if there is no DOCTYPE declaration for the document, the
1492:   document’s doctype attribute will be set to .nil instead of an instance of this interface.
1493: 
1494:   xmlDocumentType is a subclass (precisation) of xmlNode, and adds the following attributes:
1495:   
1496:   - entities - This is a xmlNamedNodeMap giving the definitions of external and internal entities. For entity names
1497:   defined more than once, only the first definition is provided (others are ignored as required by the XML
1498:   recommendation). This may be .nil if the information is not provided by the parser, or if no entities are
1499:   defined.
 
1500:   - internalSubset - A string giving the complete internal subset from the document. This does not include the
1501:   brackets which enclose the subset. If the document has no internal subset, this is .nil.
 
1502:   - name - The name of the root element as given in the DOCTYPE declaration, if present.
 
1503:   - notations - This is a xmlNamedNodeMap giving the definitions of notations. For notation names defined more than
1504:   once, only the first definition is provided (others are ignored as required by the XML recommendation). This may be
1505:   .nil if the information is not provided by the parser, or if no notations are defined.
 
1506:   - publicId - The public identifier for the external subset of the document type definition. This will be a string
1507:   or .nil.
 
1508:   - systemId - The system identifier for the external subset of the document type definition. This will be a URI as a
1509:   string, or .nil.
 
1510:   
1511: 
1512:   DOM Level 3 doesn't support editing DocumentType nodes. DocumentType nodes are read-only. 
1513: */
1514: ::class xmlDocumentType public subclass xmlNode
1515: /**
1516:   Entities is a xmlNamedNodeMap containing the general entities, both external and internal, declared in the DTD.
1517:   Parameter entities are not contained. Every node in this map also implements the Entity interface.
1518:   The DOM Level 2 does not support editing entities, therefore entities cannot be altered in any way.
1519: */
1520: ::attribute entities get
1521: ::attribute entities set
1522: /**
1523:   The internal subset as a string, or .nil if there is none. This does not contain the delimiting square
1524:   brackets.
1525:   NOTE, - The actual content returned depends on how much information is available to the implementation.
1526:   This may vary depending on various parameters, including the XML processor used to build the document.
1527: */
1528: ::attribute internalSubset get
1529: ::attribute internalSubset set
1530: /**
1531:   The name of DTD; i.e., the name immediately following the DOCTYPE keyword.
1532: */
1533: ::attribute name get
1534: ::attribute name set
1535: /**
1536:   Notations is xmlNamedNodeMap containing the notations declared in the DTD. Duplicates are discarded. Every node in
1537:   this map also implements the xmlNotation interface.
1538:   The DOM Level 2 does not support editing notations, therefore notations cannot be altered in any way.
1539: */
1540: ::attribute notations get
1541: ::attribute notations set
1542: /**
1543:   The public identifier of the external subset.
1544: */
1545: ::attribute publicId get
1546: ::attribute publicId set
1547: /**
1548:   The system identifier of the external subset. This may be an absolute URI or not.
1549: */
1550: ::attribute systemId get
1551: ::attribute systemId set
1552: /**
1553:   xmlDocumentType instance constructor.
1554:   @param name - The qualified name of the document (e.g. 'gpx'), is equal to the root tagName.
1555:   @param publicId - The public identifier of this document type (e.g. '-//W3C//DTD XHTML 1.0 Strict//EN').
1556:   @param systemId - The system identifier for the docType (e.g. 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd').
1557: */
1558: ::method init
1559:   use strict arg name, publicId, systemId
1560:   self~nodeType = 10
1561:   self~nodeName = name
1562:   self~publicId = publicId
1563:   self~systemId = systemId
1564:   self~entities = .NamedNodeMap~new
1565:   self~notations = .NamedNodeMap~new
1566:   self~internalSubset = .nil
1567: return
1568: /* :end */
1569: 
1570: /* CLASS: xmlElement */
1571: /**
1572:   The Element interface represents an element in an HTML or XML document. Elements may have attributes associated with
1573:   them; since the Element interface inherits from Node, the generic Node interface attribute attributes may be used to
1574:   retrieve the set of all attributes for an element. There are methods on the Element interface to retrieve either an
1575:   Attr object by name or an attribute value by name. In XML, where an attribute value may contain entity references, an
1576:   Attr object should be retrieved to examine the possibly fairly complex sub-tree representing the attribute value. On
1577:   the other hand, in HTML, where all attributes have simple string values, methods to directly access an attribute value
1578:   can safely be used as a convenience.
1579: 
1580:   Note: In DOM Level 2, the method normalize is inherited from the Node interface where it was moved.
1581: */
1582: ::class xmlElement public subclass xmlNode
1583: /**
1584:   Private method to walk the xmlNode tree and retrieve all elements with the specified tagName.
1585:   @param nodes - the xmlNodes to start with, i.e. the childNodes from the receiver node.
1586:   @param tag - The name odf the tag for the elements to be selected,'*' means all tags.
1587:   @param nodeList - A xmlNodeList with all the selected elements in the subtree with specified tagName. 
1588: */
1589: ::method selectElements private
1590:   use strict arg nodes, tag, nodeList
1591:   do n=0 to nodes~length-1
1592:     node = nodes~item(n)
1593:     if node~nodeType==.xmlNode~elementNode then do
1594:       if tag<>'*' then do
1595:         if node~tagName==tag then nodeList~append(node)
1596:       end
1597:       else do
1598:         nodeList~append(node)
1599:       end
1600:       if node~childNodes~length>0 then do
1601:         self~selectElements(node~childNodes, tag, nodeList)
1602:       end
1603:     end
1604:   end
1605: return
1606: /**
1607:   Private method to walk the xmlNode tree and retrieve all elements from a namespace with the specified local name.
1608:   @param nodes - the xmlNodes to start with, i.e. the childNodes from the receiver node.
1609:   @param namespaceURI - The namespace of the elements to be selected.
1610:   @param localName - The local name for the element to be selected.
1611:   @param nodeList - A xmlNodeList with all the elements in the subtree with specified tagName. 
1612: */
1613: ::method selectElementsNS private
1614:   use strict arg nodes, namespaceURI, localName, nodeList
1615:   do n=0 to nodes~items-1
1616:     node = nodes[n]
1617:     if node~nodeType==.xmlNode~elementNode then do
1618:       if localName<>'*' then do
1619:         if node~localName==localName then do
1620:           if namespaceURI<>'*' then do
1621:             if node~namespaceURI==namespacURI then nodeList~append(node)
1622:           end
1623:           else do
1624:             nodeList~append(node)
1625:           end
1626:         end
1627:         else do
1628:           nop
1629:         end
1630:       end
1631:       else do
1632:         if namespaceURI<>'*' then do
1633:           if node~namespaceURI==namespacURI then nodeList~append(node)
1634:         end
1635:         else do
1636:           nodeList~append(node)
1637:         end
1638:       end
1639:     end
1640:     if node~childNodes~items>0 then do
1641:       self~getElementNodesByTagNS(node~childNodes, namespaceURI, localName, nodeList)
1642:     end
1643:   end
1644: return
1645: /**
1646:   The type information associated with this element. 
1647: */
1648: ::method schemaTypeInfo
1649:   raise syntax 93.900 array (isUnderConstruction(.context~name))
1650: return
1651: /**
1652:   The name of the element. If Node localName is different from null, this attribute is a qualified name.
1653: */
1654: ::method tagName
1655: return self~nodeName
1656: /**
1657:   xmlElement instance constructor
1658:   @param tagName - The name of the xmlElement to be created.
1659:   
1660:   nodeValue, localName, prefix, namespaceURI and childNodes are set by the superclass xmlNode
1661: */
1662: ::method init
1663:   use strict arg tagName
1664:   self~init:super
1665:   self~nodeName = tagname
1666:   self~nodeType = .xmlNode~elementNode
1667:   self~attributes = .xmlNamedNodeMap~new
1668:   --self~nodeValue = .nil
1669:   --self~localName = .nil
1670:   --self~prefix = .nil
1671:   --self~namespaceURI = .nil
1672:   --self~childNodes = xmlNodeList~new
1673: return
1674: /**
1675:   Retrieves an attribute value by name.
1676:   @param name - The name of the attribute to retrieve.
1677:   @return string - The xmlAttr value or .nil if that attribute does not have a specified or default value.
1678: */
1679: ::method getAttribute
1680: use strict arg name
1681: nodeValue = .nil
1682: node = self~attributes~getNamedItem(name)
1683: if node<>.nil then nodeValue = node~nodeValue
1684: return nodeValue 
1685: /**
1686:   Retrieves an attribute value by local name and namespace URI.
1687:   @param namespaceURI=.nil - The namespace URI of the attribute to retrieve.
1688:   @param localName - The local name of the attribute to retrieve.
1689:   @return string - The xmlAttr value, or the empty string if that attribute does not have a specified or default value.
1690:   
1691:   Per [XML Namespaces], applications must use the value null as the namespaceURI parameter for methods if they wish to
1692:   have no namespace.
1693:   
1694:   Assumption: Attributes can not have a default namespace, thus need a prefix if they belong to a certain namespace.
1695:   Assumption: A namespace can have multiple prefixes.
1696: */
1697: ::method getAttributeNS
1698:   use strict arg namespaceURI=.nil, localName
1699:   nodeValue = .nil
1700:   if namespaceURI==.nil then do 
1701:     node = self~attributes~getNamedItem(localName)
1702:     if node<>.nil then nodeValue = node~nodeValue
1703:   end
1704:   else do
1705:     prefixes = self~ownerdocument~nameSpaces[namespaceURI]
1706:     found = .false
1707:     if prefixes<>.nil then do i=1 to prefix~words until found
1708:       prefix = prefixes~word(i)
1709:       node = self~attributes~getNamedItem(prefix":"localName)
1710:         if node<>.nil then do
1711:           nodeValue = node~nodeValue
1712:           found = .true
1713:       end
1714:     end
1715:   end
1716: return nodeValue
1717: /**
1718:   Retrieves an attribute node by name.
1719:   @param name - The nodeName of the attribute to retrieve
1720:   @return node - The xmlAttr node with the specified nodeName or .nil if there is no such attribute.
1721:   
1722:   To retrieve an attribute node by qualified name and namespace URI, use the getAttributeNodeNS method.
1723: */
1724: ::method getAttributeNode
1725: use strict arg name
1726: attrNode = self~attributes~getNamedItem(name)
1727: return attrNode
1728: /**
1729:   Retrieves an Attr node by local name and namespace URI.
1730:   @param namespaceURI=.nil - The namespace URI of the attribute to retrieve.
1731:   @param localName - The local name of the attribute to retrieve.
1732:   @return node - The xmlAttr node with the specified attribute local name and namespace URI or null if there is no such
1733:   attribute.
1734: 
1735:   Per [XML Namespaces], applications must use the value null as the namespaceURI parameter for methods if they wish to 
1736:   have no namespace.
1737: 
1738:   Assumption: Attributes can not have a default namespace, thus need a prefix if they belong to a certain namespace.
1739:   Assumption: A namespace can have multiple prefixes.
1740: */
1741: ::method getAttributeNodeNS
1742:   use strict arg namespaceURI=.nil, localName
1743:   if namespaceURI==.nil then do 
1744:     attrNode = self~attributes~getNamedItem(localName)
1745:   end
1746:   else do
1747:     prefixes = self~ownerdocument~nameSpaces[namespaceURI]
1748:     found = .false
1749:     if prefixes<>.nil then do i=1 to prefix~words until found
1750:       prefix = prefixes~word(i)
1751:       attrNode = self~attributes~getNamedItem(prefix":"localName)
1752:       if attrNode<>.nil then found = .true
1753:     end
1754:   end
1755: return attrNode
1756: /**
1757:   Returns a xmlNodeList of all descendant xmlElements with a given tag name, in document order.
1758:   @param tag - The name of the tag to match on. The special value "*" matches all tags.
1759:   @return nodeList - A list of matching xmlElement nodes.
1760: */
1761: ::method getElementsByTagName
1762:   use strict arg tag
1763:   nodeList = .xmlNodeList~new
1764:   self~selectElements(self~childNodes, tag, nodeList)
1765: return nodeList
1766: /**
1767:   Returns true when an attribute with a given name is specified on this element or has a default value, false otherwise.
1768:   @param name - The name of the attribute to look for.
1769:   @return boolean - .true if an attribute with the given name is specified on this element or has a default
1770:   value, .false otherwise.
1771: */  
1772: ::method hasAttribute
1773:   use strict arg name
1774: return self~attributes~getNamedItem(name)<>.nil
1775: /**
1776:   Returns true when an attribute with a given local name and namespace URI is specified on this element or has a default
1777:   value, false otherwise.
1778:   @param namespaceURI=.nil - The namespace URI of the attribute to look for.
1779:   @param localName - The local name of the attribute to look for.
1780:   @return boolean - .true if an attribute with the given local name and namespace URI is specified or has a
1781:   default value on this element, .false otherwise.
1782:    
1783:   Per [XML Namespaces], applications must use the value .nil as the namespaceURI parameter for methods if they
1784:   wish to have no namespace.
1785: 
1786:   Assumption: Attributes can not have a default namespace, thus need a prefix if they belong to a certain namespace.
1787:   Assumption: A namespace can have multiple prefixes.
1788:   */
1789: ::method hasAttributeNS
1790:   use strict arg namespaceURI=.nil, localName
1791:   boolean = .false
1792:   if namespaceURI==.nil then do
1793:     boolean = self~attributes~getNamedItem(name)<>.nil
1794:   end
1795:   prefixes = self~ownerDocument~nameSpaces[namespaceURI]
1796:   if prefixes<>.nil then do
1797:     do p=1 to prefixes~words until boolean==.true
1798:       prefix = prefixes~word(p)
1799:       boolean = self~attributes~getNamedItem(prefix':'localName)<>.nil
1800:     end
1801:   end
1802: return boolean
1803: /**
1804:   Removes an attribute by name. 
1805:   NOT supported here:
1806:   (If a default value for the removed attribute is defined in the DTD, a new attribute immediately appears with the
1807:   default value as well as the corresponding namespace URI, local name, and prefix when applicable. The implementation
1808:   may handle default values from other schemas similarly but applications should use Document.normalizeDocument() to
1809:   guarantee this information is up-to-date.)
1810:   @param name - The name of the attribute to remove.
1811: 
1812:   If no attribute with this name is found, this method has no effect.
1813:   To remove an attribute by local name and namespace URI, use the removeAttributeNS method.
1814: */
1815: ::method removeAttribute
1816: use strict arg name
1817: removed = self~attributes~removeNamedItem(name)
1818: return
1819: /**
1820:   Removes an attribute by local name and namespace URI.
1821:   NOT supported here:
1822:   (If a default value for the removed attribute is defined in the DTD, a new attribute immediately appears with the
1823:   default value as well as the corresponding namespace URI, local name, and prefix when applicable. The implementation
1824:   may handle default values from other schemas similarly but applications should use Document.normalizeDocument() to
1825:   guarantee this information is up-to-date.)
1826:   @param nameSpaceURI=.nil - The namespace URI of the attribute to remove.
1827:   @param localName - The local name of the attribute to remove.
1828: 
1829:   If no attribute with this local name and namespace URI is found, this method has no effect.
1830:  
1831:   Per [XML Namespaces], applications must use the value .nil as the namespaceURI parameter for methods if they
1832:   wish to have no namespace.
1833: */
1834: ::method removeAttributeNS
1835:   use strict arg nameSpaceURI=.nil, localName
1836:   removed = self~attributes~removeNamedItemNS(namespaceURI,localName)
1837: return 
1838: /**
1839:   Removes the specified attribute node. 
1840:   NOT supported here:
1841:   (If a default value for the removed Attr node is defined in the DTD, a new node immediately appears with the default
1842:   value as well as the corresponding namespace URI, local name, and prefix when applicable. The implementation may
1843:   handle default values from other schemas similarly but applications should use Document.normalizeDocument() to
1844:   guarantee this information is up-to-date.)
1845:   @param oldAttr - The reference to the xmlAttr to be removed.
1846:   @return attr - The removed attribute.
1847:   @raises user domException - NOT_FOUND_ERR perhaps
1848: */
1849: ::method removeAttributeNode
1850:   use strict arg oldAttr
1851:   removed = self~attributes~removeNamedItem(oldAttr~nodeName)
1852: return removed
1853: /**
1854:   Adds a new attribute. If an attribute with that name is already present in the element, its value is changed to be
1855:   that of the value parameter. This value is a simple string; it is not parsed as it is being set. So any markup (such
1856:   as syntax to be recognized as an entity reference) is treated as literal text, and needs to be appropriately escaped
1857:   by the implementation when it is written out. In order to assign an attribute value that contains entity references,
1858:   the user must create an xmlAttr node plus any xmlText and xmlEntityReference nodes, build the appropriate subtree, and
1859:   use setAttributeNode to assign it as the value of an attribute.
1860:   @param name - The name of the attribute to create or alter.
1861:   @param value - Value to set in string form.
1862:   @raises user domException - INVALID_CHARACTER_ERR
1863:   
1864:   To set an attribute with a qualified name and namespace URI, use the setAttributeNS method.
1865: */
1866: ::method setAttribute
1867:   use strict arg name, value
1868:   if name~verify(xmlValidName())>0 then do
1869:     raise user domException description (.domException~invalid_character_err)
1870:   end
1871:   node = self~attributes~getNamedItem(name)
1872:   if node<>.nil then do
1873:     node~nodeValue = value
1874:   end
1875:   else do
1876:     node = xmlAttr~new
1877:     node~nodeName = name
1878:     node~nodeValue = value
1879:     self~attributes~setNamedItem(node)
1880:   end
1881: return 
1882: /**
1883:   Adds a new attribute. If an attribute with the same local name and namespace URI is already present on the element,
1884:   its prefix is changed to be the prefix part of the qualifiedName, and its value is changed to be the value parameter.
1885:   This value is a simple string; it is not parsed as it is being set. So any markup (such as syntax to be recognized as
1886:   an entity reference) is treated as literal text, and needs to be appropriately escaped by the implementation when it
1887:   is written out. In order to assign an attribute value that contains entity references, the user must create an Attr 
1888:   node plus any Text and EntityReference nodes, build the appropriate subtree, and use setAttributeNodeNS or
1889:   setAttributeNode to assign it as the value of an attribute.
1890:   @param namespaceURI=.nil - The namespace URI of the attribute to create or alter.
1891:   @param qualifiedName - The qualified name of the attribute to create or alter.
1892:   @param value - The value to set in string form.
1893:   @raises user domException - INVALID_CHARACTER_ERR
1894:   @raises user domException - NAMESPACE_ERR
1895:   
1896:   Per [XML Namespaces], applications must use the value .nil as the namespaceURI parameter for methods if they
1897:   wish to have no namespace.
1898: */
1899: ::method setAttributeNS
1900:   use strict arg namespaceURI=.nil, qualifiedName, value
1901:   if qualifiedName~verify(xmlValidName())>0 then do
1902:     raise user domException description (.domException~invalid_character_err)
1903:   end
1904:   if qualifiedName~pos(':')>0 & namespaceURI==.nil then do
1905:     raise user domException description (.domException~namespace_err)
1906:   end
1907:   if qualifiedName~substr(1,3)~lower=="xml" & namespaceURI<>"http://www.w3.org/XML/1998/namespace" then do
1908:     raise user domException description (.domException~namespace_err)
1909:   end
1910:   if qualifiedName~substr(1,5)~lower=="xmlns" & namespaceURI<>"http://www.w3.org/2000/xmlns/" then do
1911:     raise user domException description (.domException~namespace_err)
1912:   end
1913:   if qualifiedName~substr(1,5)~lower<>"xmlns" & namespaceURI=="http://www.w3.org/2000/xmlns/" then do
1914:     raise user domException description (.domException~namespace_err)
1915:   end
1916:   localName = qualifiedName
1917:   if quailifedName~pos(':')>0 then parse var qualifiedName prefix ':'localName
1918:   node = self~attributes~getNamedItemNS(namespaceURI,localName)
1919:   if node<>.nil then do
1920:     node~nodeValue = value
1921:   end
1922:   else do
1923:     node = xmlAttr~new
1924:     node~nodeName = name
1925:     node~nodeValue = value
1926:     node~namespaceURI = namespaceURI
1927:     node~localName = localName
1928:     node~prefix = prefix
1929:     self~attributes~setNamedItemNS(node)
1930:   end
1931: return
1932: /**
1933:   Adds a new attribute node. If an attribute with that name (nodeName) is already present in the element, it is replaced
1934:   by the new one. Replacing an attribute node by itself has no effect.
1935:   @param newAttr - The xmlAttr node to add to the attribute list.
1936:   @return attr - If the newAttr attribute replaces an existing attribute, the replaced Attr node is returned, otherwise
1937:   .nil is returned.
1938:   @raises user domExcep[tion - WRONG_DOCUMENT_ERR
1939:   @raises user domException - INUSE_ATTRIBUTE_ERR
1940:   
1941:   To add a new attribute node with a qualified name and namespace URI, use the setAttributeNodeNS method.
1942: */
1943: ::method setAttributeNode
1944:   use strict arg newAttr
1945:   if newAttr~ownerDocument<>self~ownerDocument then do
1946:     raise user domException additional (.domException~wrong_document_err) description ("Attribute" newAttr~name "is owned by another document") 
1947:   end
1948:   if newAttr~ownerElement<>self then do 
1949:     raise user domException additional (.domException~inuse_attribute_err) description (newAttr~ownerElement)
1950:   end
1951:   node = self~attributes~setNamedItem(newAttr)
1952: return node
1953: /**
1954:   Adds a new attribute. If an attribute with that local name and that namespace URI is already present in the element,
1955:   it is replaced by the new one. Replacing an attribute node by itself has no effect.
1956:   @param newAttr - The xmlAttr node to add to the attribute list.
1957:   @return attr - If the newAttr attribute replaces an existing attribute, the replaced Attr node is returned, otherwise
1958:   .nil is returned.
1959:   @raises user domExcep[tion - WRONG_DOCUMENT_ERR
1960:   @raises user domException - INUSE_ATTRIBUTE_ERR
1961:   
1962:   Per [XML Namespaces], applications must use the value .nil as the namespaceURI parameter for methods if they
1963:   wish to have no namespace.
1964: */
1965: ::method setAttributeNodeNS
1966:   use strict arg newAttr
1967:   node = self~attributes~setNamedItemNS(newAttr)
1968: return node
1969: /**
1970:   If the parameter isId is true, this method declares the specified attribute to be a user-determined ID attribute. This
1971:   affects the value of the xmlAttr isId meyhod and the behavior of the xmlDocument getElementById method,
1972:   but does not change any schema that may be in use, in particular this does not affect the the xmlAttr
1973:   schemaTypeInfo property of the specified xmlAttr node. 
1974:   Use the value .false for the parameter isId to undeclare an attribute for being a user-determined ID attribute.
1975:   @param name - The name of the attribute.
1976:   @param isId - Whether the attribute is a of type ID.
1977:   @raises user domException - NOT_FOUND_ERR
1978:   
1979:   To specify an attribute by local name and namespace URI, use the setIdAttributeNS method. 
1980: */
1981: ::method setIdAttribute
1982:   use strict arg name, isId
1983:   node = self~attributes~getNamedItem(name)
1984:   if node==.nil then do 
1985:     raise user domException description (.domException~not_found_err)
1986:   end
1987:   node~isId = isId
1988: return
1989: /**
1990:   If the parameter isId is true, this method declares the specified attribute to be a user-determined ID attribute. This
1991:   affects the value of the xmlAttr isId meyhod and the behavior of the xmlDocument getElementById method,
1992:   but does not change any schema that may be in use, in particular this does not affect the the xmlAttr
1993:   schemaTypeInfo property of the specified xmlAttr node. 
1994:   Use the value .false for the parameter isId to undeclare an attribute for being a user-determined ID attribute.
1995:   @param namespaceURI - The namespace URI of the attribute.
1996:   @param localName - The local name of the attribute.
1997:   @param isId - Whether the attribute is a of type ID.
1998:   @raises user domException - NOT_FOUND_ERR
1999: */
2000: ::method setIdAttributeNS
2001:   use strict arg namespaceURI, localName, isId
2002:   node = self~attributes~getNamedItemNS(namespaceURI, localName)
2003:   if node==.nil then do
2004:     raise user domException description (.domException~not_found_err)
2005:   end
2006:   node~isId = isId
2007: return
2008: /**
2009:   If the parameter isId is true, this method declares the specified attribute to be a user-determined ID attribute. This
2010:   affects the value of the xmlAttr isId meyhod and the behavior of the xmlDocument getElementById method,
2011:   but does not change any schema that may be in use, in particular this does not affect the the xmlAttr
2012:   schemaTypeInfo property of the specified xmlAttr node. 
2013:   Use the value .false for the parameter isId to undeclare an attribute for being a user-determined ID attribute.
2014:   @param idAttr -
2015:   @param isId - 
2016:   @raises user domException - NOT_FOUND_ERR
2017: */
2018: ::method setIdAttributeNode
2019:   use strict arg idAttr, isId
2020:   if idAttr~ownerElement<>self then do
2021:     raise user domException description(.domException~not_found_err)
2022:   end
2023:   idAttr~isId = isId
2024: return
2025: /* :end */
2026: 
2027: /* CLASS: xmlDocument */
2028: /**
2029:   The xmlDocument interface represents the entire HTML or XML document. Conceptually, it is the root of the document
2030:   tree, and provides the primary access to the document's data.
2031: 
2032:   Since elements, text nodes, comments, processing instructions, etc. cannot exist outside the context of a Document,
2033:   the xmlDocument interface also contains the factory methods needed to create these objects. The xmlNode objects
2034:   created have a ownerDocument attribute which associates them with the Document within whose context they were created.
2035: */
2036: ::class xmlDocument public subclass xmlNode
2037: /**
2038:   A directory with elementIds as index and the associated xmlElement as item.
2039: */
2040: ::attribute elementIds private
2041: /**
2042:   A directory with tagNames as index and an array of xmlElement objects with the tagName as objects
2043: */
2044: ::attribute elementTags private
2045: /**
2046:   A directory with namespaceURIs as index and their prefix as item
2047: */
2048: ::attribute nameSpaces private
2049: /**
2050:   The Document Type Declaration (see DocumentType) associated with this document. For XML documents without a document
2051:   type declaration this returns .nil. For HTML documents, a DocumentType object may be returned, independently of
2052:   the presence or absence of document type declaration in the HTML document.
2053:   
2054:   This provides direct access to the xmlDocumentType node, child node of this xmlDocument. This node can be set a
2055:   t document creation time and later changed through the use of child nodes manipulation methods, such as xmlNode's 
2056:   insertBefore, or xmlNode's replaceChild. 
2057:   
2058:   Note, however, that while some implementations may instantiate different types of Document objects supporting
2059:   additional features than the "Core", such as "HTML" [DOM Level 2 HTML], based on the xmlDocumentType specified at
2060:   creation time, changing it afterwards is very unlikely to result in a change of the features supported.
2061: */ 
2062: ::attribute docType get
2063: /**
2064: */
2065: ::attribute docType set
2066: /**
2067:   This is a convenience attribute that allows direct access to the child node that is the document element of 
2068:   the document.
2069: */
2070: ::attribute documentElement get
2071: /**
2072: */
2073: ::attribute documentElement set
2074: /**
2075:   The location of the document or .nil if undefined or if the Document was created using xmlDOMImplementation
2076:   createDocument. No lexical checking is performed when setting this attribute; this could result in a
2077:   .nil value returned when using xmlNode baseURI. 
2078:   
2079:   Beware that when the Document supports the feature "HTML" [DOM Level 2 HTML], the href attribute of the HTML BASE 
2080:   element takes precedence over this attribute when computing xmlNode baseURI. 
2081: */
2082: ::attribute documentURI
2083: /**
2084:   The configuration used when xmlDocument normalizeDocument is invoked. 
2085: */ 
2086: ::attribute domConfig get
2087: /**
2088: */
2089: ::attribute domConfig set
2090: /**
2091:   The xmlDOMImplementation object that handles this document. A DOM application may use objects from multiple
2092:   implementations.
2093:   The attributes setter method ("IMPLEMENTATION=") starts out as public and is set to private once set
2094:   turning the attribute into a read-only.
2095: */
2096: ::attribute implementation get
2097: ::attribute implementation set 
2098: /**
2099:   An attribute specifying the encoding used for this document at the time of the parsing. This is null when it is not
2100:   known, such as when the xmlDocument was created in memory.
2101: */
2102: ::attribute inputEncoding get
2103: ::attribute inputEncoding set
2104: /**
2105:   An attribute specifying whether error checking is enforced or not. When set to .false, the implementation is 
2106:   free to not test every possible error case normally defined on DOM operations, and not raise any xmlDOMException on
2107:   DOM operations or report errors while using xmlDocument normalizeDocument. In case of error, the behavior is
2108:   undefined. This attribute is true by default.
2109: */
2110: ::attribute strictErrorChecking 
2111: /**
2112:   An attribute specifying, as part of the XML declaration, the encoding of this document. This is .nil when
2113:   unspecified or when it is not known, such as when the Document was created in memory.
2114: */
2115: ::attribute xmlEncoding
2116: /**
2117:   An attribute specifying, as part of the XML declaration, whether this document is standalone. This is .false
2118:   when unspecified.
2119:   
2120:   Note: No verification is done on the value when setting this attribute. Applications should use xmlDocument
2121:   normalizeDocument with the "validate" parameter to verify if the value matches the validity constraint for
2122:   standalone document declaration as defined in [XML 1.0]. 
2123: */
2124: ::attribute xmlStandalone
2125: /**
2126:   An attribute specifying, as part of the XML declaration, the version number of this document. If there is no
2127:   declaration and if this document supports the "XML" feature, the value is "1.0". If this document does not support the
2128:   "XML" feature, the value is always null. Changing this attribute will affect methods that check for invalid characters
2129:   in XML names. Application should invoke xmlDocument normalizeDocument in order to check for invalid characters
2130:   in the Nodes that are already part of this Document.
2131:   
2132:   DOM applications may use the xmlDOMImplementation hasFeature(feature, version) method with parameter values
2133:   "XMLVersion" and "1.0" (respectively) to determine if an implementation supports [XML 1.0]. DOM applications may use
2134:   the same method with parameter values "XMLVersion" and "1.1" (respectively) to determine if an implementation supports
2135:   [XML 1.1]. In both cases, in order to support XML, an implementation must also support the "XML" feature defined in
2136:   this specification. Document objects supporting a version of the "XMLVersion" feature must not raise a
2137:   NOT_SUPPORTED_ERR exception for the same version number when using xmlDocument xmlVersion. 
2138:   
2139:   @raises user domException - NOT_SUPPORTED_ERR
2140: 
2141:   Raised if the version is set to a value that is not supported by this Document or if this document does not support
2142:   the "XML" feature.  
2143: */
2144: ::attribute xmlVersion
2145: /**
2146:   xmlDocument instance constructor
2147: */
2148: ::method init
2149:   -- public attributes
2150:   self~init:super
2151:   self~nodeType = .xmlNode~documentNode
2152:   self~nodeName = "#document"
2153:   self~nodeValue = .nil
2154:   self~attributes = .nil
2155:   self~parentNode = .nil
2156:   self~previousSibling = .nil
2157:   self~nextSibling = .nil
2158:   self~ownerDocument = .nil
2159:   --self~docType = .nil same as implementation
2160:   --self~implementation = .xmlDomImplementation~new -- This one is set by .xmlDomImplementation createDocument method
2161:   -- private attributes
2162:   self~elementIds = .directory~new
2163:   self~elementTags = .directory~new
2164:   self~nameSpaces = .directory~new
2165: return
2166: /**
2167:   Attempts to adopt a node from another document to this document. If supported, it changes the ownerDocument of the
2168:   source node, its children, as well as the attached attribute nodes if there are any. If the source node has a parent
2169:   it is first removed from the child list of its parent. This effectively allows moving a subtree from one document to
2170:   another (unlike importNode which create a copy of the source node instead of moving it). When it fails,
2171:   applications should use xmlDocument importNode instead. 
2172:   
2173:   Note that if the adopted node is already part of this document (i.e. the source and target document are the same),
2174:   this method still has the effect of removing the source node from the child list of its parent, if any. The following
2175:   list describes the specifics for each type of node. 
2176:   
2177:   - ATTRIBUTE_NODE - The ownerElement attribute is set to null and the specified flag is set to true on the adopted
2178:   xmlAttr. The descendants of the source xmlAttr are recursively adopted.
 
2179:   - DOCUMENT_FRAGMENT_NODE - The descendants of the source node are recursively adopted.
 
2180:   - DOCUMENT_NODE - Document nodes cannot be adopted.
 
2181:   - DOCUMENT_TYPE_NODE - DocumentType nodes cannot be adopted.
 
2182:   - ELEMENT_NODE - Specified attribute nodes of the source element are adopted. Default attributes are discarded,
2183:   though if the document being adopted into defines default attributes for this element name, those are assigned. The
2184:   descendants of the source element are recursively adopted.
 
2185:   - ENTITY_NODE - Entity nodes cannot be adopted.
 
2186:   - ENTITY_REFERENCE_NODE - Only the EntityReference node itself is adopted, the descendants are discarded, since the
2187:   source and destination documents might have defined the entity differently. If the document being imported into
2188:   provides a definition for this entity name, its value is assigned.
 
2189:   - NOTATION_NODE - Notation nodes cannot be adopted.
 
2190:   - PROCESSING_INSTRUCTION_NODE, TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE - These nodes can all be adopted. No
2191:   specifics.
 
2192:   
2193:   
2194:   Note: Since it does not create new nodes unlike the xmlDocument importNode method, this method does not raise
2195:   an INVALID_CHARACTER_ERR exception, and applications should use the xmlDocument normalizeDocument method to
2196:   check if an imported name is not an XML name according to the XML version in use.
2197:   @param source - The xmlNode to move into this document.
2198:   @return node - The adopted node, or .nil if this operation fails, such as when the source node comes from a 
2199:   different implementation.
2200: */
2201: ::method adoptNode 
2202:   use strict arg source
2203:   raise syntax 93.900 array (isUnderConstruction(.context~name))
2204: return
2205: /**
2206:   Creates an xmlAttr of the given name. Note that the xmlAttr instance can then be set on an xmlElement using the
2207:   setAttributeNode method. 
2208:   The new xmlAttr has the nodeName attribute set to name, and localName, prefix, and
2209:   namespaceURI set to null. The value of the attribute is the empty string.
2210:   @param name - The name of the attribute.
2211:   @param value=.nil - The (optional) value of the attribute
2212:   @return attr - A new Attr object
2213:   @raises user domException - INVALID_CHARACTER_ERR
2214:   
2215:   Raised if the specified name is not an XML name according to the XML version in use specified in the xmlDocument
2216:   xmlVersion attribute.
2217:   To create an attribute with a qualified name and namespace URI, use the createAttributeNS method.
2218: */
2219: ::method createAttribute
2220:   use strict arg name, value=.nil
2221:   if name~verify(xmlValidName())>0 
2222:     then raise user domException description (.domException~invalid_character_err)
2223:   attr = .xmlAttr~new
2224:   --attr~name = name
2225:   attr~nodeName = name
2226:   attr~localName = .nil
2227:   attr~prefix = .nil
2228:   attr~namespaceURI = .nil
2229:   attr~nodeValue = value
2230:   --attr~value = .nil
2231:   attr~ownerDocument = self
2232: return attr
2233: /**
2234:   Creates an attribute of the given qualified name and namespace URI.
2235:   @param namespaceURI=.nil - The optional namespace URI of the attribute to create.
2236:   @param qualifiedName - The qualified name of the attribute to instantiate.
2237:   @return attr - A new xmlAttr object with the following attributes:
2238:   
2239:   
2240:   - nodeName - The specified qualifiedName.
 
2241:   - namespaceURI - The specified namespaceURI.
 
2242:   - prefix - prefix, extracted from qualifiedName, or null if there is no prefix.
 
2243:   - localName - name, extracted from the specified qualifiedName.
 
2244:   - name - The specified qualifiedName.
 
2245:   - nodeValue - An empty string (i.e. "").
 
2246:   
2247:   @raises user domException - INVALID_CHARACTER_ERR
2248:   @raises user domException - NAMESPACE_ERR
2249:   
2250:   Per [XML Namespaces], applications must use the value null as the namespaceURI parameter for methods if they wish to
2251:   have no namespace.
2252: */
2253: ::method createAttributeNS
2254:   use strict arg namespaceURI=.nil, qualifiedName
2255:   if qualifiedName~verify(xmlValidName())>0 
2256:     then raise user domException description (.domException~invalid_character_err)
2257:   exception = .false
2258:   if qualifiedName~countStr(':')>1 then exception = .true
2259:   prefix = ''
2260:   localName = qualifiedName
2261:   if qualifiedName~countStr(':')==1 then do
2262:     parse var qualifiedName prefix ':' localName
2263:     if prefix=='XML' & namesapceURI<>"http://www.w3.org/XML/1998/namespace" then exception = .true 
2264:     -- 2 more conditions to check, will be todo
2265:   end
2266:   if exception==.true then raise user domException description (.domException~namespace_err)
2267:   attr = .xmlAttr~new
2268:   attr~ nodeName = qualifiedName
2269:   attr~namespaceURI = namespaceURI
2270:   attr~prefix = prefix
2271:   attr~localName = localName
2272:   attr~name = qualifiedName
2273:   attr~nodeValue = ''
2274: return attr
2275: /**
2276:   Creates a xmlCDATASection node whose value is the specified string.
2277:   @param data - The data for the node.
2278:   @return cdata - The new xmlCDATASection object.
2279: */
2280: ::method createCDATASection 
2281:   use strict arg data
2282:   cdata = .xmlCDATASection~new(data)
2283: return cdata
2284: /**
2285:   Creates a xmlComment node given the specified string.
2286:   @param data - The data for the node
2287:   @return comment - The new xmlComment object
2288: */
2289: ::method createComment
2290:   use strict arg data
2291:   comment = .xmlComment~new(data)
2292: return comment
2293: /**
2294:   Creates an empty DocumentFragment object.
2295:   @return docFragment - The newly created empty xmlDocumentFragment
2296: */
2297: ::method createDocumentFragment
2298:   use strict arg
2299:   docFragment = .xmlDocumentFragment~new
2300: return docFragment
2301: /**
2302:   Creates an element of the type specified. Note that the instance returned implements the Element interface, so
2303:   attributes can be specified directly on the returned object. The new xmlElement object will have the nodeName
2304:   attribute set to tagName, and localName, prefix, and namespaceURI set to null. 
2305:   @param tagName - The name(case-sensitive for XML) of the element type to instantiate. 
2306:   
2307:   NOT YET!!!!!
2308:   In addition, if there are known attributes with default values, xmlAttr nodes representing them are automatically 
2309:   created and attached to the element.
2310:   @return element - A new xmlElement as described above.
2311:   @raises user domExceptuion - INVALID_CHARACTER_ERR
2312:   
2313:   To create an element with a qualified name and namespace URI, use the createElementNS method.
2314: */
2315: ::method createElement
2316:   use strict arg tagName
2317:   if tagName~verify(xmlValidName())>0
2318:     then raise user domException description (.domException~invalid_character_err)
2319:   element = .xmlElement~new(tagName)
2320:   element~ownerDocument = self
2321:   --if self~elementTags[tagName]==.nil then self~elementTags[tagName] = .xmlNodelist~new
2322:   --self~elementTags[tagName]~append(element)
2323: return element
2324: /**
2325:   Creates an element of the given qualified name and namespace URI.
2326:   @param namespaceURI=.nil - The optional namespace URI of the element to create.
2327:   @param qualifiedName - The qualified name of the element type to instantiate.
2328:   @return attr - A new xmlAttr object with the following attributes:
2329:   
2330:   
2331:   - nodeName - The specified qualifiedName.
 
2332:   - namespaceURI - The specified namespaceURI.
 
2333:   - prefix - prefix, extracted from qualifiedName, or null if there is no prefix.
 
2334:   - localName - name, extracted from the specified qualifiedName.
 
2335:   - tagName - The specified qualifiedName.
 
2336:   
2337:   @raises user domException - INVALID_CHARACTER_ERR
2338:   @raises user domException - NAMESPACE_ERR
2339:   
2340:   
2341:   Per [XML Namespaces], applications must use the value null as the namespaceURI parameter for methods if they wish to
2342:   have no namespace.
2343: */
2344: ::method createElementNS
2345:   use strict arg namespaceURI=.nil, qualifiedName
2346:   if qualifiedName~verify(xmlValidName())>0
2347:     then raise user domException description (.domException~invalid_character_err)
2348:   exception = .false
2349:   if qualifiedName~countStr(':')>1 then exception = .true
2350:   prefix = ''
2351:   localName = qualifiedName
2352:   if qualifiedName~countStr(':')==1 then do
2353:     parse var qualifiedName prefix ':' localName
2354:     if prefix=='XML' & namesapceURI<>"http://www.w3.org/XML/1998/namespace" then exception = .true 
2355:     -- more conditions to check, will be todo
2356:   end
2357:   if exception==.true then raise user domException description (.domException~namespace_err)
2358:   element = .xmlElement~new
2359:   element~nodeName = qualifiedName
2360:   element~namespaceURI = namespaceURI
2361:   element~prefix = prefix
2362:   element~localName = localName
2363:   element~tagName = qualifiedName
2364: return element
2365: /**
2366:   Creates a xmlEntityReference object. In addition, if the referenced entity is known, the child list of the
2367:   xmlEntityReference node is made the same as that of the corresponding xmlEntity node.
2368:   @param name - The name of the reference
2369:   
2370:   Note: If any descendant of the Entity node has an unbound namespace prefix, the corresponding descendant of the
2371:   created EntityReference node is also unbound; (its namespaceURI is null). The DOM Level 2 and 3 do not support any
2372:   mechanism to resolve namespace prefixes in this case.
2373: */
2374: ::method createEntityReference
2375:   use strict arg name
2376:   raise syntax 93.900 array (isUnderConstruction(.context~name))
2377: return
2378: /**
2379:   Creates a xmlProcessingInstruction node given the specified target and data strings.
2380:   @param target - The target part of the processing instruction
2381:   @param data - The data for the node
2382:   @return pi - The new xmlProcessingInstruction object
2383:   @raises user domException - INVALID_CHARACTER_ERR
2384: */
2385: ::method createProcessingInstruction
2386:   use strict arg target, data
2387:   if target~verify(xmlValidName())>0 
2388:     then raise user domException description (.domException~invalid_character_err)
2389:   pi = .xmlPI~new(target, data)
2390: return pi
2391: /**
2392:   Creates a xmlText node given the specified string.
2393:   @param data - The data for the node
2394:   @return text - The new xmlText object
2395: */
2396: ::method createTextNode
2397:   use arg data
2398:   text = .xmlText~new(data)
2399: return text
2400: /**
2401:   Returns the xmlElement that has an ID attribute with the given value. If no such element exists, this returns null. If
2402:   more than one element has an ID attribute with that value, what is returned is undefined. 
2403: 
2404:   NOTE - Attributes with the name "ID" or "id" are not of type ID unless so defined.
2405: 
2406:   @param elementId - The unique id value for an element.
2407:   @return element - The matching element or .nil if there is none.
2408: 
2409:   The DOM implementation is expected to use the attribute Attr~isId to determine if an attribute is of type ID. 
2410: */
2411: ::method getElementById
2412:   use strict arg elementId
2413:   element = self~elementIds[elementId]
2414: return element
2415: /**
2416:   Returns a xmlNodeList of all the xmlElements in document order with a given tag name and are within in the document.
2417:   @param tagName - The name of the tag to match on. The special value "*" matches all tags.
2418:   @return nodeList - A new xmlNodeList object containing all the matched xmlElements.
2419: 
2420:   For XML, the tagname parameter is case-sensitive, otherwise it depends on the case-sensitivity of the markup language
2421:   in use. 
2422: */
2423: ::method getElementsByTagName
2424:   use strict arg tagName
2425:   elements = .xmlNodeList~new
2426:   self~selectElements(self~childNodes, tagName, elements)
2427: return elements
2428: /**
2429:    Private method to walk the nodes tree and retrieve nodes by tagName
2430:    @param nodes - The sibling nodes to walk thru.
2431:    @param tag - The name of the tag to select on.
2432:    @param nodelist - The xmlNodeList to append selected nodes to.
2433: */
2434: ::method selectElements private
2435:   use strict arg nodes, tag, nodelist
2436:   do n=0 to nodes~length-1
2437:     node = nodes~item(n)
2438:     if (node~nodeType==.xmlNode~elementNode) then do
2439:       if tag<>'*' then do
2440:         if (node~tagName==tag) then nodelist~append(node)
2441:       end
2442:       else do
2443:         nodelist~append(node)
2444:       end
2445:       if (node~childNodes~length>0) then do
2446:         self~selectElements(node~childNodes, tag, nodelist)
2447:       end
2448:     end
2449:   end
2450: return
2451: /**
2452:   Returns a xmlNodeList of all the xmlElements with a given local name and namespace URI in document order.
2453:   @param namespaceURI=.nil - The namespace URI of the elements to match on. The special value "*" matches all namespaces.
2454:   @param localName - The local name of the elements to match on. The special value "*" matches all local names.
2455:   @return nodeList - A new xmlNodeList containing all the matched xmlElements.
2456: */
2457: ::method getElementsByTagNameNS
2458:   use strict arg namespaceURI=.nil, localName
2459:   raise syntax 93.900 array (isUnderConstruction(.context~name))
2460: return
2461: /**
2462:   Imports a node from another document to this document, without altering or removing the source node from the original
2463:   document; this method creates a new copy of the source node. The returned node has no parent; (parentNode is null).
2464: 
2465:   For all nodes, importing a node creates a node object owned by the importing document, with attribute values identical
2466:   to the source node's nodeName and nodeType, plus the attributes related to namespaces (prefix, localName, and
2467:   namespaceURI). As in the cloneNode operation, the source node is not altered. User data associated to the imported
2468:   node is not carried over. However, if any UserDataHandlers has been specified along with the associated data these 
2469:   handlers will be called with the appropriate parameters before this method returns.
2470:   
2471:   Additional information is copied as appropriate to the nodeType, attempting to mirror the behavior expected if a
2472:   fragment of XML or HTML source was copied from one document to another, recognizing that the two documents may have
2473:   different DTDs in the XML case. 
2474:   
2475:   The following list describes the specifics for each type of node.
2476:   
2477:   - ATTRIBUTE_NODE - The ownerElement attribute is set to null and the specified flag is set to true on the generated
2478:   xmlAttr. The descendants of the source xmlAttr are recursively imported and the resulting nodes reassembled to form
2479:   the corresponding subtree.
2480:   NOTE - The deep parameter has no effect on xmlAttr nodes; they always carry their children with them
2481:   when imported.
 
2482:   - DOCUMENT_FRAGMENT_NODE - If the deep option was set to true, the descendants of the source DocumentFragment are
2483:   recursively imported and the resulting nodes reassembled under the imported DocumentFragment to form the corresponding
2484:   subtree. Otherwise, this simply generates an empty DocumentFragment.
 
2485:   - DOCUMENT_NODE - Document nodes cannot be imported.
 
2486:   - DOCUMENT_TYPE_NODE - DocumentType nodes cannot be imported.
 
2487:   - ELEMENT_NODE - Specified attribute nodes of the source element are imported, and the generated xmlAttr nodes are
2488:   attached to the generated xmlElement. Default attributes are not copied, though if the document being imported into
2489:   defines default attributes for this element name, those are assigned. If the importNode deep parameter was set to
2490:   true, the descendants of the source element are recursively imported and the resulting nodes reassembled to form the
2491:   corresponding subtree.
 
2492:   - ENTITY_NODE - Entity nodes can be imported, however in the current release of the DOM the xmlDocumentType is
2493:   readonly. Ability to add these imported nodes to a xmlDocumentType will be considered for addition to a future release
2494:   of the DOM.
 
2495:   - ENTITY_REFERENCE_NODE - Only the EntityReference itself is copied, even if a deep import is requested, since the
2496:   source and destination documents might have defined the entity differently. If the document being imported into
2497:   provides a definition for this entity name, its value is assigned.
 
2498:   - NOTATION_NODE - Notation nodes can be imported, however they are read-only
 
2499:   - PROCESSING_INSTRUCTION_NODE - The imported node copies its target and data from those of the source node.
 
2500:   - TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE - These three types of nodes inheriting from xmlCharacterData copy
2501:   their data and length attributes from those of the source node.
 
2502:   
2503:   @param importNode - The node to import
2504:   @param deep=.false - optional boolean to indicate a deep copy
2505:   @return node - the imported node that belongs to this xmlDocument now.
2506:   @raises user domException - INVALID_CHARACTER_ERR
2507: */
2508: ::method importNode 
2509:   use strict arg importNode, deep=.false 
2510:   raise syntax 93.900 array (isUnderConstruction(.context~name))
2511: return
2512: /**
2513:   This method acts as if the document was going through a save and load cycle, putting the document in a "normal" form.
2514:   As a consequence, this method updates the replacement tree of EntityReference nodes and normalizes Text nodes, as
2515:   defined in the method xmlNode normalize. 
2516:  
2517:   Otherwise, the actual result depends on the features being set on the Document.domConfig object and governing what
2518:   operations actually take place. Noticeably this method could also make the document namespace well-formed according to
2519:   the algorithm described in Namespace Normalization, check the character normalization, remove the CDATASection nodes,
2520:   etc. See DOMConfiguration for details. 
2521: 
2522:   Mutation events, when supported, are generated to reflect the changes occurring on the document.
2523:   
2524:   If errors occur during the invocation of this method, such as an attempt to update a read-only node or a Node.nodeName
2525:   contains an invalid character according to the XML version in use, errors or warnings (DOMError.SEVERITY_ERROR or
2526:   DOMError.SEVERITY_WARNING) will be reported using the DOMErrorHandler object associated with the "error-handler"
2527:   parameter. Note this method might also report fatal errors (DOMError.SEVERITY_FATAL_ERROR) if an implementation cannot
2528:   recover from an error. 
2529: */
2530: ::method normalizeDocument
2531:   use strict arg
2532:   raise syntax 93.900 array (isUnderConstruction(.context~name))
2533: return
2534: /**
2535:   Rename an existing node of type ELEMENT_NODE or ATTRIBUTE_NODE.
2536:   
2537:   When possible this simply changes the name of the given node, otherwise this creates a new node with the specified
2538:   name and replaces the existing node with the new node as described below.
2539:   
2540:   If simply changing the name of the given node is not possible, the following operations are performed: a new node is
2541:   created, any registered event listener is registered on the new node, any user data attached to the old node is
2542:   removed from that node, the old node is removed from its parent if it has one, the children are moved to the new node,
2543:   if the renamed node is an Element its attributes are moved to the new node, the new node is inserted at the position 
2544:   the old node used to have in its parent's child nodes list if it has one, the user data that was attached to the old
2545:   node is attached to the new node.
2546:   
2547:   When the node being renamed is an Element only the specified attributes are moved, default attributes originated from
2548:   the DTD are updated according to the new element name. In addition, the implementation may update default attributes
2549:   from other schemas. Applications should use Document.normalizeDocument() to guarantee these attributes are up-to-date.
2550:   
2551:   When the node being renamed is an Attr that is attached to an Element, the node is first removed from the Element
2552:   attributes map. Then, once renamed, either by modifying the existing node or creating a new one as described above, it
2553:   is put back.
2554:   In addition:
2555:   
2556:   - a user data event NODE_RENAMED is fired
  
2557:   - when the implementation supports the feature "MutationNameEvents", each mutation operation involved in this method
2558:   fires the appropriate event, and in the end the event {http://www.w3.org/2001/xml-events, DOMElementNameChanged} or
2559:   {http://www.w3.org/2001/xml-events, DOMAttributeNameChanged} is fired.
 
2560:   <\ul>
2561:   @param node - The node to rename
2562:   @param namespaceURI=.nil - The new namespace URI.
2563:   @param qualifiedName - The new qualified name.
2564:   @return node - The renamed node. 
2565:    
2566:   The renamed node is either the specified node or the new node that was created to replace the specified node.
2567:   
2568:   @raises user domException - NOT_SUPPORTED_ERR
2569:   @raises user domException - INVALID_CHARACTER_ERR
2570:   @raises user domException - WRONG_DOCUMENT_ERR
2571:   @raises user domException - NAMESPACE_ERR
2572: */
2573: ::method renameNode
2574:   use strict arg node, namespaceURI=.nil, qualifiedName
2575:   raise syntax 93.900 array (isUnderConstruction(.context~name))
2576: return 
2577: /* :end */
2578: 
2579: /* CLASS: xmlDomImplementation */
2580: /**
2581:   The xmlDomImplementation interface provides a number of methods for performing operations that are independent of any
2582:   particular instance of the document object model. 
2583: */
2584: ::class xmlDomImplementation public 
2585: ::attribute features private
2586: ::method init
2587:   use strict arg
2588:   self~init:super
2589:   self~features = .directory~new
2590:   self~features["core"] = .directory~new~~putall(.array~of("",1.0,2.0))
2591:   self~features["xml"] = .directory~new~~putall(.array~of("",1.0,2.0))
2592:   self~features["ls-load"] = .directory~new~~putall(.array~of("",3.0))
2593: return
2594: /**
2595:   Creates a DOM Document object of the specified type with its document element.
2596:   
2597:   Note that based on the DocumentType given to create the document, the implementation may instantiate specialized
2598:   Document objects that support additional features than the "Core", such as "HTML" [DOM Level 2 HTML]. On the other
2599:   hand, setting the DocumentType after the document was created makes this very unlikely to happen. Alternatively,
2600:   specialized Document creation methods, such as createHTMLDocument [DOM Level 2 HTML], can be used to obtain specific
2601:   types of Document objects.
2602:   @param namespaceURI='' - The (optional) namespace URI of the document element to create or .nil.
2603:   @param qualifiedName='' - The (optional) qualified name of the document element to be created or null.
2604:   @param docType=.nil - The (optional) type of document to be created or .
2605:   @return document - A new xmlDocument object with its document element. 
2606:   @raises user - domException.INVALID_CHARACTER_ERR
2607:   @raises user - domException.NAMESPACE_ERR
2608: 
2609:   If the namespaceURI, qualifiedName, and docType are .nil, the returned xmlDocument is empty with no document
2610:   element.
2611:   When docType is not .nil, its ownerDocument attribute is set to the document being created.
2612: */
2613: ::method createDocument
2614:   use strict arg namespaceURI='', qualifiedName='', docType=.nil 
2615:   if qualifiedName~verify(xmlValidName())>0 
2616:     then raise user domException description (.domException~INVALID_CHARACTER_ERR)
2617:   prefix = ''
2618:   localName = qualifiedName
2619:   if qualifiedName~countStr(':')>1 
2620:     then raise user domException additional (.domException~namespace_err) description ("Qualified name can contain only one ':' character.")
2621:   if qualifiedName~countStr(':')==1 then parse var qualifiedName prefix':'localName
2622:   if prefix<>'' & namespaceURI=='' 
2623:     then raise user domException additional (.domException~NAMESPACE_ERR) description ("Cannot have a prefix without namespaceURI.") 
2624:   if namespaceURI<>'' & qualifiedName=='' 
2625:     then raise user domException additional (.domException~NAMESPACE_ERR) description ("Cannot have namespaceURI without prefix.")
2626:   if prefix~upper=='XML' & namespaceURI~lower<>'http://www.w3.org/XML/1998/namespace'
2627:     then raise user domException additional (.domException~NAMESPACE_ERR) description ("Invalid namespaceURI for prefix" prefix".")    
2628:   if docType<>.nil then do
2629:     if docType~isA(.xmlDocType) then do
2630:       if docType~ownerDocument<>.nil then raise user domException additional (.domException~WRONG_DOCUMENT_ERR) description ("DOCTYTPE belongs to different document.")
2631:     end
2632:     else raise user domException additional (.domException~SYNTAX_ERR) description ("Argument is NOT a .xmlDocType.")
2633:   end
2634:   --trace i
2635:   document = .xmlDocument~new
2636:   document~implementation = self
2637:   document~prefix = prefix
2638:   document~localName = localName
2639:   document~namespaceURI = namespaceURI
2640:   if docType<>.nil then do 
2641:     document~appendChild(docType) 
2642:     docType~ownerDocument = document
2643:   end
2644:   document~docType = docType
2645:   --if namespaceURI<>.nil | qualifiedName<>.nil | docType<>.nil then do 
2646:   --  documentElement = document~createElement(qualifiedName)
2647:   --  document~appendChild(documentElement)
2648:   --  document~documentElement = documentElement
2649:   --end
2650: return document
2651: /**
2652:   Creates an empty DocumentType node. Entity declarations and notations are not made available. Entity reference
2653:   expansions and default attribute additions do not occur.
2654:   @param qualifiedName - The qualified name for to new document (e.g. 'gpx')
2655:   @param publicId - The public identifier of this document type (e.g. '-//W3C//DTD XHTML 1.0 Strict//EN')
2656:   @param systemId - The system identifier for the document type (e.g. 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd')
2657:   @return node - An empty xmlDocumentType node.
2658: */
2659: ::method createDocumentType
2660:   use strict arg qualifiedName, publicId, systemId
2661:   raise syntax 93.900 array (isUnderConstruction(.context~name))
2662: return
2663: /**
2664:   This method returns a specialized object which implements the specialized APIs of the specified feature and version,
2665:   as specified in DOM Features. The specialized object may also be obtained by using binding-specific casting methods
2666:   but is not necessarily expected to, as discussed in Mixed DOM Implementations. This method also allow the
2667:   implementation to provide specialized objects which do not support the DOMImplementation interface. 
2668:   @param feature - The name of the feature requested. 
2669:   @param version - This is the version number of the feature to test.
2670:   @return object - Returns a xmlDomObject or .nil.
2671: 
2672:   The returned xmlDomObject which implements the specialized APIs of the specified feature and version, it is
2673:   .nil if there is no object which implements interfaces associated with that feature.
2674: 
2675:   NOTE,/b> - The DOM Level 3 Feature handler support is not currently implemented, therefore getFeature
2676:   will always return .nil.
2677: */
2678: ::method getFeature
2679:   use strict arg feature, version
2680:   featureHandler = .nil
2681:   versions = self~features[feature~lower]
2682:   if versions<>.nil then do
2683:     featureHandler = versions~index(feature)
2684:   end
2685: return featureHandler
2686: /**
2687:   Test if the DOM implementation implements a specific feature and version, as specified in DOM Features.
2688:   @param feature - The name of the feature requested. 
2689:   @param version='' - This is the (optional) version number of the feature to test.
2690:   @return boolean - Returns .true if the feature is implemented in the specified version, .false
2691:   otherwise.
2692: */
2693: ::method hasFeature
2694:   use strict arg feature, version=''
2695:   versions = self~features[feature~lower]
2696:   if versions<>.nil then do
2697:     featureSupported = versions~index[feature~lower]
2698:   end
2699: return featureSupported<>.nil
2700: /* :end */
2701: 
2702: /* CLASS: domBuilder */
2703: /**
2704: 
2705: */
2706: ::class dom1Builder public 
2707: /**
2708:   The DOM (Level 1) implementation for building a DOM (Level 1)
2709:   
2710:   NOTE - The domImplementation is currently only used for it's createDocument method.
2711: */
2712: ::attribute dom private
2713: /**
2714:   The DOM document resulting from the XML Parser and DOM (Level 1) builder.
2715: */
2716: ::attribute doc get
2717: ::attribute doc set private
2718: /**
2719:   The stack of nested elements with childnodes.
2720:   
2721:   NOTE - nodeStack[1] represents the current active Element node.
2722: */
2723: ::attribute nodeStack private
2724: /**
2725:   Represents the current active Attr node
2726: */
2727: ::attribute attrNode private
2728: /**
2729:   Flag to indicate if the convenience attribute documentElement must be set or not.
2730: */
2731: ::attribute haveDocumentElement private
2732: /**
2733:   DOM Builder instance constructor
2734:   
2735:   NOTE - domImplementation was introduced in DOM Level2, it is used here only to create a document with no
2736:   namespace and doctype.
2737: */
2738: ::method init
2739:   self~dom = .xmlDomImplementation~new
2740:   self~nodeStack = .queue~new
2741:   self~haveDocumentElement = .false
2742: return
2743: /**
2744:   The method invoker wants to start a new DOM document. A DOM Level1 document is created with the help of the DOM Level2
2745:   DomImplemetation interface.
2746:   @param content=.nil - Currently ignored, if present
2747: */
2748: ::method startDocument
2749:   use strict arg content=.nil
2750:   self~doc = self~dom~createDocument()
2751:   self~nodeStack~push(self~doc)
2752: return
2753: /**
2754:   Signals the end of DOM building process. At this stage the stack with active nodes should only have the document node
2755:   as content.
2756: */
2757: ::method endDocument
2758:   use strict arg
2759:   -- stack should have just 1 item now
2760:   if self~nodeStack~items<>1 then do
2761:     raise syntax 93.900 array ("Error in XML input")
2762:   end
2763:   docNode = self~nodeStack~pull
2764: return
2765: /**
2766:   Start a new element node.
2767:   @param tagName - the name of the tag for this element node.
2768:   
2769:   If this is the first element created, the convenience attribute documentElement is set. The new element node is
2770:   made the currently active one after being appended as a childnode of the parentnode.
2771: */
2772: ::method startElement
2773:   use strict arg tagName
2774:   elementNode = self~doc~createElement(tagName)
2775:   if (self~haveDocumentElement==.false) then do
2776:     self~doc~documentElement = elementNode
2777:     self~haveDocumentElement = .true
2778:   end
2779:   self~nodeStack[1]~appendChild(elementNode)
2780:   self~nodeStack~push(elementNode)
2781: return
2782: /**
2783:   Finish the currently active element node.
2784:   @param tagName - the name of the tag of the element being ended.
2785:   @raises syntax 93.900 - Mismatch in start and ending tag.
2786: 
2787:   The previous elemnt node is made the active node, by removing this active node from the stack.
2788: */
2789: ::method endElement
2790:   use strict arg tagName
2791:   if self~nodeStack[1]~tagName<>tagName then do
2792:     raise syntax 93.900 array ("Mismatch in start:" self~nodeStack[1]~tagName "and ending tag" tagName) 
2793:   end
2794:   -- get rid of processed node
2795:   processedNode = self~nodeStack~pull
2796: return
2797: /**
2798:   Handle an attribute's name
2799:   @param attrName - the name part of the current element's attribute.
2800:   
2801:   This will create the Attr node for the attribute, no name space checking is done.
2802: */
2803: ::method nameAttr
2804:   use strict arg attrName
2805:   self~attrNode = self~doc~createAttribute(attrName)
2806: return
2807: /**
2808:   Handle an attibute's value.
2809:   @param attrValue - the value part of the current element's attribute.
2810:   
2811:   Appends this Attr node to the (perhaps empty) list of attributes. Also sets the Attr's node ownerelement.
2812: */
2813: ::method valueAttr
2814:   use strict arg attrValue
2815:   self~attrNode~nodeValue = attrValue
2816:   self~attrNode~ownerElement = self~nodeStack[1]
2817:   self~nodeStack[1]~setAttributeNode(self~attrNode)
2818: return
2819: /**
2820:   Handle a Processing Instruction (PI). 
2821:   @param target - The target for the PI (e.g. 'xml' in '<?xml version=.......?>'.
2822:   @param data - The information following the target as a string.
2823:   
2824:   The PInode is appended as a childnode for the currently active element node.
2825: */
2826: ::method havePI
2827:   use strict arg target, data
2828:   piNode = self~doc~createProcessingInstruction(target,data)
2829:   self~nodeStack[1]~appendChild(piNode)
2830: return  
2831: /**
2832:   Handle a Comment.
2833:   @param comment - The string representing the comment
2834:   
2835:   No validity checking is done on the comment's content. The comment node is appended as a childnode for the active
2836:   element node.
2837: */
2838: ::method haveComment
2839:   use strict arg comment
2840:   cmtNode = self~doc~createComment(comment)
2841:   self~nodeStack[1]~appendChild(cmtNode)
2842: return
2843: /**
2844:   Handle a Text node.
2845:   @param text - the (inner) text of the node with entities resolved.
2846:   
2847:   The text node is appended as a childnode for the active element node.
2848: */
2849: ::method haveText
2850:   use strict arg text
2851:   txtNode = self~doc~createTextNode(text)
2852:   self~nodeStack[1]~appendChild(txtNode)
2853: return
2854: /**
2855:   Handle CDATA.
2856:   @param cdata - The raw (unparsed) text for the CDATASection node.
2857:   
2858:   The CDATA node is appended as a childnode for the currently active element node
2859: */
2860: ::method haveCDATA
2861:   use strict arg cdata
2862:   cdataNode = self~doc~createCDATASection(cdata)
2863:   self~nodeStack[1]~appendChild(cdataNode)
2864: return
2865: /* :end */
2866: 
2867: /* CLASS: xmlParser */
2868: /**
2869:   A non-validating simple XML parser. The parser recognizes the following:
2870:   
2871:   - Document start, when a XML file has been stringified and when the parseSting method has accepted the
2872:   string.
  
2873:   - XML Comments, no test for not allowed comment nesting.
 
2874:   - Removable White Space is removed when encountered.
 
2875:   - Processing Instructions (PI's), split into target (e.g. xml in <?xml version....?>) and data.
 
2876:   - CDATA with it's raw unparsed text.
 
2877:   - Attribute only tags, with their parsed, but without namespace checking, attributes.
 
2878:   - Tags with atributes as above and their parsed (i.e. resolved entities) text content.
 
2879:   - Document end, when the end of the XML string has been reached.
 
2880:   
2881: */
2882: ::class xmlParser public
2883: /**
2884:   The DOM builder given as parameter at instance creation time
2885: */
2886: ::attribute domBuilder private
2887: /**
2888:   The xmlParser constructor.
2889:   @param domBuilder - the DOM builder the parser should use
2890: */
2891: ::method init
2892:   use strict arg domBuilder
2893:   self~domBuilder = domBuilder
2894: return
2895: /**
2896:   Converts a XML file or stream into a string and passes the string on to parseString.
2897:   @param xmlStream - An object with a supplier method
2898:   @return domDocument - the DOM created from the input stream or .nil in case of errors
2899: */
2900: ::method parseStream
2901:   use strict arg xmlStream
2902:   s = xmlStream~supplier
2903:   xml = ''
2904:   do while s~available
2905:     xml ||= s~item || .endofline
2906:     s~next
2907:   end
2908: return self~parseString(xml)
2909: /**
2910:   Analyzes the input string for situations the DOM builder wants to know about and invokes the appropiate methods for
2911:   the builder to handle the situations.
2912:   @param xml - the XML string to be parsed.
2913:   @return domDocument - the DOM created by the builder or .nil in case of errors.
2914: */  
2915: ::method parseString
2916:   use strict arg xml
2917:   self~domBuilder~startDocument
2918:   do while (xml~pos('>')>0)
2919:     tagEnd = xml~pos('>')
2920:     -- check comment first cause it can appear anywhere
2921:     cmtStart = xml~pos("" +3 xml
2925:       -- repair comment xml
2926:       tag = ""
2927:     end
2928:     else do
2929:       -- there could be (element) content in front of the tag(= '<')
2930:       parse var xml text '<' tagContent '>' +1 xml
2931:       -- repair tag xml
2932:       tag = '<'tagContent'>'
2933:     end
2934:     -- if there is text it is the content for an element
2935:     if (text<>'') then do
2936:       -- if it is not ignorable whitespace
2937:       if self~removeIgnorableWhiteSpace(text)<>'' 
2938:         then self~domBuilder~haveText(self~resolveEntities(text))
2939:         else text = ''
2940:     end
2941:     -- now handle the tag
2942:     select 
2943:       when (tag~pos(""
2946:         self~domBuilder~haveComment(comment)
2947:       end
2948:       when (tag~pos("")>0) then do
2949:         -- this is a processing instruction (e.g. <?xml version=....?>)
2950:         parse var tag "" target data "?>"
2951:         self~domBuilder~havePI(target, data)
2952:       end
2953:       when (tag~pos("0) then do
2954:         -- there is unparsed (raw) text
2955:         parse var tag ""
2956:         self~domBuilder~haveCDATA(rawText)
2957:       end
2958:       when (tag~pos("/>")>0) then do
2959:         -- there is a complete element 
2960:         parse var tag '<' tagName attributes "/>"
2961:         self~domBuilder~startElement(tagName)
2962:         -- handle attributes if any
2963:         self~parseAttributes(self~removeIgnorableWhiteSpace(attributes))
2964:         self~domBuilder~endElement(tagName)
2965:       end
2966:       when (tag~pos("")>0) then do
2967:         -- this is an element ending tag
2968:         parse var tag "" tagName '>'
2969:         self~domBuilder~endElement(tagName)
2970:       end
2971:       otherwise do
2972:         -- must be a element starting tag
2973:         parse var tag '<' tagName attributes '>'
2974:         self~domBuilder~startElement(tagName)
2975:         -- handle attributes if any
2976:         self~parseAttributes(self~removeIgnorableWhiteSpace(attributes))
2977:       end
2978:     end
2979:   end
2980:   self~domBuilder~endDocument
2981: return self~domBuilder~doc
2982: /**
2983:   Processes the attributes specified within an element tag and passes them on the the builder.
2984:   @param attributes - the string containing all the attributes specifications within an element tag.
2985: */
2986: ::method parseAttributes private
2987:   use strict arg attributes
2988:   attributes = attributes~strip
2989:   do while (attributes<>'')
2990:     parse var attributes attrName '=' rest  
2991:     aposPos = rest~pos("'")
2992:     quotPos = rest~pos('"')
2993:     select
2994:       when (quotPos=0) then delimiter = "'"
2995:       when (aposPos=0) then delimiter = '"'
2996:       when (aposPosNOTE - As DOCTYPE is not supported (yet) no DOCTYPE defined entities are handled.
3019: */
3020: ::method resolveEntities private
3021:   use strict arg text
3022:   text = text~changeStr("<",'<')
3023:   text = text~changeStr(">",'>') 
3024:   text = text~changeStr("&",'&')
3025:   text = text~changeStr("'","'")
3026:   text = text~changeStr(""",'"')
3027: return text
3028: /* :end */ 
3029:   
3030: 
3031: 
3032: 
3033: