ooRexx logo
   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: 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: 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: 673: For two xmlDocumentType nodes to be equal, the following conditions must also be satisfied: 674: 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 "" 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 "' 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:
If you feel inclined to make corrections, suggestions etc., please mail me any.
All content © Ruurd Idenburg, 2007–, except where marked otherwise. All rights reserved. This page is primarily for non-commercial use only. The Idenburg website records no personal information and sets no ‘cookies’. This site is hosted on a VPS(Virtual Private System) rented from Transip.nl, a Dutch company, falling under Dutch (privacy) laws (I think).

This page updated on by Ruurd Idenburg.