From: <bi...@us...> - 2009-05-20 15:35:52
|
Revision: 4715 http://oorexx.svn.sourceforge.net/oorexx/?rev=4715&view=rev Author: bigrixx Date: 2009-05-20 15:35:26 +0000 (Wed, 20 May 2009) Log Message: ----------- a little more work on the DOM classes Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2009-05-20 12:37:02 UTC (rev 4714) +++ incubator/orxutils/xml/xmldom.cls 2009-05-20 15:35:26 UTC (rev 4715) @@ -110,7 +110,7 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() > 0 then raise syntax 93.902 array (0) +use strict arg self~ver = .directory~new self~ver['1.0'] = .directory~new return @@ -122,9 +122,7 @@ /*----------------------------------------------------------------------------*/ ::method hasFeature -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg feature, version +use strict arg feature, version = (.nil) if version = .nil then do featureset over self~ver if featureset[feature] <> .nil then return .true end @@ -145,9 +143,11 @@ ::class 'NodeList' public ::method init expose nodes + -- we're a read-only list...the owning node returns the list, we work off + -- of a snapshot copy use strict arg nodes + nodes = nodes~copy - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: NodeList */ @@ -163,7 +163,6 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ - /*----------------------------------------------------------------------------*/ /* Method: item */ /* Description: get a list item. */ @@ -176,13 +175,11 @@ -- maintain that. return nodes[index + 1] -- returns .nil for out of bounds - /*----------------------------------------------------------------------------*/ /* Method: length */ /* Description: get the number of items in the list. */ /*----------------------------------------------------------------------------*/ - -::method length +::attribute length get expose nodes use strict arg return nodes~items @@ -193,7 +190,7 @@ return nodes~copy -- make sure this is a copy ::method "[]" - return forward message("ITEM") + return message("ITEM") /*----------------------------------------------------------------------------*/ @@ -204,8 +201,9 @@ ::class 'NamedNodeMap' public ::method init - expose attributes - use strict arg attributes + expose ownerNode attributes + use strict arg ownerNode + attributes = .nil /*----------------------------------------------------------------------------*/ @@ -215,7 +213,63 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +::method findNamePoint private + expose attributes + use arg name + if attributes == .nil then do + return 0 + end + + do i = 1 to attributes~items + if attributes[i]~nodeName == name then do + return i + end + end + + return 0 + + +::method findNamePointNS private + expose attributes + use arg name, namespace + + if attributes == .nil then do + return 0 + end + + do i = 1 to attributes~items + attr = attributes[i] + if namespace == .nil then do + if attr~namespaceURI == .nil & name == attr~localName then do + return i + end + + if attr~localName == .nil & name == attr~nodeName then do + return i + end + end + else do + if attr~namespaceURI == namespace & attr~localName == name then do + return i + end + end + end + + return 0 + +::method removeAt private + expose attributes + use arg position + + do i = position to attributes~items - 1 + attributes[i] = attributes[i + 1] + end + + -- this removes the last item + attributes~remove[i] + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: NamedNodeMap */ @@ -233,12 +287,18 @@ expose attributes use strict arg name - do i = 1 to attributes~items - if attributes[i]~name == name then do - return attribuetes[i] + if attributes == .nil then do + return .nil + end + + do attribute over attributes + if attribute~name == name then do + return attribute end end + return .nil + /*----------------------------------------------------------------------------*/ /* Method: getNamedItemNS */ /* Description: get a named item by namespace */ @@ -248,12 +308,16 @@ expose attributes use strict arg name, namespace - do i = 1 to attributes~items - attr = attributes[i] - if attr~name == name & attr~namespaceURI == namespace then do - return attr + if attributes == .nil then do + return .nil + end + + do attribute over attributes + if attribute~name == name & attribute~namespaceURI == namespace then do + return attribute end end + return .nil /*----------------------------------------------------------------------------*/ @@ -262,19 +326,123 @@ /*----------------------------------------------------------------------------*/ ::method setNamedItem - raise syntax 93.963 -- not supported + expose attributes + use strict arg node + index = self~findNamePoint(node~nodeName) + previous = .nil + if i > 0 then do + previous = attributes[i] + attributes[i] = node + end + else do + if attributes == .nil then do + attributes = .array~new + end + attributes~append(node) + end + + return previous + + /*----------------------------------------------------------------------------*/ +/* Method: setNamedItemNS */ +/* Description: set a named item. */ +/*----------------------------------------------------------------------------*/ + +::method setNamedItemNS + expose attributes + use strict arg node + + index = self~findNamePointNS(node~localName, node~namespaceURI) + previous = .nil + + if i > 0 then do + previous = attributes[i] + attributes[i] = node + end + else do + -- we try again just based on the nodeName + index = self~findNamePoint(node~nodeName) + if index > 0 then do + previous = attributes[i] + attributes[i] = node + end + else do + if attributes == .nil then do + attributes = .array~new + end + attributes~append(node) + end + end + + return previous + + +/*----------------------------------------------------------------------------*/ /* Method: removeNamedItem */ /* Description: remove a named item. */ /*----------------------------------------------------------------------------*/ ::method removeNamedItem - raise syntax 93.963 -- not supported + expose attributes + use strict arg name + index = self~findNamePoint(name) + previous = .nil + if i > 0 then do + previous = attributes[i] + self~removeAt(i) + end + return previous + + /*----------------------------------------------------------------------------*/ +/* Method: removeNamedItemNS */ +/* Description: remove a named item. */ +/*----------------------------------------------------------------------------*/ + +::method removeNamedItem + expose attributes + use strict arg namespace, name + + index = self~findNamePointNS(name, namespace) + previous = .nil + + if i > 0 then do + previous = attributes[i] + self~removeAt(i) + end + return previous + +/*----------------------------------------------------------------------------*/ +/* Method: cloneMap */ +/* Description: perform a deep copy of this map object */ +/*----------------------------------------------------------------------------*/ +::method clone + expose attributes + use strict arg owner + newMap = .NamedNodeMap(owner) + newMap~cloneContent(attributes) + +/*----------------------------------------------------------------------------*/ +/* Method: cloneContent */ +/* Description: initialize the content from another map */ +/*----------------------------------------------------------------------------*/ +::method cloneContent + expose attributes + use arg source + if source \= .nil then do + attributes = source~copy + do i = 1 to attributes~items + attributes[i] = attributes[i]~cloneNode(.true) + end + end + + +/*----------------------------------------------------------------------------*/ /* Method: item */ /* Description: return the named item. */ /*----------------------------------------------------------------------------*/ @@ -282,7 +450,12 @@ ::method item expose attributes use strict arg position - return attributes[position + 1] + if attributes == .nil then do + return .nil + end + else do + return attributes[position + 1] + end /*----------------------------------------------------------------------------*/ @@ -293,7 +466,12 @@ ::method length expose attributes use strict arg - return attributes~items + if attributes != .nil then do + return attributes~items + end + else do + return 0; + end ::method makearray expose attributes @@ -301,7 +479,7 @@ return attributes~copy -- make sure this is a copy ::method "[]" - return forward message("ITEM") + forward message("ITEM") @@ -313,99 +491,133 @@ /*----------------------------------------------------------------------------*/ ::CLASS 'Node' public -::METHOD ELEMENT_NODE class - use strict arg - return 1 -::METHOD ATTRIBUTE_NODE class - use strict arg - return 2 -::METHOD TEXT_NODE class - use strict arg - return 3 -::METHOD CDATA_SECTION_NODE class - use strict arg - return 4 -::METHOD ENTITY_REFERENCE_NODE class - use strict arg - return 5 -::METHOD ENTITY_NODE class - use strict arg - return 6 -::METHOD PROCESSING_INSTRUCTION_NODE class - use strict arg - return 7 -::METHOD COMMENT_NODE class - use strict arg - return 8 -::METHOD DOCUMENT_NODE class - use strict arg - return 9 -::METHOD DOCUMENT_TYPE_NODE class - use strict arg - return 10 -::METHOD DOCUMENT_FRAGMENT_NODE class - use strict arg - return 11 -::METHOD NOTATION_NODE class - use strict arg - return 12 +::CONSTANT ELEMENT_NODE 1 +::CONSTANT ATTRIBUTE_NODE 2 +::CONSTANT TEXT_NODE 3 +::CONSTANT CDATA_SECTION_NODE 4 +::CONSTANT ENTITY_REFERENCE_NODE 5 +::CONSTANT ENTITY_NODE 6 +::CONSTANT PROCESSING_INSTRUCTION_NODE 7 +::CONSTANT COMMENT_NODE 8 +::CONSTANT DOCUMENT_NODE 9 +::CONSTANT DOCUMENT_TYPE_NODE 10 +::CONSTANT DOCUMENT_FRAGMENT_NODE 11 +::CONSTANT NOTATION_NODE 12 +::METHOD init class + expose ctr + ctr = 0 +::METHOD getId class private + expose ctr + ctr += 1 + return ctr + + +/*----------------------------------------------------------------------------*/ +/* Method: init */ +/* Description: instance initialization. */ +/*----------------------------------------------------------------------------*/ + ::METHOD init - expose prefix localname nodename namespaceuri nodeType - use strict arg prefix, localname, nodename, namespaceuri, nodetype + expose ownerNode childNodes nodeId + use strict arg ownerNode + nodeId = self~class~getId + childNodes = .NodeList~new + self~owned = .false -- unowned until we are added as a child + self~readonly = .false -- newly created nodes can be altered ::ATTRIBUTE nodeName GET -::ATTRIBUTE namespaceURI GET -::ATTRIBUTE nodeType GET -::ATTRIBUTE localName GET -::ATTRIBUTE prefix GET - --- default implementations designed to be overridden +-- superclasses overrid ::ATTRIBUTE nodeValue GET - use strict arg return .nil +::ATTRIBUTE nodeValue SET + return -- default behavior is to do nothing...superclasses override this +::ATTRIBUTE nodeType GET +-- superclasses override ::ATTRIBUTE parentNode GET - use strict arg return .nil ::ATTRIBUTE childNodes GET - use strict arg - return .nil +-- superclasses override ::ATTRIBUTE firstChild GET - use strict arg return .nil +-- superclasses override ::ATTRIBUTE lastChild GET - use strict arg return .nil +-- superclasses override ::ATTRIBUTE previousSibling GET - use strict arg return .nil +-- superclasses override ::ATTRIBUTE nextSibling GET - use strict arg return .nil +-- superclasses override ::ATTRIBUTE attributes GET - use strict arg return .nil + +::METHOD hasAttributes + use strict arg + return .false + ::ATTRIBUTE ownerDocument GET + expose ownerDocument ownerNode + + -- if we're a child node, then ask our owner for the information + if self~owned then do + return ownerNode~ownerDocument + end + else do + -- return the owner directly + return ownerNode + end + +::ATTRIBUTE ownerDocument SET PRIVATE + expose ownerNode + + use strict arg doc + if \self~owned then do + ownerNode = doc + end + +::ATTRIBUTE namespaceURI GET use strict arg return .nil +::ATTRIBUTE prefix GET + use strict arg + return .nil +::ATTRIBUTE prefix SET + -- this is an error by default + .DomErrors~raiseError(.DomErrors~NAMESPACE_ERR) +::ATTRIBUTE localName GET + use strict arg + return .nil +::ATTRIBUTE baseURI GET + use strict arg + return .nil +-- private attributes used for the implementation +::ATTRIBUTE owned PRIVATE +::ATTRIBUTE readonly PRIVATE + +-- default implementations designed to be overridden ::METHOD hasChildNodes use strict arg - return .false + return .false; -::METHOD clone +-- base cloning method +::METHOD cloneNode use strict arg deep = .false - return .nil + // make a copy of ourselves + newNode = self~copy + // neither owned or readonly + newNode~owned = .false + newNode~readOnly = .false + return newNode + ::METHOD isSupported use strict arg feature, version return .false -::METHOD hasAttributes - use strict arg - return .false - ::ATTRIBUTE nodeValue SET use strict arg value raise syntax 93.963 -- not supported @@ -416,35 +628,36 @@ ::METHOD insertBefore use strict arg newChild, refChild - raise syntax 93.963 -- not supported + -- not implemented in the base node + .DomErrors~raiseError(.DomErrors~Hierarchy_request_err) ::METHOD replaceChild use strict arg newChild, oldChild - raise syntax 93.963 -- not supported + -- not implemented in the base node + .DomErrors~raiseError(.DomErrors~Hierarchy_request_err) ::METHOD removeChild use strict arg oldChild - raise syntax 93.963 -- not supported + -- not implemented in the base node + .DomErrors~raiseError(.DomErrors~Not_found_err) ::METHOD appendChild use strict arg newChild - raise syntax 93.963 -- not supported + return self~insertBefore(newChild, .nil) ::METHOD compareDocumentPosition use strict arg other raise syntax 93.963 -- not supported ::ATTRIBUTE textContent GET - use strict arg - raise syntax 93.963 -- not supported + forward message("NODEVALUE") ::ATTRIBUTE textContent SET - use strict arg value - raise syntax 93.963 -- not supported + forward message("NODEVALUE=") ::METHOD isSameNode use strict arg other - raise syntax 93.963 -- not supported + return self~identityHash = other~identityHash ::METHOD lookupPrefix use strict arg uri @@ -460,8 +673,35 @@ ::METHOD isEqualNode use strict arg other - raise syntax 93.963 -- not supported + if self == other then do + return .true + end + + if self~nodetype != other~nodetype then do + return .false + end + + if self~nodename != other~nodename then do + return .false + end + + if self~localname != other~localname then do + return .false + end + + if self~namespaceURI != other~namespaceURI then do + return .false + end + + if self~prefix != other~prefix then do + return .false + end + + if self~nodevalue != other~nodevalue then do + return .false + end + ::METHOD getFeature use strict arg feature, version return .nil @@ -474,344 +714,49 @@ use strict arg key raise syntax 93.963 -- not supported +-- The following are NodeList methods implemented by the node class. Enables +-- nicer Rexx-style access - /*----------------------------------------------------------------------------*/ +/* Method: item */ +/* Description: get a list item. */ /*----------------------------------------------------------------------------*/ -/* Class: Node */ -/* Private methods */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -::attribute ctr class private -::attribute id private -::attribute children private -::attribute attr private +::method item + expose childNodes + forward to(childNodes) - /*----------------------------------------------------------------------------*/ -/* Method: nodeType= */ -/* Description: set type of node. */ +/* Method: length */ +/* Description: get the number of items in the list. */ /*----------------------------------------------------------------------------*/ +::attribute length get + expose childNodes + forward to(childNodes) -::method 'nodeType=' private -expose nodeType -use arg nodeType -return +::method makearray + expose childNodes + forward to(childNodes) +::method "[]" + expose childNodes + forward to(childNodes) message("ITEM") -/*----------------------------------------------------------------------------*/ -/* Method: nodeName= */ -/* Description: set node name. */ -/*----------------------------------------------------------------------------*/ -::method 'nodeName=' private -expose nodeName -use arg nodeName -return - /*----------------------------------------------------------------------------*/ -/* Method: parentNode */ -/* Description: set the parent node of this node. */ /*----------------------------------------------------------------------------*/ - -::method 'parentNode=' private -expose parentNode -use arg parentNode -return - - -/*----------------------------------------------------------------------------*/ -/* Method: ownerDocument */ -/* Description: set the owner document node of this node. */ -/*----------------------------------------------------------------------------*/ - -::method 'ownerDocument=' private -expose ownerDocument -use arg ownseDocument -return - - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ /* Class: Node */ -/* Public methods */ +/* Private methods */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::method nodeValue +::attribute ctr class private +::attribute id private /*----------------------------------------------------------------------------*/ -/* Method: init */ -/* Description: instance initialization. */ /*----------------------------------------------------------------------------*/ - -::method init -if .node~ctr = 'CTR' then .node~ctr = 0 -.node~ctr = .node~ctr + 1 -self~id = .node~ctr -self~nodeType = '' -self~nodeName = '' -self~nodeValue = .nil -self~parentNode = .nil -self~children = .NodeList~new -self~attr = .nil -self~ownerDcoument = .nil -return - - -/*----------------------------------------------------------------------------*/ -/* Method: = */ -/* Description: test for equal. */ -/*----------------------------------------------------------------------------*/ - -::method '=' -use arg testnode -if testnode~id = self~id then return .true -return .false - - -/*----------------------------------------------------------------------------*/ -/* Method: nodeType */ -/* Description: get type of node. */ -/*----------------------------------------------------------------------------*/ - -::method nodeType -expose nodeType -if arg() > 0 then raise syntax 93.902 array (0) -return nodeType - - -/*----------------------------------------------------------------------------*/ -/* Method: nodeName */ -/* Description: get node name. */ -/*----------------------------------------------------------------------------*/ - -::method nodeName -expose nodeNaem -if arg() > 0 then raise syntax 93.902 array (0) -return nodeName - - -/*----------------------------------------------------------------------------*/ -/* Method: parentNode */ -/* Description: get parent node of this node. */ -/*----------------------------------------------------------------------------*/ - -::method parentNode -expose parentNode -if arg() > 0 then raise syntax 93.902 array (0) -return parentNode - - -/*----------------------------------------------------------------------------*/ -/* Method: childNode */ -/* Description: get list od child nodes. */ -/*----------------------------------------------------------------------------*/ - -::method childNodes -expose children -if arg() > 0 then raise syntax 93.902 array (0) -return self~children - - -/*----------------------------------------------------------------------------*/ -/* Method: firstChild */ -/* Description: get the first child node. */ -/*----------------------------------------------------------------------------*/ - -::method firstChild -expose children -if arg() > 0 then raise syntax 93.902 array (0) -if children~items = 0 then return .nil -return children[1] - - -/*----------------------------------------------------------------------------*/ -/* Method: lastChild */ -/* Description: get the last child node. */ -/*----------------------------------------------------------------------------*/ - -::method lastChild -expose children -if arg() > 0 then raise syntax 93.902 array (0) -if children~items = 0 then return .nil -return children[children~items] - - -/*----------------------------------------------------------------------------*/ -/* Method: previousSibling */ -/* Description: get our previous sibling. */ -/*----------------------------------------------------------------------------*/ - -::method previousSibling -if arg() > 0 then raise syntax 93.902 array (0) -if self~parentNode = .nil then return .nil -siblings = self~parentNode~childNodes -do i = 1 to siblings~items - if siblings[1] = self then do - if i = 1 then return .nil - else return siblings[i - 1] - end - end -end -return .nil - - -/*----------------------------------------------------------------------------*/ -/* Method: nextSibling */ -/* Description: get our next sibling. */ -/*----------------------------------------------------------------------------*/ - -::method nextSibling -if arg() > 0 then raise syntax 93.902 array (0) -if self~parentNode = .nil then return .nil -siblings = self~parentNode~childNodes -do i = 1 to siblings~items - if siblings[1] = self then do - if i = siblings~items then return .nil - else return siblings[i + 1] - end - end -end -return .nil - - -/*----------------------------------------------------------------------------*/ -/* Method: attributes */ -/* Description: get our list of attributes. */ -/*----------------------------------------------------------------------------*/ - -::method attributes -if arg() > 0 then raise syntax 93.902 array (0) -return self~attr - - -/*----------------------------------------------------------------------------*/ -/* Method: ownerDocument */ -/* Description: get the owner document node of this node. */ -/*----------------------------------------------------------------------------*/ - -::method ownerDocument -expose ownerDocument -if arg() > 0 then raise syntax 93.902 array (0) -return ownerDocument - - -/*----------------------------------------------------------------------------*/ -/* Method: insertBefore */ -/* Description: insert a node in the child list before the specified child. */ -/*----------------------------------------------------------------------------*/ - -::method insertBefore -expose children -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg newChild, refChild -if refChild = .nil then do - children[children~items + 1] = newChild - return newChild - end --- find the reference node -do i = 1 to children~items - if children[i] = refChild then leave - end -xx = children~inseret(newChild, i - 1) -newChild~parentNode = self -return newChild - - -/*----------------------------------------------------------------------------*/ -/* Method: replaceChild */ -/* Description: replace a node in the child list. */ -/*----------------------------------------------------------------------------*/ - -::method replaceChild -expose children -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg newChild, oldChild -if oldChild = .nil then return .nil --- find the reference node -do i = 1 to children~items - if children[i] = refChild then leave - end -temp = children[i] -children[i] = newChild -newChild~parentNode = self -temp~parentNode = .nil -return temp - - -/*----------------------------------------------------------------------------*/ -/* Method: removeChild */ -/* Description: removes a node in the child list. */ -/*----------------------------------------------------------------------------*/ - -::method removeChild -expose children -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg oldChild -if oldChild = .nil then return .nil --- find the reference node -do i = 1 to children~items - if children[i] = refChild then leave - end -temp = children~remove(i) -temp~parentNode = .nil -return temp - - -/*----------------------------------------------------------------------------*/ -/* Method: appendChild */ -/* Description: appends a node in the child list. */ -/*----------------------------------------------------------------------------*/ - -::method appendChild -expose children -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg newChild -if newChild = .nil then return .nil -children[children~items + 1] = newChild -newChild~parentNode = self -return newChild - - -/*----------------------------------------------------------------------------*/ -/* Method: hasChildNodes */ -/* Description: returns .true if this nodes has child nodes. */ -/*----------------------------------------------------------------------------*/ - -::method hasChildNodes -expose children -if arg() > 0 then raise syntax 93.902 array (0) -if children~items > 0 then return .true -return .false - - -/*----------------------------------------------------------------------------*/ -/* Method: cloneNode */ -/* Description: returns a copy of this node. */ -/*----------------------------------------------------------------------------*/ - -::method cloneNode -if arg() > 1 then raise syntax 93.902 array (1) -if arg() = 1 then use arg deep -else deep = .false -temp = self~copy -temp~parentNode = .nil -if deep = .true then do - -- TODO: got a lot of work to do here, see spec - end -return temp - - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ /* Class: DocumentFragment */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -1987,3 +1932,30 @@ use arg nodeValue return + +::class DOMErrors +::constant HIERARCHY_REQUEST_ERR "An attempt was made to insert a node where it is not permitted." +::constant INDEX_SIZE_ERR "The index or size is negative, or greater than the allowed value." +::constant INUSE_ATTRIBUTE_ERR "An attempt is made to add an attribute that is already in use elsewhere." +::constant INVALID_ACCESS_ERR "A parameter or an operation is not supported by the underlying object." +::constant INVALID_CHARACTER_ERR "An invalid or illegal XML character is specified." +::constant INVALID_MODIFICATION_ERR "An attempt is made to modify the type of the underlying object." +::constant INVALID_STATE_ERR "An attempt is made to use an object that is not, or is no longer, usable." +::constant NAMESPACE_ERR "An attempt is made to create or change an object in a way which is incorrect with regard to namespaces." +::constant NOT_FOUND_ERR "An attempt is made to reference a node in a context where it does not exist." +::constant NOT_SUPPORTED_ERR "The implementation does not support the requested type of object or operation." +::constant NO_DATA_ALLOWED_ERR "Data is specified for a node which does not support data." +::constant NO_MODIFICATION_ALLOWED_ERR "An attempt is made to modify an object where modifications are not allowed." +::constant SYNTAX_ERR "An invalid or illegal string is specified." +::constant VALIDATION_ERR "A call to a method such as insertBefore or removeChild would make the Node invalid with respect to document grammar." +::constant WRONG_DOCUMENT_ERR "A node is used in a different document than the one that created it." +::constant TYPE_MISMATCH_ERR "The value type for this parameter name is incompatible with the expected value type." + +::constant BAD_BOUNDARYPOINTS_ERR "The boundary-points of a Range do not meet specific requirements." +::constant INVALID_NODE_TYPE_ERR "The container of a boundary-point of a Range is being set to either a node of an invalid type or a node with an ancestor of an invalid type." + +::method raiseError class + use arg message + + raise syntax 98.900 array(message) -- just raise this as a user execution error + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2009-05-23 22:45:30
|
Revision: 4725 http://oorexx.svn.sourceforge.net/oorexx/?rev=4725&view=rev Author: bigrixx Date: 2009-05-23 22:45:27 +0000 (Sat, 23 May 2009) Log Message: ----------- incremental checkin of DOM work Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2009-05-22 17:57:57 UTC (rev 4724) +++ incubator/orxutils/xml/xmldom.cls 2009-05-23 22:45:27 UTC (rev 4725) @@ -179,7 +179,7 @@ /* Method: length */ /* Description: get the number of items in the list. */ /*----------------------------------------------------------------------------*/ -::attribute length get +::method length expose nodes use strict arg return nodes~items @@ -195,6 +195,169 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: NodeList */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + + +::class DeepNodeList subclass NodeList +::method init + expose rootNode tagName changes nodes nsName + + use strict arg rootNode, tagName, nsName = .nil + nodes = .Array~new + changes = 0 + +-- lazy search for the matching nodes. This only fills in the cache +-- as far as the last valid requested position +::method item + expose rootNode changes nodes + use strict arg index + -- if the tree has changed, we need to restart this + if rootNode~changes \= changes then do + nodes = .array~new + changes = rootNode~changes + end + + currentSize = nodes~items + if index < currentSize then do + return nodes[index + 1] + end + else do + // we need to continue the traversal from the last node added + if currentSize == 0 then do + thisNode = rootNode + end + else do + thisNode = nodes[currentSize] + end + -- keep adding up to the one we're looking for + + do while index > currentSize + thisNode = self~nexMatchingElementAfter(thisNode) + if thisNode \= .nil then do + nodes~append(thisNode) + currentSize += currentSize + end + else do + // no more nodes available + leave + end + end + -- this is either the one we want or .nil + return thisNode + end + +::attribute length GET + expose nodes + use strict arg + -- this forces everything to be initialized + item(999999999) + return nodes~items + +::attribute makearray + expose nodes + use strict arg + -- this forces everything to be initialized + item(999999999) + return nodes~copy + +::method nextMatchingElementAfter private + expose rootNode tagName nsName + use arg current + + do while current \= nil + -- go down to the first child if it has one + if current~hasChildNodes then do + current = current~firstChild + end + -- no children and we're at the rootnode, so we + -- don't go up or to any siblings + else if current == rootNode do + return .nil + end + -- now try for a sibling of our current position + next = current~nextSibling + -- if we found one, then this is our next candidate + if next \= .nil then do + current = next + end + else do + next = .nil + -- now we step "up and to the right" for as many attempts as needed + -- or utnil we pop back to the root node + do while current \= rootNode + current = current~parentNode + next = current~nextSibling + if next \= .nil then do + leave + end + end + -- this is either a good node, or .nil + current = next + end + -- we have a candidate node, now make sure it matches what we're looking for + if current \= rootNode, current \= .nil, current~nodeType == .Node~ELEMENT_NODE then do + -- no namespace checking? We'll take any element node if the name is + -- "*" or it matches directly + if nsName == .nil then do + if tagName == "*" | current~tagName == tagName then do + return current + end + end + -- namespace qualified (which might also be "*") + else do + -- wildcard match on the tagname, so just check the namespace name + if tagName == "*" then do + -- wildcards on both, this is easy + if nsName == "*" then do + return current + end + else do + -- null string is a non-specific namepace request, which + -- matches only if the element does not have a namespace + if nsName == "" & current~namespaceURI == .nil then do + return current + end + -- requires an exact namespace match + else if nsName == current~namespaceURI + return current + end + end + end + -- non-wild card on the name + else do + -- if we have a name match, then see if the namespace + -- name also matches + if current~localName == tagName then do + -- ok, the local name matches, the ns rules are the + -- same as above + if nsName == "*" then do + return current + end + else do + -- null string is a non-specific namepace request, which + -- matches only if the element does not have a namespace + if nsName == "" & current~namespaceURI == .nil then do + return current + end + -- requires an exact namespace match + else if nsName == current~namespaceURI + return current + end + end + end + end + end + end + -- if we get here, we had a candidate, but it was not a match + -- just continue the tree walk + end + -- nothing found + return .nil + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: NamedNodeMap */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -218,16 +381,18 @@ use arg name if attributes == .nil then do - return 0 + return .nil end - do i = 1 to attributes~items - if attributes[i]~nodeName == name then do - return i + s = attributes~supplier + do while s~available + attr = s~item + if attr~nodeName == name then do + return s~index end end - return 0 + return .nil ::method findNamePointNS private @@ -235,41 +400,31 @@ use arg name, namespace if attributes == .nil then do - return 0 + return .nil end - do i = 1 to attributes~items - attr = attributes[i] + s = attributes~supplier + do while s~available + attr = s~item if namespace == .nil then do if attr~namespaceURI == .nil & name == attr~localName then do - return i + return s~index end if attr~localName == .nil & name == attr~nodeName then do - return i + return s~index end end else do if attr~namespaceURI == namespace & attr~localName == name then do - return i + return s~index end end end - return 0 + return .nil -::method removeAt private - expose attributes - use arg position - do i = position to attributes~items - 1 - attributes[i] = attributes[i + 1] - end - - -- this removes the last item - attributes~remove[i] - - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: NamedNodeMap */ @@ -332,13 +487,13 @@ index = self~findNamePoint(node~nodeName) previous = .nil - if i > 0 then do - previous = attributes[i] - attributes[i] = node + if index \= .nil then do + previous = attributes[index] + attributes[index] = node end else do if attributes == .nil then do - attributes = .array~new + attributes = .list~new end attributes~append(node) end @@ -358,20 +513,20 @@ index = self~findNamePointNS(node~localName, node~namespaceURI) previous = .nil - if i > 0 then do - previous = attributes[i] - attributes[i] = node + if index \= .nil then do + previous = attributes[index] + attributes[index] = node end else do -- we try again just based on the nodeName index = self~findNamePoint(node~nodeName) - if index > 0 then do - previous = attributes[i] - attributes[i] = node + if index > .nil then do + previous = attributes[index] + attributes[index] = node end else do if attributes == .nil then do - attributes = .array~new + attributes = .list~new end attributes~append(node) end @@ -392,9 +547,9 @@ index = self~findNamePoint(name) previous = .nil - if i > 0 then do - previous = attributes[i] - self~removeAt(i) + if index \= .nil then do + previous = attributes[index] + attributes~remove(index) end return previous @@ -404,16 +559,16 @@ /* Description: remove a named item. */ /*----------------------------------------------------------------------------*/ -::method removeNamedItem +::method removeNamedItemNS expose attributes use strict arg namespace, name index = self~findNamePointNS(name, namespace) previous = .nil - if i > 0 then do - previous = attributes[i] - self~removeAt(i) + if index \= .nil then do + previous = attributes[index] + attributes~remove(index) end return previous @@ -421,7 +576,7 @@ /* Method: cloneMap */ /* Description: perform a deep copy of this map object */ /*----------------------------------------------------------------------------*/ -::method clone +::method cloneMap expose attributes use strict arg owner newMap = .NamedNodeMap(owner) @@ -435,9 +590,9 @@ expose attributes use arg source if source \= .nil then do - attributes = source~copy - do i = 1 to attributes~items - attributes[i] = attributes[i]~cloneNode(.true) + attributes = .list~new + do attr over source + attributes~append(attr~cloneNode(.true) end end @@ -454,7 +609,7 @@ return .nil end else do - return attributes[position + 1] + return attributes~makearray[position + 1] end @@ -466,7 +621,7 @@ ::method length expose attributes use strict arg - if attributes != .nil then do + if attributes \== .nil then do return attributes~items end else do @@ -476,11 +631,12 @@ ::method makearray expose attributes use strict arg - return attributes~copy -- make sure this is a copy + return attributes~makearray -- make sure this is a copy ::method "[]" forward message("ITEM") +::attribute attributes PRIVATE @@ -526,6 +682,7 @@ childNodes = .NodeList~new self~owned = .false -- unowned until we are added as a child self~readonly = .false -- newly created nodes can be altered + self~firstChild = .false -- not attached yet, so can't be first ::ATTRIBUTE nodeName GET -- superclasses overrid @@ -538,6 +695,10 @@ ::ATTRIBUTE parentNode GET return .nil ::ATTRIBUTE childNodes GET + use strict arg + -- the nodes implement the NodeList methods directly, so + -- all we need to do is return ourself + return self -- superclasses override ::ATTRIBUTE firstChild GET return .nil @@ -597,6 +758,7 @@ -- private attributes used for the implementation ::ATTRIBUTE owned PRIVATE ::ATTRIBUTE readonly PRIVATE +::ATTRIBUTE isFirstChild PRIVATE -- default implementations designed to be overridden ::METHOD hasChildNodes @@ -714,49 +876,1015 @@ use strict arg key raise syntax 93.963 -- not supported --- The following are NodeList methods implemented by the node class. Enables --- nicer Rexx-style access /*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Node */ +/* Private methods */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::attribute ctr class private +::attribute id private + +-- methods of NodeList that the node implements directly. superclasses will +-- implement this more full + +/*----------------------------------------------------------------------------*/ /* Method: item */ /* Description: get a list item. */ /*----------------------------------------------------------------------------*/ ::method item - expose childNodes - forward to(childNodes) + use strict arg index + // always returns .nil + return .nil /*----------------------------------------------------------------------------*/ /* Method: length */ /* Description: get the number of items in the list. */ /*----------------------------------------------------------------------------*/ -::attribute length get - expose childNodes - forward to(childNodes) +::method length + use strict arg + -- always returns 0 ::method makearray - expose childNodes - forward to(childNodes) + use strict arg + // just an empty array + return .array~new(0) ::method "[]" + return message("ITEM") + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: ChildNode base type for nodes that can be children of other nodes */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "ChildNode" subclass Node +::method init + expose previousSibling nextSibling + forward class(super) continue + + previousSibling = .nil + nextSibling = .nil + + +::method cloneNode + use strict arg deep = .false + + newNode = self~init:super(deep) + // detach the new instance from the context + newNode~previousSibling = .nil + newNode~nextSibling = .nil + newNode~isFirstChild = .false + + return newNode + +::attribute parentNode GET + if self~isOwned then do + return self~ownerNode + end + else do + return .nil + end + +::attribute nextSibling GET +::attribute nextSibling SET PRIVATE + +::attribute previousSibling GET +::attribute previousSibling SET PRIVATE + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: ParentNode base type for nodes that can be parents of other nodes */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "ParentNode" extend ChildNode +::method init + expose firstChild lastChild ownerDocument childNodes + forward class(super) continue + + -- set this explicitly + use strict arg ownerDocument + self~clearChildNodes + +::method clearChildren private + expose firstChild lastChild childNodes + firstChild = .nil + lastChild = .nil + childNodes = 0 + +::method cloneNode + expose firstChild + use strict arg deep = .false + + newNode = self~cloneNode:super(deep) + newNode~clearChildNodes + -- if this is a deep copy, then we need to clone all of the children too + if deep then do + child = firstChild + do while child \= .nil + newNode~appendNode(child~cloneNode(.true)) + child = child.nextSibling + end + end + return newNode + +::attribute ownerDocument GET +::attribute ownerDocument SET private + expose ownerDocument firstChild + use strict arg doc + -- we need to set this at the higher levels too + self~"OWNERDOCUMENT":super(doc) + -- set this in each of the children too + child = firstChild + do while child \= .nil + child~ownerDocument = doc + child = child.nextSibling + end + +::method hasChildren + expose firstChild + use strict arg + return firstChild \= .nil + +::attribute firstChild GET +::attribute lastChild GET + +::method insertBefore + expose firstChild lastChild ownerDocument childNodes + use arg newChild, refChild, replace = .false + + -- this case is really a no-op, but we need to go through the steps + -- in case we need to signal events. + if newChild == refChild then do + refChild = refChild~nextSibling + self~removeChild(newChild) + self~insertBefore(newChild, refChild) + return newChild + end + + -- inform the owner that this is happening + ownerDocment~insertingNode(this, replace) + + -- make sure we've detached this node from any previous + -- parent node. + oldParent = newChild~parentNode + if oldParent \= .nil then do + oldParent~removeChild(newChild) + end + + -- set the new owner + newChild~ownerNode = self + newChild~isOwned = .true + + -- Now detach before and after + + -- first added child is easy + if firstChild == .nil then do + firstChild = newChild + lastChild = newChild + end + -- .nil is an append + else if refChild == .nil then do + lastChild~nextSibling = newChild + newChild~previousSibling = lastChild + newChild~nextSibling = .nil + lastChild = newChild + end + -- normal insertion + else do + -- insertion at the beginning, need to adjust + if refChild == firstChild then do + newChild~firstSibling = firstChild + newChild~previousSibling = .nil + firstChild~previousSibling = newChild + firstChild = newChild + end + -- insertion in the middle + else do + previousNode = refNode~previousSibling + previousNode~nextSibling = newChild + newChild~previousSibling = previousNode + newChild~nextSibling = refNode + refNode~previousSibling = newChild + end + end + -- bump the count of nodes + childNodes += 1 + + -- broadcast a change event + self~changed + -- inform the document of this update + ownerDocument~insertedNode(self, newChild, replace) + return newChild + +::method removeChild + expose firstChild lastChild ownerDocument childNodes + use strict arg oldChild replace = .false + + ownerDocument~removingNode(self, oldChild, replace) + + -- removing the first child + if oldChild == firstChild then do + firstChild = firstChild~nextSibling + firstChild~previousSibling = .nil + -- if this was the only child, then clear out everything + if lastChild == oldChild then do + lastChild = .nil + end + end + else do + previous = oldChild~previousSibling + next = oldChild~nextSibling + previous~nextSibling = next + // this could be the last child, so we might have to update that + if next == .nil then do + lastChild = previous + end + else do + -- close up the chaing + next~previousSibling = previous + end + end + + childNodes -= 1 + + oldChild~ownerNode = ownerDocument + oldChild~isOwned = .false + oldChild~nextSibling = .nil + oldChild~previousSibling = .nil + + -- note the change update + self~changed + + ownerDocument~removeNode(self, replace) + return oldChild + +::method replaceChild + expose ownerDocument + use strict arg newChild, oldChild + + self~insertBefore(newChild, oldChild, .true) + if newChild !== oldChild then do + removeChild(oldChild, true) + end + + ownerDocument.replacedNode(this) + return oldChild + +::method textContent + use strict arg + + child = self~firstChild + if child \== .nil then do + next = child~nextSibling + if next == .nil then do + if self~hasTextContent(child) then do + return child~textContent + end + else do + return "" + end + end + else do + buffer = .mutablebuffer~new + buildTextContent(buffer) + return buffer~string + end + end + return "" + +::method buildTextContext private + use arg buffer + child = self~firstChild + do while child \= .nil + if self~hasTextContent(child) then do + child~buildTextContext(buffer) + end + child = child~nextSibling + end + +::method hasTextContext private + use arg child + type = child~nodeType + if type \= .Node~COMMENT_NODE && - + child \= .Node~PROCESSING_INSTRUCTION_NODE && - + child \= .Node~TEXT_NODE -then do + return .false + end + + return \child~isIgnorableWhilespace + +::attribute textContent SET + use strict arg text + child = self~firstChild + do while child \= .nil + self~removeChild(child) + end + + -- create a text node and append + if text \= .nil, text \== "" then do + self~appendChild(self~ownerDocument~createTextNode(text) + end + +-- overrides for the NodeList methods +::attribute length GET expose childNodes - forward to(childNodes) message("ITEM") + use strict arg + return childNodes +::attribute item + expose firstNode childNodes + use strict arg index + if index < 0 || index >= childNodes then do + return .nil + end + child = firstChild + do while index > 0 + child = child~nextSibling + index -= 1 + end + return child + +::method makearray + expose firstNode childNodes + use strict arg + + result = .array~new(childNodes) + child = firstChild + do while child \= .nil + result~append(child) + child = child~nextSibling + end + + return result + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: Node */ -/* Private methods */ +/* Class: AttributeMap -- an implementation of NamedNodeMap that can deal */ +/* with member ownership issues */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::attribute ctr class private -::attribute id private +::class "AttributeMap" subclass NamedNodeMap +::method init + expose hasDefaults + use strict arg ownerNode, defaults = . nil + self~init:super(ownerNode) + hasDefaults = .false + -- if we have a defaults set, clone it and if we really added + -- something, marks us as having defaults + if defaults \= .nil then do + self~cloneContent(defaults) + if self~attributes \= .nil then do + hasDefaults = .true + end + end +::method setNamedItem + use strict arg attribute + -- replaceing an attribute with itself does nothing + if attribute~isOwned then do + return attribute + end + + attribute~ownerNode = self~ownerNode + attribute~isOwned = .true + + index = self~findNamePoint(attribute~nodeName, 0) + attributes = self~attributes + previous = .nil + if index \= .nil then do + previous = attributes[i] + attributes[i] = attribute + previous~ownerNode = self~ownerNode~ownerDocument + previous~isOwned = .false + previous~isSpecified = .true + end + else do + if attributes = .nil then do + attributes = .list~new + self~attributes = attributes + end + attributes~append(attribute) + end + + self~ownerNode~ownerDocument~setAttrNode(attribute, previous) + return previous + +::method setNamedItemNS + use strict arg attribute + -- replaceing an attribute with itself does nothing + if attribute~isOwned then do + return attribute + end + + attribute~ownerNode = self~ownerNode + attribute~isOwned = .true + + index = self~findNamePointNS(attribute~namespaceURI, attribute~nodeName) + attributes = self~attributes + previous = .nil + if index \= .nil then do + previous = attributes[i] + attributes[i] = attribute + previous~ownerNode = self~ownerNode~ownerDocument + previous~isOwned = .false + previous~isSpecified = .true + end + else do + if attributes = .nil then do + attributes = .list~new + self~attributes = attributes + end + attributes~append(attribute) + end + + self~ownerNode~ownerDocument~setAttrNode(attribute, previous) + return previous + +::method removeNamedItem + use strict arg name + + index = self~findNamePoint(name) + if index == .nil then do + return .nil + end + + return self~remove(self~attributes[index], index, true) + +::method removeNamedItemNS + use strict arg namespaceURI, name + + index = self~findNamePointNS(namspaceURI, name) + if index == .nil then do + return .nil + end + + return self~remove(self~attributes[index], index, true) + +::method remove private + use strict arg attr, index, addDefault = .false + + ownerDocument = self~ownerNode~ownderDocument + name = attr~nodeName + if attr~isIdAttribue then do + ownerDocument~removeIdentifier(attr~value) + end + + attributes = self~attributes + + setdefault = .false + -- do we have default attributes that we might need to revert to? + if self~hasDefaults & addDefault then do + defaults = ownerNode~defaultAttributes + if defaults \= .nil then do + defaultAttr = defaults~getNamedItem(name) + if defaultAttr \= .nil then do + newAttr = defaultAttr~cloneNode(.true) + -- the namespace uri comes from the deleted node, + -- not the default source value if the default + -- does not have a local name + if newAttr~localName \== .nil then do + newAttr~namespaceURI = attr~namespaceURI + end + newAttr~ownerNode = ownerNode + newAttr~isOwned = true + -- mark this as a default value + newAttr~isSpecified = false + attributes[index] = newAttr + setdefault = .true + -- if this is the id attribute, make sure the document knows + -- about this mapping + if attr~isIdAttribute then do + ownerDocument~putIdentifier(newAttr~nodeValue, ownerNode) + end + end + end + end + -- if we didn't end up setting a default, remove the node + if \setDefault then do + attributes~remove(index) + end + -- detach from usage + attr~ownerNode = .nil + attr~isOwned = .false + attr~isSpecified = .true + attr~isIdAttribute = false + + -- notify the document + ownerDocument~removedAttrNode(attr, ownerNode, name) + return attr + +::method cloneContent + use strict arg source + srcnodes = source~attributes + if srcnodes \= .nil then do + self~attributes = .List~new + do node over srcnodes + newNode = node~cloneNode(true) + newNode~ownerNode = self~ownerNode + newNode~isOwned = .true + self~attributes~append(newNode) + end + end + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: Element */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "Element" subclass Node public +::method init + expose nodeName attributes + use strict arg ownerDoc, nodeName + self~init:super(ownerDoc) + attributes = .nil + +::attribute nodeType GET + return .node~ELEMENT_NODE + +::attribute nodeName GET + +::attribute attributes GET + expose attributes + use strict arg + + if attributes == .nil then do + attributes = .AttributeMap~new(this, .nil) + end + + return attributes + +::attribute attributes SET private + +::method cloneNode + expose attributes + use strict arg deep = .false + newNode = self~cloneNode(deep) + + -- the attributes are always copied regardless of the deep flag + if attributes \= .nil then do + newNode~attributes = attributes~cloneMap(newNode) + end + + return newNode + +::attribute baseURI GET + use strict arg + return .nil + +::attribute ownerDocument SET private + expose attributes + use strict arg doc + + forward class(super) continue + -- also set this for all of the attributes + if attributes \= .nil then do + attributes~ownderDocument = doc + end + + +::method getAttribute + expose attributes + + use strict arg name + if attributes == .nil then do + return "" + end + + attr = attributes~getNamedItem(name) + if attr == .nil then do + return "" + end + else do + return attr~value + end + + +::method getAttributeNode + expose attributes + + use strict arg name + if attributes == .nil then do + return .nil + end + + return attributes~getNamedItem(name) + +::method getElementsByTagName + use strict arg tagname + // this version does a lazy search + return .DeepNodeList~new(this, tagname) + +::remove attributeNode + expose attributes + + use strict arg attr + + if attributes \= .nil then do + attributes~removeItem(attr) + end + +-- this is the same as the nodename for an element +::attribute tagname GET + expose nodeName + return nodeName + +::method removeAttribute + expose attributes + ust strict arg name + + if attrbutes \= .nil then do + attributes~removeNamedItem(name) + end + +::method removeAttributeNode + expose attributes + ust strict arg oldAttr + + if attrbutes \= .nil then do + attributes~removItem(oldAttr, .true) + end + +::method setAttribute + expose attributes + + use strict arg name, value + + attr = self~getAttributeName(name) + if newAttr == .nil then do + newAttr = getOwnerDocument().createAttribute(name) + + if attributes =- .nil then do + attributes = .AttributeMap~new(this) + end + + newAttr~nodeValue = value + attributes~setNamedItem(newAttr) + end + else do + newAttr~nodeValue = value + end + +::method setAttributeNode + expose attributes + + use strict arg newAttr + + if attributes == .nil then do + attributes = .AttributeMap~new(this) + end + + return attributes~setNamedItem(newAttr) + + +::method getAttributeNS + expose attributes + use strict arg namespaceURI, localName + + if attributes == .nil then do + return "" + end + + attr = attributes~getNamedItemNS(namespaceURI, localName) + if attr == .nil then do + return "" + end + else do + return attr~value + end + + +::method setAttributeNS + espose attributes + use strict arg namespaceURI, qualifiedName, value + + index = qualifiedName~pos(":") + if pos > 0 then do + parse var qualifiedName prefix ":" localName + end + else do + prefix = .nil + localName = qualifiedName + end + + newAttr = getAttributeNodeNS(namespaceURI, localName) + if newAttr == .nil then do + newAttr = self~getOwnerDocument ~createAttributeNS(namespaceURI, qualifiedName) + + if attributes == .nil then do + attributes = .AttributeMap~new(this) + end + + newAttr~nodeValue = value + attributes~setNameItemNS(newAttr) + end + else do + newAttr~name = qualifiedName + newAttr~nodeValue = value + end + +::method removeAttributeNS + expose attributes + use strict arg namespaceURI, localName + + if attributes == .nil then do + return + end + + attributes~removeNamedItemNS(namespaceURI, localName) + +::method getAttributeNodeNS + expose attributes + use strict arg namespaceURI, localName + + if attributes == .nil then do + return + end + + return attributes~getNamedItemNS(namespaceURI, localName) + +::method setAttributeNodeNS + expose attributes + use strict arg newAttr + + if attributes == .nil then do + return + end + + return attributes~setNamedItemNS(newAttr) + +::method hasAttributes + expose attributes + + if attributes == .nil then do + return .false + end + + return attributes~length > 0 + +::method hasAttribute + use strict arg name + return self~getAttributeNode(name) \= .nil + +::method hasAttributeNS + use strict arg namespaceURI, localName + + return self~getAttributeNodeNS(namespaceURI, localName) \= .nil + +::method getElementsByTagNameNS + use strict arg namespaceURI, localName + + return .DeepNodeList~new(this, localName, namespaceURI) + +::method setIdAttributeNode + use strict arg at, makeId + + at~isIdAttribute = makeId + if makeId then do + self~ownerDocument~putIdentifier(at~value, this) + end + else do + self~ownerDocument~removeIdentifier(at~value) + end + +::method setIdAttribute + use strict arg name, makeId + + at = self~getAttributeNode(name) + if at == .nil then do + return + end + + at~isIdAttribute makeId + if makeId then do + self~ownerDocument~putIdentifier(at~value, this) + end + else do + self~ownerDocument~removeIdentifier(at~value) + end + +::method setIdAttributeNS + use strict arg namespaceURI, localname, makeId + + at = self~getAttributeNodeNS(namspaceURI, localname) + if at == .nil then do + return + end + + at~isIdAttribute makeId + if makeId then do + self~ownerDocument~putIdentifier(at~value, this) + end + else do + self~ownerDocument~removeIdentifier(at~value) + end + +::attribute typeName GET + use strict arg + return .nil + +::attribute typeNamespace GET + use strict arg + return .nil + +::method isDerivedFrom + use strict arg nampeNamespace, typeName, deivationMethod + + return .false + +::attribute schemaTypeInfo GET + use strict arg + return self + +-- ElementTraversal methods + +::attribute childElementCount GET + use strict arg + count = 0 + child = self~firstElementChild + do while child \= .nil + count += 1 + child = child~nextElementSibling + end + + return count + +::attribute firstElementChild GET + use strict arg + node = self~firstChild + + do while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then do + return node + end + else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do + e = self~getFirstChildElement(node) + if e \= .nil then do + return e + end + end + node = node~nextSibling + end + return .nil + +::attribute lastElementChild GET + use strict arg + node = self~lastChild + + do while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then do + return node + end + else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do + e = self~getFirstChildElement(node) + if e \= .nil then do + return e + end + end + node = node~previousSibling + end + return .nil + + +::attribute nextElementSibling GET + use strict arg + node = self~nextLogicalSibling(self) + + do while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then do + return node + end + else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do + e = self~getFirstChildElement(node) + if e \= .nil then do + return e + end + end + node = node~nextLogicalSibling(node) + end + + +::attribute previousElementSibling GET + use strict arg + node = self~previousLogicalSibling(self) + + do while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then do + return node + end + else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do + e = self~getFirstChildElement(node) + if e \= .nil then do + return e + end + end + node = node~previousLogicalSibling(node) + end + +::method getFirstElementChild private + use strict arg node + + top = node + + do while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then do + return node + end + next = node~firstChild + do while next \= .nil + if node == top then do + leave; + end + next = node~nextSibling + if next \= .nil then do + node = node~parentNode + if node == .nil | node == top then do + return .nil + end + end + end + node = next + end + return .nil + +::method getLastElementChild private + use strict arg node + + top = node + + do while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then do + return node + end + next = node~lastChild + do while next \= .nil + if node == top then do + leave; + end + next = node~previousSibling + if next \= .nil then do + node = node~parentNode + if node == .nil | node == top then do + return .nil + end + end + end + node = next + end + return .nil + +::method getNextLogicalSibling private + use arg node + + next = node~nextSibling + + if next == .nil then do + parent = node~parentNode + do while parent \= .nil, parent~nodeType == .Node~ENTITY_REFERENCE_NODE + next = parent~nextSibling + if next \= .nil then do + leave + end + parent = parent~parentNode + end + end + + return next + +::method getPreviousLogicalSibling private + use arg node + + previous = node~previousSibling + + if previous == .nil then do + parent = node~parentNode + do while parent \= .nil, parent~nodeType == .Node~ENTITY_REFERENCE_NODE + previous = parent~previousSibling + if previous \= .nil then do + leave + end + parent = parent~parentNode + end + end + + return previous + + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: DocumentFragment */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2009-05-25 23:26:22
|
Revision: 4730 http://oorexx.svn.sourceforge.net/oorexx/?rev=4730&view=rev Author: bigrixx Date: 2009-05-25 23:26:14 +0000 (Mon, 25 May 2009) Log Message: ----------- incremental checkin of DOM work Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2009-05-25 01:30:39 UTC (rev 4729) +++ incubator/orxutils/xml/xmldom.cls 2009-05-25 23:26:14 UTC (rev 4730) @@ -145,8 +145,15 @@ expose nodes -- we're a read-only list...the owning node returns the list, we work off -- of a snapshot copy - use strict arg nodes - nodes = nodes~copy + use strict arg nodes = .nil + -- this is an empty node list if no list given + if nodes == .nil then do + nodes = .array~new(0) + end + else do + -- make a copy of this + nodes = nodes~copy + end /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -1159,7 +1166,7 @@ end return "" -::method buildTextContext private +::method buildTextContent private use arg buffer child = self~firstChild do while child \= .nil @@ -1404,7 +1411,7 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "Element" subclass Node public +::class "Element" subclass ParentNode public ::method init expose nodeName attributes use strict arg ownerDoc, nodeName @@ -1881,10 +1888,823 @@ return previous +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Attr */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "Attr" subclass Node +::init + expose value name textNode typeName + use strict arg ownerDocument, name + value = .nil + typeName = .nil + textNode = .nil + self~isSpecified = .false + self~hasStringValue = .true +::attribute ownerDocument SET private + expose value + use strict arg doc + forward class(super) continue + if \self~hasStringValue then do + child = value + do while child \= .nil + child~ownerDocument = doc + child = child~nextSibling + end + end + +::attribute idAttribute SET + use strict arg value + self~isIdAttribute = value + +::method isId + use strict arg + return self~isIdAttribute + +::method cloneNode + expose value + use strict arg deep = .false + + newNode = self~cloneNode:super(deep) + + if \self~hasStringValue then do + close~value = .nil + child = value + do while child \= .nil + newNode~appendChild(child~cloneNode(.true)) + child = child~nextSibling + end + end + + newNode~isSpecified = .true + return newNode + +::attribute nodeType GET + use strict arg + return .Node~ATTRIBUTE_NODE + +::attribute nodeName GET + expose name + use strict arg + return name + +::attribute nodeValue SET + forward message("VALUE=") +::attribute nodeValue GET + forward message("VALUE") + +::attribute typeName GET +::attribute typeNamespace GET + expose typeName + use strict arg + if typeName \= .nil then do + return "http://www.w3.org/TR/REC-xml" + end + else do + return .nil + end + +::attribute schemaTypeInfo + use strict arg + -- we provide all of our own type information directly + return this + +::attribute name GET + +::attribute value SET + expose value textNode + use strict arg newValue + + self~ownerElement + oldvalue = "" + + -- we might need to process an old value if it's a serious of text nodes + if value \= .nil then do + if self~ownerDocument~mutationEvents then do + if self~hasMutationEvents then do + -- if we have a string value and we need to + -- broadcast mutation events, then we need to + -- convert this into a text node for the event + if self~hasStringValue then do + oldValue = value + if textNode == .nil then do + textNode = self~ownerDocument~createTextNode(value) + end + else do + textNode~data = value + end + -- set the value to be a text node rather than a string + value = textNode + textNode~ownerNode = this + textNode~isOwned = .true + self~removeChild(textNode, true) + end + else do + oldValue = self~value + do while value \= .nil + self~removeChild(value, .true) + end + end + end + end + else do + if self~hasStringValue then do + oldValue = value + end + else do + -- discard any text children + oldValue = self~value + firstChild = value + firstChild ownerNode = self~ownerDocument + end + -- remove the existing value + value = .nil + end + end + + self~isSpecified = .true + if self~ownerDocument~mutationEvents then do + self~insertBefore(self~ownerDocument~createTextNode(newValue), .nil, .true) + self~hasStringValue = .false + self~ownerDocument~modifiedAttrValue(this, oldvalue) + end + else do + value = newValue + self~changed() + end + + if self~isIdAttribute & self~ownderElement \= .nil then do + self~ownerDocument~putIdentifier(newvalue, ownerElement) + end + +::attribute value GET + expose value + use strict arg + -- no set value is a null string + if value == .nil then do + return "" + end + -- if already a string, then set it directly + if value~isA(.String) then do + return value + end + + -- this is a potential chain of child nodes + firstChild = value + + if firstChild~nodeType == .Node~ENTITY_REFERENCE_NODE then do + data = firstChild~entryRefValue + end + else do + data = firstChild~nodeValue + end + -- no data at this point, return a null string + if data == .nil then do + return "" + end + + node = firstChild~nextSibling + -- if the only child node, we're done + if node == .nil then do + return data + end + + buffer = .mutableBuffer~new(data) + + do while node \= .nil + if firstChild~nodeType == .Node~ENTITY_REFERENCE_NODE then do + data = firstChild~entryRefValue + if data \= .nil then do + buffer~append(data) + end + end + else do + buffer~append(firstChild~nodeValue) + end + node = node~nextSibling + end + + return buffer~string + +::attribute element GET + use strict arg + + if self~isOwned then do + return self~ownerNode + end + else do + return .nil + end + +::attribute ownerElement GET + forward message("ELEMENT") + +::attribute specified GET + forward name("ISSPECIFIED") +::attribute specified SET + forward name("ISSPECIFIED=") + +::method hasChildNodes + expose value + use strict arg + return value \= .nil + +::method childNodes + -- we handle the node list methods directly + use strict arg + return self + +::method firstChild + expose value + use strict arg + self~makeChildNode + return value + +::method lastChild + expose value + use strict arg + + self~makeChildNode + + child = value + previous = .nil + + do while child \= .nil + previous = child + child = child~nextSibling + end + + return previous + +::method insertBefore + expose value + use strict arg newChild, refChild, replace = .false + + -- if this is a fragment, transfer each of the + -- children from the fragment to ourselves + if newChild~nodeType == .Node~DOCUMENT_FRAGMENT_MODE then do + do while newChild~hasChildNodes + self~insertBefore(newChild~firstChild, refChild) + end + return newChild + end + -- already here? This is a little silly, but the event model + -- requires us to remove it and the reinsert + if newChild == refChild then do + refChild = refChild~nextSibling + self~removeChild(newChild) + self~insertBefore(newChild, refChild) + return newChild + end + -- ensure if we just have a string value that it is converted into a text + -- node + self~makeChildNode + + self~ownerDocument~insertingNode(this, replace) + -- detach from any existing parent node + oldParent = newChild~parentNode + + if oldParent \= .nil then do + oldParent~removeChild(newNode) + end + + newNode~ownerNode = this + newNode~isOwned = .true + + firstChild = value + -- no existing value, this case is easy + if firstChild == .nil then do + value = newChild + end + else do + -- append operation? + if refNode == .nil then do + lastChild = self~lastChild + lastChild~nextSibling = newNode + newNode~previousSibling = lastChild + end + -- normal insertion + else do + if refChild == firstChild then do + newNode~nextSibling = firstChild + firstChild~previousSibling = newNode + newNode~previousSibling = .nil + value = newNode + end + else do + previous = refNode~previousSibling + newNode~nextSibling = refNode + previous~nextSibling = newNode + refNode~previousSibling = newNode + newNode~previousSibling = previous + end + end + end + + -- record the change + self~changed + + self~ownerDocument~insertedNode(this, newNode, replace) + + return newChild + +::method removeChild + expose value + use strict arg oldChild, replace = .false + + if value~isA(.string) then do + return .nil + end + + self~ownerDocument~removingNode(this, oldNode, replace) + + -- removing the first? + if oldNode == value then do + value = oldNode~nextSibling + if value \= .nil then do + value~previousSibling = .nil + end + end + else do + previous = oldNode~previousSibling + next = oldNode~nextSibling + previous~nextSibling = next + if next \= .nil then do + next~previousSibling = previous + end + end + + oldNode~ownerNode = self~ownerDocument + oldNode~isOwned = .false + oldNode~nextSibling = .nil + oldNode~previousSibling = .nil + + self~changed + + ownerDocument~removedNode(this, replace) + + return oldNode + +::method replaceChild + use strict arg newChild, oldChild + + self~makeChildNode + self~ownerDocument~replacingNode(self) + self~insertBefore(newChild, oldChild, .true) + if newChild \= oldChild then do + self~removeChild(oldChild, true) + end + + self~ownerDocument~repacingNode(self) + return oldChild + +-- NodeList methods +::attribute length GET + expose value + use strict arg + + if value~isA(.string) then do + return 1 + end + + child = value + length = 0 + do while child \= .nil + length += 1 + child = child~nextSibling + end + + return length + +::method item + expose value + use strict arg index + + if value~isA(.String) then do + if index \= 0 then do + return .nil + end + self~makeChildNode + return value + end + else do + if index < 0 then do + return .nil + end + node = value + do i = 0 to index while node \= .nil + node = node~nextSibling + end + return node + end + +::method isDerivedFrom + use strict arg typeNamespace, typeName, derivationMethod + return .false + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: CharacterData -- base class for all nodes that carry character data */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "CharacterData" subclass ChildNode +::method init + expose data + use strict arg ownerDocument, data + self~init:super(ownerDocument) + +::attribute childNodes GET + use strict arg + -- always returns an empty node list + return .NodeList~new + +::attribute nodeValue GET + expose data + use strict arg + return data + +::attribute nodeValue SET + expose data + use strict arg value, replace = .false + + oldValue = data + self~ownerDocument~modifyingCharacterData(self, replace) + + data = value + + self~ownerDocument~modifiedCharacterData(self, oldValue, value, replace) + +::attribute data GET +::attribute length GET + expose data + use strict arg + return data~length + +::method appendData + expose data + use strict arg newData + if newData == .nil then do + return + end + + self~setNodeValue(data||newData) + +::method deleteData + expose data + use strict arg offset, count, replace = .false + + tailLength = max(data~length - count - offset, 0) + if offset >= data~length then do + newData = data + end + else do + newData = data~delstr(offset + 1, count) + end + -- set the node value to the adjusted version + self~nodeValue = newData + + self~ownerDocument~deletedText(self, offset, count) + +::method insertData + expose data + use strict arg offset, newData, replace = .false + + if offset >= data~length then do + newValue = data + end + else do + newValue = date~insert(newData, offset +1) + end + + self~ownerDocument~deletedText(self, offset, data~length) + +::method replaceData + expose data + use strict arg offset, count, newData + + oldvalue = data + + self~ownerDocument~replacingData(self) + + -- this needs to be done as multiple operations to get all of the + -- events broadcast + self~deleteData(offset, count, .true) + self~insertData(offset, newData, .true) + + self~ownerDocument~replacedCharacterData(self, oldvalue, data) + +::method setData + forward message("NODEVALUE=") + +::method substringData + expose data + use strict arg offset, count + + return data~substring(offset + 1, count) + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Text -- a DOM text node */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "Text" subclass CharacterData + +::attribute nodeType GET + use strict arg + return .Node~TEXT_NODE + +::attribute nodeName GET + use strict arg + return "#text" + +::method getWholeText + use strict arg + + buffer = .mutablebuffer~new + data = self~data + if data \= .nil then do + buffer~append(data) + end + + self~getWholeTextBackward(self~previousSibling, buffer, self~parentNode) + self~getWholeTextForward(self~nextSibling, buffer, self~parentNode) + + return buffer~string + +::method getWholeTextForward + use arg node, buffer, parent + + processingEntity = .false + if parent \= .nil then do + processingEntity = parent~nodeType == .Node~ENTITY_REFERENCE_NODE + end + + do while node \= .nil + type= node~nodeType + // unwind the entity references as a unit + if type == .Node~ENTITY_REFERENCE_NODE then do + if self~getWholeTextForward(node~firstChild, buffer, node) then do + return .true + end + end + -- a text node, just add the text content to the buffer + else if type == .Node~TEXT_NODE | type = .Node~CDATA_SECTION_NODE do + node~buildTextContent(buffer) + end + else do + -- we're finished if we found a non-text node + return .true + end + node = node~nextSibling + end + + -- we've run through everything, but if we started with the child of an + -- entity reference, we need to check the siblings for additional logical + -- text nodes + if processingEntity then do + self~getWholeTextForward(parent~nextSibling, buffer, parent~parentNode) + return .true + end + + return .false + +::method getWholeTextBackward + use strict arg node, buffer, parent + + processingEntity = .false + if parent \= .nil then do + processingEntity = parent~nodeType == .Node~ENTITY_REFERENCE_NODE + end + + do while node \= .nil + type= node~nodeType + // unwind the entity references as a unit + if type == .Node~ENTITY_REFERENCE_NODE then do + if self~getWholeTextBackward(node~lastChild, buffer, node) then do + return .true + end + end + -- a text node, just add the text content to the buffer + else if type == .Node~TEXT_NODE | type = .Node~CDATA_SECTION_NODE do + node~insertTextContent(buffer) + end + else do + -- we're finished if we found a non-text node + return .true + end + node = node~previousSibling + end + + -- we've run through everything, but if we started with the child of an + -- entity reference, we need to check the siblings for additional logical + -- text nodes + if processingEntity then do + self~getWholeTextBackward(parent~previousSibling, buffer, parent~parentNode) + return .true + end + + return .false + +::method insertTextContent private + use arg buffer + content = self~nodeValue + if content \= .nil then do + buffer~insert(1, content) + end + +::method replaceWholeText + use strict arg content + + parent = self~parentNode + -- no content or a null string content, we just remove everything + if content == .nil | content == "" then do + -- just remove ourselves from the parent + if parent \= .nil then do + parent~removeChild(self) + end + return .nil + end + + self~data = content + currentNode = self + + previous = currentNode~previousSibling + do while previous \= .nil + -- remove any logically adjacent text or entity reference nodes + nodetype = previous~nodeType + if nodeType = .Node~TEXT_NODE | - + nodeType = .Node~CDATA_SECTION_NODE | - + nodeType = .Node~ENTITY_REFERENCE_NODE | - + then do + -- remove the node from the parent + parent~removeChild(previous) + end + else do + -- non-text node found, time to quit + leave + end + -- we keep pulling the previous sibling of the current + -- until we find a non-text node + previous = currentNode~previousSibling + end + + -- now remove the trailing siblings + next = currentNode~nextSibling + + do while next \= .nil + -- remove any logically adjacent text or entity reference nodes + nodetype = next~nodeType + if nodeType = .Node~TEXT_NODE | - + nodeType = .Node~CDATA_SECTION_NODE | - + nodeType = .Node~ENTITY_REFERENCE_NODE | - + then do + -- remove the node from the parent + parent~removeChild(next) + end + else do + -- non-text node found, time to quit + leave + end + -- we keep pulling the previous sibling of the current + -- until we find a non-text node + next = currentNode~nextSibling + end + + -- this is now the only text node + return currentNode + +::method splitText + expose data + use strict arg offset + + newText = self~ownerDocument~createTextNode(data~substr(offset + 1)) + self~nodeValue = data~substr(1, offset) + + -- now insert the new text node + parent = self~parentNode + if parentNode \= .nil then do + parentNode~insertBefore(newText, self~nextSibling) + end + + return newText + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Comment -- a comment node */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "Comment" subclass CharacterData PUBLIC +::attribute nodeType GET + use strict arg + return .Node~COMMENT_NODE + +::attribute nodeName get + use strict arg + return "#comment" + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Entity -- an entity value */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "Entity" subclass ParentNode PUBLIC +::method init + expose name publicId systemId XmlEncoding inputEncoding XMLversion notationName baseURI + use strict arg ownerDoc, name + self~init:super(ownerDoc) + publicId = .nil + systemId = .nil + XmlEncoding = .nil + inputEncoding = .nil + XmlVersion = .nil + notationName = .nil + baseURI = ,nil + +::attribute nodeType GET + use strict arg + return .Node~ENTITY_NODE + +::attribute nodeName GET + expose name + use strict arg + return name + +::attribute publicId +::attribute systemId +::attribute XmlVersion +::attribute XmlEncoding +::attribute inputEncoding +::attribute notationName +::attribute baseURI + +::class "EntityReference" subclass ParentNode +::method init + expose name baseURI + use strict arg ownerDoc, name + self~init:super(ownerDoc) + baseURI = .nil + +::attribute nodeType GET + use strict arg + return .Node~ENTITY_NODE + +::attribute nodeName GET + expose name + use strict arg + return name + +::attribute entityRefValue + use strict arg + + value = "" + firstChild = self~firstChild + if firstChild == .nil then do + return .nil + end + if firstChild~nodeType == .Node~ENTITY_REFERENCE_NODE then do + value = firstChild~entityRefValue + end + else if firstChild~nodeType == .Node~TEXT_NODE do + value = firstChild~nodeValue + end + else do + return .nil + end + + if firstChild~nextSibling == .nil then do + return value + end + else do + buffer = .mutablebuffer~new(value) + next = firstChild~nextSibling + do while next \= .nil + if next~nodeType == .Node~ENTITY_REFERENCE_NODE then do + value = next~entityRefValue + end + else if next~nodeType == .Node~TEXT_NODE do + value = next~nodeValue + end + else do + return .nil + end + buffer~append(value) + next = next~nextSibling + end + return buffer~string + end + + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: DocumentFragment */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2009-05-27 00:46:23
|
Revision: 4731 http://oorexx.svn.sourceforge.net/oorexx/?rev=4731&view=rev Author: bigrixx Date: 2009-05-27 00:39:51 +0000 (Wed, 27 May 2009) Log Message: ----------- incremental checkin of DOM work Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2009-05-25 23:26:14 UTC (rev 4730) +++ incubator/orxutils/xml/xmldom.cls 2009-05-27 00:39:51 UTC (rev 4731) @@ -49,36 +49,9 @@ /*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/* Class: DOMString */ -/* This class is here as a placeholder only as we do not support */ -/* unicode string, only ASCII strings. We can modify this class in */ -/* the future if we ever support unicode strings. */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -::class DOMString subclass string public - - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: DOMString */ -/* Private methods */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/* Class: DOMString */ -/* Public methods */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ /* Class: DOMImplementation */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -133,7 +106,52 @@ end return .false +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: CoreDocument */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "CoreDocument" subclass ParentNode +::method init + expose docType docElement encoding actualEncoding version standalone documentURI - + userdata identifiers domNormalizer configuration xpathEvaluator changes - + allowGrammerAccess errorChecking documentNumber nodeCounter nodeTable + use strict arg docType = .nil, grammarAccess = .false + self~init:super(.nil) + self~ownerDocument = self + docElement = .nil + encoding = .nil + actualEncoding = .nil + version = .nil + standalone = .false + documentURI = .false + userData = .nil + identifiers = .nil + domNormalizer = .nil + configuration = .nil + xpathEvaluator = .nil + changes = 0 + errorChecking = .true + documentNumber = 0 + nodeCounter = 0 + nodeTable = .nil + + -- if we have a document type, this gets appended as our first child + if docType \= .nil then do + docType~ownerDocument = self + appendChild(docType) + end + +::attribute ownerDocument GET + use strict arg + -- documents don't have an owner + return .nil + + + + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: NodeList */ @@ -2702,9 +2720,87 @@ end +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: CDATASection */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "CDATASection" subclass Text PUBLIC +::attribute nodeType GET + use strict arg + return .Node~CDATA_SECTION_NODE + +::attribute nodeName GET + use strict arg + return "#cdata-section" + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: Notation */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "Notation" subclass Node PUBLIC +::method init + expose name publicId systemId baseURI + use strict arg ownerDoc, name + self~init:super(ownerDoc) + + publicId = .nil + systemId = .nil + baseURI = .nil + +::attribute nodeType GET + use strict arg + return .Node~NOTATION_NODE + +::attribute nodeName GET + expose name + use strict arg + return name + +::attribute publicId +::attribute systemId +::attribute baseURI + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: ProcessingInstruction */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "ProcessingInstruction" subclass CharacterData PUBLIC +::method init + expose target + use strict arg ownerDocument, target, data + self~init:super(ownerDocument, data) + +::attribute nodeType GET + use strict arg + return .Node~PROCESSING_INSTRUCTION_NODE + +::attribute nodeName GET + expose target + use strict arg + return target + +::attribute target +::attribute data GET + forward message("NODEVALUE") +::attribute data SET + forward message("NODEVALUE=") +::attribute baseURI GET + use strict arg + return self~ownerNode~baseURI + + + + + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: DocumentFragment */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2009-06-06 16:12:43
|
Revision: 4769 http://oorexx.svn.sourceforge.net/oorexx/?rev=4769&view=rev Author: bigrixx Date: 2009-06-06 16:12:42 +0000 (Sat, 06 Jun 2009) Log Message: ----------- incremental checkin of xml dom work Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2009-06-05 14:31:02 UTC (rev 4768) +++ incubator/orxutils/xml/xmldom.cls 2009-06-06 16:12:42 UTC (rev 4769) @@ -148,10 +148,218 @@ -- documents don't have an owner return .nil +::attribute nodeType GET + use strict arg + return .Node~DOCUMENT_NODE +::attirbute nodeName GET + use strict arg + return "#document" +::method cloneNode + use strict arg deep = .false + newDoc = .CoreDocument~new + self~cloneDocument(newDoc, deep) + return newDoc +::method cloneDocument private + expose identifers, firstChild + use arg newDoc, deep + if deep then do + reversedIdentifers = .nil + if identifiers \= .nil then do + reversedIdentifiers = .table~new + -- create the table using the inverse look up logic + sup = identifiers~supplier + do while sup~available + reversedIdentifiers[sup~item] = sup~index + end + end + + -- now copy each of the children into the new document + child = firstChild + do while child \= .nil + newDoc~appendChild(newDoc~importDocNode(child, .true, .true, reversedIdentifers)) + end + end + + newDoc~allowGrammarAccess = self~allowGrammarAccess + newDoc~errorChecking = self~errorChecking + +::method insertBefore + expose docElement docType + use strict arg newChild, refChild + + type = newChild~nodeType + -- if this is a DocumentType node, then make ourselves the owner + if newChild~ownerDocument == .nil & newChild~isA(.DocumentType) then do + newChild~ownerDocument = self + end + -- do a normal insert + self~insertBefore:super(newChild, refChild) + -- we only have two types of children, so cache each of + -- type types + if type == .Node~ELEMENT_NODE then do + docElement = newChild + end + else if type == .Node~DOCUMENT_TYPE_NODE then do + docType = newChild + end + return newChild + +::method removeChild + expose docElement docType + use strict arg oldChild + + self~removeChild:super(oldChild) + + type = oldChild~ELEMENT_NODE + + if type = .Node~ELEMENT_TYPE then do + docElement = .nil + end + else if type = .Node~DOCUMENT_TYPE_NODE do + docType = .nil + end + return oldChild + +::method replaceChild + expose docElement docType + use strict arg newChild, oldChild + + -- if this is a DocumentType node, then make ourselves the owner + if newChild~ownerDocument == .nil & newChild~isA(.DocumentType) then do + newChild~ownerDocument = self + end + + self~replaceChild:super(newChild, oldChild) + + type = oldChild~ELEMENT_NODE + + if type = .Node~ELEMENT_TYPE then do + docElement = .newChild + end + else if type = .Node~DOCUMENT_TYPE_NODE do + docType = .newChild + end + return oldChild + +::attribute textContent GET + use strict arg + return .nil + +::attribute textContent SET + use strict arg value + -- this is a NOP + +::method getFeature + expose xpathEvaluator + use strict arg feature, version = .nil + + anyVersion = version == .nil | version == "" + + if feature~caselessEquals("+XPath") & (anyVersion | version == "3.0") then do + if xpathEvaluator == .nil then do + xpathEvaluator = .XPathEvaluator~new(self) + end + return xpathEvaluator + end + + return self~getFeature:super(feature, version) + +-- Document factory methods + +::method createAttribute + use strict arg name + return .Attr~new(self, name) + +::method createCDATASection + use strict arg data + return .CDATASection~new(self, data) + +::method createComment + use strict arg data + return .Comment~new(self, data) + +::method createDocumentFragment + use strict arg + return .DocumentFragment~new(self) + +::method createElement + use strict arg tagname + return .Element~new(self, tagname) + +::method createEntityReference + use strict arg name + return .EntityReference~new(self, name) + +::method createProcessingInstruction + use strict arg target, data + return .ProcessingInstruction~new(self, target, data) + +::method createTextNode + use strict arg data + return .Text~new(self, data) + +::attribute docType GET +::attribute documentElement GET + expose docElement + use strict arg + return docElement + +::method getElementsByTagName + use strict arg tagName + return .DeepNodeList~new(self, tagname) + +::method getImplementation + use strict arg + + return .DomImplementation~getDOMImplementation + +::attribute errorChecking +::attribute strictErrorChecking + +::attribute inputEncoding +::attribute xmlEncoding + +::attribute documentURI + +::method createDocumentType + use strict arg qualifiedName, publicID, systemID + + return .DocumentType~new(self, qualifiedName, publicID, systemID) + +::method createEntity + use strict arg name + return .Entity~new(self, name) + +::method createNotation + use strict arg name + return .Notation~new(self, name) + +::method importNode + use strict arg source, deep = .false + return self~importDocNode(source, deep, .false, .nil) + +::method importDocNode private + use strict arg source, deep, cloningDoc, reversedIdentifers + + newNode = .nil + type = source~nodeType + select + when type == .Node~ELEMENT_NODE then do + if source~localName == .nil then do + newElement = self~createElement(source~nodeName) + end + else do + newElement = self~create + end + end + end + + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: NodeList */ @@ -1431,11 +1639,86 @@ ::class "Element" subclass ParentNode public ::method init - expose nodeName attributes - use strict arg ownerDoc, nodeName - self~init:super(ownerDoc) + expose nodeName attributes namespaceURI localName type attributes = .nil + namespaceURI = .nil + localName = .nil + type = .nil + if arg() == 2 then do + use strict arg ownerDoc, nodeName + self~init:super(ownerDoc) + end + else if arg() == 3 then do + use strict arg ownerDoc, namespaceURI, nodeName + self~init:super(ownerDoc) + self~setName(nodeName) + end + else do + use strict arg ownerDoc, namespaceURI, nodeName, localName + self~init:super(ownerDoc) + end + +::method setName private + expose namespaceURI localName + use arg qname + -- null string is the same as not there + if namspaceURI == "" then do + namespaceURI = .nil + end + + colon1 = qname~pos(":") + colon2 = qname~lastPos(":") + -- no prefix + if colon1 == 0 then do + -- local name and qualified name are the same + localName = qname + end + else do + parse var qname localName (colon1) (colon2 + 1) localName + end + +-- support for the Document renameNode method +::method rename + expose nodeName namespaceURI + use strict arg uri, name = .nil + if name == .nil then do + nodeName = uri + end + else do + nodeName = name + namespaceURI = uri + self~setName(name) + end + +-- override for default method +::attribute namespaceURI GET +-- get the prefix from the node name +::attribute prefix GET + expose nodeName + index = nodeName~pos(":") + if index > 0 then do + return nodeName~substr(1, index - 1) + end + else do + return .nil + end + +::attribute prefix SET + expose nodeName localName + use strict arg prefix + + -- we're either adding or replacing the prefix + if prefix \= "" then do + nodeName = prefix":"localName + end + -- or removing it entirely + else do + nodeName = localName + end + +::attribute localName GET + ::attribute nodeType GET return .node~ELEMENT_NODE @@ -1717,17 +2000,37 @@ end ::attribute typeName GET + expose type use strict arg - return .nil + if type \= .nil then do + return type~typeName + end + else do + return .nil + end ::attribute typeNamespace GET + expose type use strict arg - return .nil + if type \= .nil then do + return type~namespace + end + else do + return .nil + end ::method isDerivedFrom - use strict arg nampeNamespace, typeName, deivationMethod + expose type + use strict arg typeNamespace, typeName, derivationMethod + if type \= .nil then do + return type~isDOMDerivedFrom(typeNamespace, typeName, derivationMethod) + end + else do + return .false + end - return .false +-- set/retrieve type directly +::attribute type ::attribute schemaTypeInfo GET use strict arg @@ -1914,14 +2217,89 @@ ::class "Attr" subclass Node ::init - expose value name textNode typeName - use strict arg ownerDocument, name + expose value name textNode namespaceURI localName type value = .nil - typeName = .nil + type = .nil textNode = .nil + namespaceURI = .nil + localName = .nil + if arg() == 2 then do + use strict arg ownerDocument, name + self~init:super(ownerDoc) + end + else if arg() == 3 then do + use strict arg ownerDoc, namespaceURI, nodeName + self~init:super(ownerDoc) + self~setName(nodeName) + end + else do + use strict arg ownerDoc, namespaceURI, nodeName, localName + self~init:super(ownerDoc) + end + self~init:super(ownerDocument) self~isSpecified = .false self~hasStringValue = .true +::method setName private + expose namespaceURI localName + use arg qname + -- null string is the same as not there + if namspaceURI == "" then do + namespaceURI = .nil + end + + colon1 = qname~pos(":") + colon2 = qname~lastPos(":") + -- no prefix + if colon1 == 0 then do + -- local name and qualified name are the same + localName = qname + end + else do + parse var qname localName (colon1) (colon2 + 1) localName + end + +-- support for the Document renameNode method +::method rename + expose nodeName namespaceURI + use strict arg uri, name = .nil + if name == .nil then do + nodeName = uri + end + else do + nodeName = name + namespaceURI = uri + self~setName(name) + end + +-- override for default method +::attribute namespaceURI GET +-- get the prefix from the node name +::attribute prefix GET + expose nodeName + index = nodeName~pos(":") + if index > 0 then do + return nodeName~substr(1, index - 1) + end + else do + return .nil + end + +::attribute prefix SET + expose nodeName localName + use strict arg prefix + + -- we're either adding or replacing the prefix + if prefix \= "" then do + nodeName = prefix":"localName + end + -- or removing it entirely + else do + nodeName = localName + end + +::attribute localName GET + ::attribute ownerDocument SET private expose value use strict arg doc @@ -1974,8 +2352,46 @@ ::attribute nodeValue GET forward message("VALUE") + ::attribute typeName GET + expose type + use strict arg + if type \= .nil then do + if type~isA(.String) then do + return type + end + else do + return type~typeName + end + end + else do + return .nil + end + ::attribute typeNamespace GET + expose type + use strict arg + if type \= .nilthen do + if \type~isA(.String) then do + return type~namespace + end + else do + return "http://www.w3.org/TR/REC-xml"; + end + end + return .nil + +::method isDerivedFrom + expose type + use strict arg typeNamespace, typeName, derivationMethod + if type \= .nil, \type~isA(.String) then do + return type~isDOMDerivedFrom(typeNamespace, typeName, derivationMethod) + end + return .false + +-- set/retrieve type directly +::attribute type +::attribute typeNamespace GET expose typeName use strict arg if typeName \= .nil then do This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2009-06-17 00:10:37
|
Revision: 4805 http://oorexx.svn.sourceforge.net/oorexx/?rev=4805&view=rev Author: bigrixx Date: 2009-06-17 00:10:36 +0000 (Wed, 17 Jun 2009) Log Message: ----------- incremental checkin Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2009-06-16 23:57:24 UTC (rev 4804) +++ incubator/orxutils/xml/xmldom.cls 2009-06-17 00:10:36 UTC (rev 4805) @@ -169,7 +169,7 @@ if deep then do reversedIdentifers = .nil if identifiers \= .nil then do - reversedIdentifiers = .table~new + reversedIdentifiers = .directory~new -- create the table using the inverse look up logic sup = identifiers~supplier do while sup~available @@ -274,6 +274,16 @@ use strict arg name return .Attr~new(self, name) +::method createAttributeNS + if arg() == 2 then do + use strict arg namespaceURI, qualifiedName + return .Attr~new(self, namespaceURI, qualifiedName) + end + else do + use strict arg namespaceURI, qualifiedName, localName + return .Attr~new(self, namespaceURI, qualifiedName, localName) + end + ::method createCDATASection use strict arg data return .CDATASection~new(self, data) @@ -290,6 +300,16 @@ use strict arg tagname return .Element~new(self, tagname) +::method createElementNS + if arg() == 2 then do + use strict arg namespaceURI, qualifiedName + return .Element~new(self, namespaceURI, qualifiedName) + end + else do + use strict arg namespaceURI, qualifiedName, localName + return .Element~new(self, namespaceURI, qualifiedName, localName) + end + ::method createEntityReference use strict arg name return .EntityReference~new(self, name) @@ -312,6 +332,10 @@ use strict arg tagName return .DeepNodeList~new(self, tagname) +::method getElementsByTagNameNS + use strict arg namespaceURI, localName + return .DeepNodeList~new(self, namespaceURI, localName) + ::method getImplementation use strict arg @@ -343,7 +367,8 @@ return self~importDocNode(source, deep, .false, .nil) ::method importDocNode private - use strict arg source, deep, cloningDoc, reversedIdentifers + expose identifiers + use strict arg source, deep, cloningDoc, reversedIdentifiers newNode = .nil type = source~nodeType @@ -353,13 +378,344 @@ newElement = self~createElement(source~nodeName) end else do - newElement = self~create + newElement = self~createElementNS(source~namespaceURI, source~nodeName) end + -- we need to copy the attributes for the element here...other + -- children are handled below + sourceAttrs = source~attributes + if sourceAttrs \= .nil then do + do attr over sourceAttrs + if attr~isSpecified | cloningDoc then do + -- if we're just importing, ignore the default attributes. + newAttr = self~importNode(attr, .true, cloningDoc, reversedIdentifiers) + if attr~localName == .nil then do + newElement~setAttributeNode(newAttr) + end + else do + newElement~setAttributeNodeNS(newAttr) + end + end + end + end + -- have a reversed identifer table? We need to check if + -- the element has an identifier and fix this up + if reversedIdentifiers \= .nil then do + elementId = reversedIdentifers[source] + if elementId \= .nil then do + if identifiers == .nil then do + identifers = .table~new + end + identifiers[elementId] = newElement + end + end + newNode = newElement end + when type == .Node~ATTRIBUTE_NODE then do + if source~localName == .nil then do + newNode = self~createAttribute(source~nodeName) + end + else do + newNode = self~createAttributeNS(source~namespaceURI, source~nodeName) + end + -- we'll do a deep copy, unless this can be avoided in the simple + -- cases + deep = .true + -- if we have a string value, we can just copy that and + -- avoid doing the deep copy + if attr~hasStringValue then do + newNode~value = attr~value + deep = .false + end + end + when type == .Node~TEXT_NODE then do + newNode = self~createTextNode(source~nodeValue) + end + when type == .Node~CDATA_SECTION_NODE then do + newNode = self~createCDATASection(source~nodeValue) + end + when type == .Node~ENTITY_REFERENCE_NODE then do + newNode = self~createEntityReference(source~nodeName) + -- createEntityReference copies the subtree, so + -- disable the deep copy operation + deep = .false + end + when type == .Node~ENTITY_NODE then do + newNode = self~createEntity(source~nodeName) + newNode~publicId = source~publicId + newNode~systemId = source~systemId + newNode~notationName = source~notationName + -- the children need to be copied also...to do this, + -- we need to make the entity writeable + newNode = readOnly = .false + end + when type == .Node~PROCESSING_INSTRUCTION_NODE then do + newNode = self~createProcessingInstruction(source~nodeName, source~nodeValue) + end + when type == .Node~COMMENT_NODE then do + newNode = self~createComment(source~nodeValue) + end + when type == .Node~DOCUMENT_TYPE_NODE then do + newNode = self~createDocumentType(source~nodeName, source~publicId, source~systemId) + newNode~internalSubset = source~internalSubset + sourceMap = source~entities + newMap = newNode~entities + -- copy all of the entities, if thee are any + if sourceMap \= .nil then do + do item over sourceMap + newMap~setNamedItem(self~importNode(item, .true, .true, reversedIdentifers) + end + end + sourceMap = source~notations + newMap = newNode~notations + -- copy all of the notations, if thee are any + if sourceMap \= .nil then do + do item over sourceMap + newMap~setNamedItem(self~importNode(item, .true, .true, reversedIdentifers) + end + end + end + when type == .Node~DOCUMENT_FRAGMENT_NODE then do + newNode = self~createDocumentFragment + end + when type == .Node~NOTATION_NODE then do + newNode = self~createNotation(source~nodeName) + newNode~publicId = source~publicId + newNode~systemId = source~systemId + end + when type == .Node~DOCUMENT_NODE then do + .DomErrors~raiseError(.DomErrors~NOT_SUPPORTED_ERR) + end + otherwise do + .DomErrors~raiseError(.DomErrors~NOT_SUPPORTED_ERR) + end end + -- do we need to copy the child nodes too? + if deep then do + child = source~firstChild + do while child \= .nil + newNode~appendChild(self~importNode(child, .true, cloningDoc, reversedIdentifiers) + end + end + if newNode~nodeType == .Node~ENTITY_NODE then do + newNode~readOnly = .true + end + return newNode +::method adoptNode + expose docType + use strict arg source + + if source == .nil then do + return .nil + end + + type = source~nodeType + + select + when type == .Node~ATTRIBUTE_NODE then do + -- detach from the owner if this is owned + if source~ownerDocument \= .nil then do + source~ownerElement~removeAttributeNode(source) + end + -- this is now specified, since it's no longer + -- derived from a default associated with an element + source~specified = .true + -- change the owner + source~ownerDocument = self + end + when type == .Node~ENTITY_NODE | type == .Node~NOTATION_NODE then do + .DomErrors~raiseError(.DomErrors~NO_MODIFICATION_ALLOWED_ERR) + end + when type == .Node~DOCUMENT_NODE | type == .Node~DOCUMENT_TYPE_NODE then do + .DomErrors~raiseError(.DomErrors~NOT_SUPPORTED_ERR) + end + when type == .Node~ENTITY_REFERENCE_NODE then do + parent = source~parentNode + if parent \= .nil then do + parent~removeChild(source) + end + -- remove the replacement value + child = source~firstChild + do while child \= .nil + source~removeChild(child) + child = source~firstChild + end + + source~ownerDocument = self + if docType \= .nil then do + entities = docType~entities + entityNode = entities~getNamedItem(source~nodeName) + if entityNode \= .nil then do + child = entityNode~firstChild + do while child \= .nil + newChild = child~cloneNode(.true) + source~appendChild(newChild) + child = child~nextSibling + end + end + end + end + when type == .Node~ELEMENT_NODE then do + parent = source~parentNode + if parent \= .nil then do + parent~removeChild(source) + end + source~ownerDocument = self + end + otherwise do + parent = source~parentNode + if parent \= .nil then do + parent~removeChild(source) + end + source~ownerDocument = self + end + end + -- return the adopted node + return source + +::method getElementById + use strict arg id + + return self~getIdentifer(id) + +::method getIdentifier + expose identifers + use strict arg id + if identifers == .nil then do + return .nil + end + + element = identifers[id] + if element \= .nil then do + parent = element~parentNode + do while parent \= .nil + if parent == self then do + return element + end + parent = parent~parentNode + end + end + + return .nil + +::method clearIdentifiers private + expose identifers + if identifers \= .nil then do + identifiers~empty + end + +::method putIdentifier + expose identifiers + use strict arg name, element + + if element == .nil then do + self~removeIdentifier(name) + end + else do + if identifiers == .nil then do + identifiers = .directory~new + end + identifers[name] = element + end + +::method removeIdentifier + expose identifiers + use strict arg name + if identifiers == .nil then do + return + end + + identifers~remove(name) + +::method identifiers + if identifiers == .nil then do + identifiers = .directory~new + end + + return identifers~allIndexes + +::method copy + use strict arg + newDoc = self~copy:super() + + newDoc~docType = .nil + newDoc~docElement = .nil + return newDoc + +::method changed + expose changes + changes += 1 + +::method addEventListener + use strict arg node, type, listener, useCapture + -- this is a nop + +::method removeEventListener + use strict arg node, type, listener, useCapture + +::method copyEventListeners + use strict arg source, target + +::method dispatchEvent + use strict arg node, event + +::method replacedText + use strict arg node + +::method deletedText + use strict arg node, offset, count + +::method insertedText + use strict arg node, offset, count + +::method modifyingCharacterData + use strict arg node, replace + +::method modifiedCharacterData + use strict arg node, oldValue, value, replace + +::method insertingNode + use strict arg node, replace + +::method insertedNode + use strict arg node, newInternal, replace + +::method removingNode + use strict arg node, oldChild, replace + +::method removedNode + use strict arg node, replace + +::method replacingNode + use strict arg node + +::method replacedNode + use strict arg node + +::method replacingData + use strict arg node + +::method replacedCharacterData + use strict arg node, oldValue, value + +::method modifiedAttrValue + use strict arg attr, oldValud + +::method setAttrNode + use strict arg attr, previous + +::method removedAttrNode + use strict arg attr, oldOwner, name + +::method renamedAttrNode + use strict arg oldAttr, newAttr + +::method renamedElement + use strict arg oldElement, newElement + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: NodeList */ @@ -2371,7 +2727,7 @@ ::attribute typeNamespace GET expose type use strict arg - if type \= .nilthen do + if type \= .nil then do if \type~isA(.String) then do return type~namespace end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-06-14 14:59:12
|
Revision: 7897 http://oorexx.svn.sourceforge.net/oorexx/?rev=7897&view=rev Author: bigrixx Date: 2012-06-14 14:59:05 +0000 (Thu, 14 Jun 2012) Log Message: ----------- Some general cleanup Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-06-14 03:14:46 UTC (rev 7896) +++ incubator/orxutils/xml/xmldom.cls 2012-06-14 14:59:05 UTC (rev 7897) @@ -66,9 +66,8 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::method ver private +::attribute ver get private - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: DOMImplementation */ @@ -83,28 +82,28 @@ /*----------------------------------------------------------------------------*/ ::method init -use strict arg -self~ver = .directory~new -self~ver['1.0'] = .directory~new -return + expose ver + use strict arg + ver = .directory~new + ver['1.0'] = .directory~new - /*----------------------------------------------------------------------------*/ /* Method: hasFeature */ /* Description: return boolean indicator for a specified feature. */ /*----------------------------------------------------------------------------*/ ::method hasFeature -use strict arg feature, version = (.nil) -if version = .nil then do featureset over self~ver - if featureset[feature] <> .nil then return .true - end - end -else do - featureset = self~feature[version] - if self~featureset[feature] <> .nil then return .true - end -return .false + expose ver + use strict arg feature, version = (.nil) + if version = .nil then do featureset over ver + if featureset[feature] <> .nil then return .true + end + end + else do + featureset = self~feature[version] + if featureset <> .nil, featureset[feature] <> .nil then return .true + end + return .false /*----------------------------------------------------------------------------*/ @@ -121,7 +120,7 @@ use strict arg nodes = .nil -- this is an empty node list if no list given if nodes == .nil then do - nodes = .array~new(0) + nodes = .array~new end else do -- make a copy of this @@ -173,34 +172,6 @@ return message("ITEM") - - - - - - - - - - - - - - - - - - - - - - - - - - - - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: DocumentFragment */ @@ -232,9 +203,8 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() > 0 then raise syntax 93.902 array (0) -self~nodeType = 11 -return + use strict arg + self~nodeType = 11 /*----------------------------------------------------------------------------*/ @@ -294,7 +264,7 @@ /*----------------------------------------------------------------------------*/ ::method documentElement -return self~children[0] + return self~children[0] /*----------------------------------------------------------------------------*/ @@ -429,15 +399,11 @@ /*----------------------------------------------------------------------------*/ /* Method: specified= */ -/* Description: return the specified indicator. */ +/* Description: only the set method is private */ /*----------------------------------------------------------------------------*/ -::method specified -expose specified -use arg specified -return +::attribute specified private set - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Attr */ @@ -452,24 +418,20 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg name -self~nodeName = name -self~nodeType = 2 -self~nodeValue = '' -self~specified = .false -return + use strict arg name + self~nodeName = name + self~nodeType = 2 + self~nodeValue = '' + self~specified = .false - /*----------------------------------------------------------------------------*/ /* Method: name */ /* Description: return the node name. */ /*----------------------------------------------------------------------------*/ -::method name -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeName +::attribute name get + use strict arg + return self~nodeName /*----------------------------------------------------------------------------*/ @@ -477,20 +439,16 @@ /* Description: return the specified indicator. */ /*----------------------------------------------------------------------------*/ -::method specified -expose specified -if arg() > 0 then raise syntax 93.902 array (0) -return specified +::attribute specified get - /*----------------------------------------------------------------------------*/ /* Method: value */ /* Description: return the node value. */ /*----------------------------------------------------------------------------*/ -::method value -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeValue +::attribute value get + use strict arg + return self~nodeValue /*----------------------------------------------------------------------------*/ @@ -498,13 +456,11 @@ /* Description: set the node value. */ /*----------------------------------------------------------------------------*/ -::method 'value=' -use arg newval -self~nodeValue = newval -self~specified = .true -return +::attribute value set + use arg newval + self~nodeValue = newval + self~specified = .true - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Element */ @@ -536,24 +492,20 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg tagname -self~nodeName = tagname -self~nodeType = 1 -self~nodeValue = .nil -self~attr = .NamedNodeList~new -return + use strict arg tagname + self~nodeName = tagname + self~nodeType = 1 + self~nodeValue = .nil + self~attr = .NamedNodeList~new - /*----------------------------------------------------------------------------*/ /* Method: tagname */ /* Description: return the node name. */ /*----------------------------------------------------------------------------*/ -::method tagname -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeName +::attribute tagname get + use strict arg + return self~nodeName /*----------------------------------------------------------------------------*/ @@ -562,10 +514,8 @@ /*----------------------------------------------------------------------------*/ ::method getAttribute -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg name -return self~attributes[name]~nodeValue + use strict arg name + return self~attributes[name]~nodeValue /*----------------------------------------------------------------------------*/ @@ -574,36 +524,26 @@ /*----------------------------------------------------------------------------*/ ::method setAttribute -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg name, value -self~attributes[name]~nodeValue = value -return + use strict arg name, value + self~attributes[name]~nodeValue = value - /*----------------------------------------------------------------------------*/ /* Method: removeAttribute */ /* Description: remove an attribute value. */ /*----------------------------------------------------------------------------*/ ::method removeAttribute -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg name -x = self~attributes[name]~nodeValue = '' -return + use strict arg name + self~attributes[name]~nodeValue = '' - /*----------------------------------------------------------------------------*/ /* Method: getAttributeNode */ /* Description: get an attribute node. */ /*----------------------------------------------------------------------------*/ ::method getAttributeNode -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg name -return self~attribute[name] + use strict arg name + return self~attributes[name] /*----------------------------------------------------------------------------*/ @@ -612,11 +552,9 @@ /*----------------------------------------------------------------------------*/ ::method setAttributeNode -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg newAttr -self~attributes[newAttr~nodeName] = newAttr -return newAttr + use strict arg newAttr + self~attributes[newAttr~nodeName] = newAttr + return newAttr /*----------------------------------------------------------------------------*/ @@ -625,11 +563,9 @@ /*----------------------------------------------------------------------------*/ ::method removeAttributeNode -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg oldAttr -self~attributes~remove(oldAttr~nodeName) -return oldAttr + use strict arg oldAttr + self~attributes~remove(oldAttr~nodeName) + return oldAttr /*----------------------------------------------------------------------------*/ @@ -638,10 +574,8 @@ /*----------------------------------------------------------------------------*/ ::method getElementsByTagName -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg name -return self~getElementsByName(name) + use strict arg name + return self~getElementsByName(name) /*----------------------------------------------------------------------------*/ @@ -650,9 +584,9 @@ /*----------------------------------------------------------------------------*/ ::method normalize -if arg() > 0 then raise syntax 93.902 array (0) --- TODO: a lot of work to do here, see the spec -return + use strict arg + -- TODO: a lot of work to do here, see the spec + return /*----------------------------------------------------------------------------*/ @@ -686,13 +620,10 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg data -self~nodeName = '#text' -self~nodeType = 3 -self~nodeValue = data -return + use strict arg data + self~nodeName = '#text' + self~nodeType = 3 + self~nodeValue = data /*----------------------------------------------------------------------------*/ @@ -726,15 +657,11 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg data -self~nodeName = '#comment' -self~nodeType = 8 -self~nodeValue = data -return + use strict arg data + self~nodeName = '#comment' + self~nodeType = 8 + self~nodeValue = data - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: CDATASection */ @@ -766,15 +693,11 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg data -self~nodeName = '#cdata-section' -self~nodeType = 4 -self~nodeValue = data -return + use strict arg data + self~nodeName = '#cdata-section' + self~nodeType = 4 + self~nodeValue = data - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: ProcessingInstruction */ @@ -806,15 +729,11 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg target, data -self~nodeName = target -self~nodeType = 7 -self~nodeValue = data -return + use strict arg target, data + self~nodeName = target + self~nodeType = 7 + self~nodeValue = data - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: EntityReference */ @@ -846,15 +765,11 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg name -self~nodeName = name -self~nodeType = 5 -self~nodeValue = .nil -return + use strict arg name + self~nodeName = name + self~nodeType = 5 + self~nodeValue = .nil - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: CharacterData */ @@ -886,18 +801,16 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() > 0 then raise syntax 93.902 array (0) -return + use strict arg - /*----------------------------------------------------------------------------*/ /* Method: data */ /* Description: return the node value. */ /*----------------------------------------------------------------------------*/ -::method data -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeValue +::attribute data get + use strict arg + return self~nodeValue /*----------------------------------------------------------------------------*/ @@ -905,22 +818,18 @@ /* Description: set the node value. */ /*----------------------------------------------------------------------------*/ -::method 'data=' -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg data -self~nodeValue = data -return +::attribute data set + use strict arg data + self~nodeValue = data - /*----------------------------------------------------------------------------*/ /* Method: length */ /* Description: return the node value length. */ /*----------------------------------------------------------------------------*/ ::method length -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeValue~length + use strict arg + return self~nodeValue~length /*----------------------------------------------------------------------------*/ @@ -929,10 +838,8 @@ /*----------------------------------------------------------------------------*/ ::method substringData -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg offset, count -return self~nodeValue~substr(offset, count) + use strict arg offset, count + return self~nodeValue~substr(offset, count) /*----------------------------------------------------------------------------*/ @@ -941,51 +848,36 @@ /*----------------------------------------------------------------------------*/ ::method appendData -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg data -self~nodeValue = self~nodeValue || data -return + use strict arg data + self~nodeValue = self~nodeValue || data - /*----------------------------------------------------------------------------*/ /* Method: insertData */ /* Description: insert data into the node value. */ /*----------------------------------------------------------------------------*/ ::method insertData -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg offset, data -self~nodeValue~insert(data, offset - 1) -return + use strict arg offset, data + self~nodeValue~insert(data, offset - 1) - /*----------------------------------------------------------------------------*/ /* Method: deleteData */ /* Description: delete data from the node value. */ /*----------------------------------------------------------------------------*/ ::method deleteData -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg offset, count -x = self~nodeValue~delstr(offset, count) -return + use strict arg offset, count + self~nodeValue~delstr(offset, count) - /*----------------------------------------------------------------------------*/ /* Method: replaceData */ /* Description: replace data in the node value. */ /*----------------------------------------------------------------------------*/ ::method replaceData -if arg() < 3 then raise syntax 93.901 array (3) -if arg() > 3 then raise syntax 93.902 array (3) -use arg offset, count, data -x = self~nodeValue~delstr(offset, count) -self~nodeValue~insert(data, offset - 1) -return + use strict arg offset, count, data + self~nodeValue~delstr(offset, count) + self~nodeValue~insert(data, offset - 1) /*----------------------------------------------------------------------------*/ @@ -1019,33 +911,28 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg data -self~nodeName = '#text' -self~nodeType = 3 -self~nodeValue = data -return + use strict arg data + self~nodeName = '#text' + self~nodeType = 3 + self~nodeValue = data + return - /*----------------------------------------------------------------------------*/ /* Method: splitText */ /* Description: split the node into two parts. */ /*----------------------------------------------------------------------------*/ ::method splitText -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg offset -siblings = self~parentNode~childNodes -newnode = .Text~new(self~nodeValue~substr(offset + 1) -self~nodeValue = self~nodeValue~substr(1, offset) --- find ourselves in the siblings -do i = 1 to siblings~items - if self = siblings[i] then leave - end -siblings~insert(newnode, i) -return newNode + use strict arg offset + siblings = self~parentNode~childNodes + newnode = .Text~new(self~nodeValue~substr(offset + 1) + self~nodeValue = self~nodeValue~substr(1, offset) + -- find ourselves in the siblings + do i = 1 to siblings~items + if self = siblings[i] then leave + end + siblings~insert(newnode, i) + return newNode /*----------------------------------------------------------------------------*/ @@ -1079,25 +966,21 @@ /*----------------------------------------------------------------------------*/ ::method init -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg name -self~nodeName = name -self~nodeType = 10 -self~nodeValue = .nil -self~entities = .NamedNodeMap~new -self~notations = .NamedNodeMap~new -return + use strict arg name + self~nodeName = name + self~nodeType = 10 + self~nodeValue = .nil + self~entities = .NamedNodeMap~new + self~notations = .NamedNodeMap~new - /*----------------------------------------------------------------------------*/ /* Method: name */ /* Description: return the node name. */ /*----------------------------------------------------------------------------*/ ::method name -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeName + use strict arg + return self~nodeName /*----------------------------------------------------------------------------*/ @@ -1106,9 +989,9 @@ /*----------------------------------------------------------------------------*/ ::method entities -expose entities -if arg() > 0 then raise syntax 93.902 array (0) -return entities + expose entities + use strict arg + return entities /*----------------------------------------------------------------------------*/ @@ -1117,9 +1000,9 @@ /*----------------------------------------------------------------------------*/ ::method notations -expose notations -if arg() > 0 then raise syntax 93.902 array (0) -return notations + expose notations + use strict arg + return notations /*----------------------------------------------------------------------------*/ @@ -1153,40 +1036,25 @@ /*----------------------------------------------------------------------------*/ ::method init -expose publicId systemId -if arg() > 2 then raise syntax 93.902 array (2) -if arg() = 1 then do - use arg publicId - systemId = .nil - end -else use arg publicId, systemId -self~nodeType = 12 -self~nodeValue = .nil -return + expose publicId systemId + use strict arg publicId, systemId = .nil + self~nodeType = 12 + self~nodeValue = .nil - /*----------------------------------------------------------------------------*/ /* Method: publicId */ /* Description: return the publicId. */ /*----------------------------------------------------------------------------*/ -::method publicId -expose publicId -if arg() > 0 then raise syntax 93.902 array (0) -return publicId +::attribute publicId get - /*----------------------------------------------------------------------------*/ /* Method: systemId */ /* Description: return the systemId. */ /*----------------------------------------------------------------------------*/ -::method systemId -expose systemId -if arg() > 0 then raise syntax 93.902 array (0) -return systemId +::attribute systemId get - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Entity */ @@ -1218,53 +1086,33 @@ /*----------------------------------------------------------------------------*/ ::method init -expose NodeName, publicId systemId -if arg() > 3 then raise syntax 93.902 array (3) -if arg() = 1 then do - use arg nodeName - publicId = .nil - systemId = .nil - end -if arg() = 2 then do - use arg nodeName, publicId - systemId = .nil - end -else use arg nodeName, publicId, systemId -self~nodeType = 6 -self~nodeValue = .nil -return + expose nodeName publicId systemId + use strict arg nodeName, publicId = .nil, systemId = .nil + self~nodeType = 6 + self~nodeValue = .nil - /*----------------------------------------------------------------------------*/ /* Method: publicId */ /* Description: return the publicId. */ /*----------------------------------------------------------------------------*/ -::method publicId -expose publicId -if arg() > 0 then raise syntax 93.902 array (0) -return publicId +::attribute publicId get - /*----------------------------------------------------------------------------*/ /* Method: systemId */ /* Description: return the systemId. */ /*----------------------------------------------------------------------------*/ -::method systemId -expose systemId -if arg() > 0 then raise syntax 93.902 array (0) -return systemId +::attribute systemId get - /*----------------------------------------------------------------------------*/ /* Method: notationName */ /* Description: return the notation name. */ /*----------------------------------------------------------------------------*/ ::method notationName -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeName + use strict arg + return self~nodeName /*----------------------------------------------------------------------------*/ @@ -1298,15 +1146,11 @@ /*----------------------------------------------------------------------------*/ ::method init -expose nodeName -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg nodeName -self~nodeType = 5 -self~nodeValue = .nil -return + expose nodeName + use strict arg nodeName + self~nodeType = 5 + self~nodeValue = .nil - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: ProcessingInstruction */ @@ -1338,22 +1182,18 @@ /*----------------------------------------------------------------------------*/ ::method init -expose nodeName nodeValue -if arg() < 2 then raise syntax 93.901 array (2) -if arg() > 2 then raise syntax 93.902 array (2) -use arg nodeName, nodeValue -self~nodeType = 7 -return + expose nodeName nodeValue + use strict arg nodeName, nodeValue + self~nodeType = 7 - /*----------------------------------------------------------------------------*/ /* Method: target */ /* Description: return the node name. */ /*----------------------------------------------------------------------------*/ ::method target -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeName + use strict arg + return self~nodeName /*----------------------------------------------------------------------------*/ @@ -1361,9 +1201,9 @@ /* Description: return the node value. */ /*----------------------------------------------------------------------------*/ -::method data -if arg() > 0 then raise syntax 93.902 array (0) -return self~nodeValue +::attribute data get + use strict arg + return self~nodeValue /*----------------------------------------------------------------------------*/ @@ -1371,12 +1211,8 @@ /* Description: set the node value. */ /*----------------------------------------------------------------------------*/ -::method 'data=' -expose nodeValue -if arg() < 1 then raise syntax 93.901 array (1) -if arg() > 1 then raise syntax 93.902 array (1) -use arg nodeValue -return +::attribute data set + expose nodeValue + use strict arg nodeValue - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-07 17:01:21
|
Revision: 8009 http://oorexx.svn.sourceforge.net/oorexx/?rev=8009&view=rev Author: bigrixx Date: 2012-07-07 17:01:12 +0000 (Sat, 07 Jul 2012) Log Message: ----------- add code for xpath support. Completely untested at this point Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-07 16:19:58 UTC (rev 8008) +++ incubator/orxutils/xml/xmldom.cls 2012-07-07 17:01:12 UTC (rev 8009) @@ -37,6 +37,11 @@ /* */ /*----------------------------------------------------------------------------*/ + +-- now that everything has been started up, poke the token class to create its +-- initial tables +.XPathToken~setup + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Section: Abstract DOM interface class definitions */ @@ -75,6 +80,7 @@ -- DOM Node interface class ::class "Node" public mixinclass Object -- various type definitions +::constant ANY_NODE 0 ::constant ELEMENT_NODE 1 ::constant ATTRIBUTE_NODE 2 ::constant TEXT_NODE 3 @@ -248,6 +254,40 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: QName -- a qualified XML name */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "QName" public +::method init + expose localName prefix namespaceURI + + localName = "" + prefix = "" + namespaceURI = "" + +::attribute prefix +::attribute localName +::attribute namespaceURI + +-- get the fully constructed node name +::attribute nodeName get + expose prefix localName + return prefix":"localName + +-- test for a match between a node and this qualified name +::method matchesNode + expose localName namespaceURI + use strict arg node + + return localName == node~localName & namespaceURI == node~namespaceURI + +-- handy string method +::method string + return self~nodeName + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: NodeListImpl -- concrete NodeList class */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -262,10 +302,11 @@ if nodes == .nil then do nodes = .array~new end - else do + else if nodes~isA(.array) then -- make a copy of this nodes = nodes~copy - end + -- must be a nodelist...get the items array from the list + else nodes = nodes~makearray /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -312,6 +353,68 @@ -- access to the set of nodes ::attribute nodes +-- methods to support xpath/nodeset operations + +-- append an item to the list +::method append + expose nodes + use strict arg item + nodes~append(item) + +-- merge two nodelists by adding all of the elements of the +-- argument list to the target list. +::method union + use strict arg other + loop node over other + self~append(node) + end + return self -- always return self as a value + +-- return the index location of a given item. Returns -1 +-- if the item is not found +::method indexOf + expose nodes + use strict arg target + + index = nodes~itemIndex(target) + + if index == .nil then return -1 + -- need to convert this to zero-based for + -- nodelists + return index - 1 + +-- get the first item in the node list +::method first + expose nodes + return nodes[1] + +-- get the last item in the node list +::method last + expose nodes + + if nodes~isEmpty then return .nil + return nodes[nodes~last] + +-- get the item previous to a given one +::method previous + expose nodes + use strict arg target + + index = nodes~itemIndex(target) + -- not found or the first one, return nothing + if index == .nil | index = 1 then return .nil + return nodes[index] + +-- get the item followinging a given one +::method next + expose nodes + use strict arg target + + index = nodes~itemIndex(target) + -- not found, return nothing + if index == .nil then return .nil + return nodes[index] + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: DeepNodeList */ @@ -470,7 +573,305 @@ -- nothing found return .nil +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: NodeSet */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +-- a nodeset used in an xpath expression +::class "NodeSet" public subclass NodeListImpl +::method init + expose owner parent + use strict arg owner, parent, nodes + self~init:super(nodes) + + +-- apply a selection criteria to a nodeset, returning +-- a new nodeset with the selected nodes. +::method selectNodeSet + expose owner + use strict arg step, context + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner, context) + + -- loop over all of the nodes in this set and apply + -- the selection rules to each one, merging the result + -- into the set + loop node over self + nodeSet~union(step~evaluateNodeSet(node, self)) + end + return nodeSet + +-- retrieve a named set of nodes from the set using a qualified name. +::method getNamedItems + expose owner + use strict arg name + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + -- wild card on the namespace? This is a complete wildcard request + if name~namespaceURI == '*' then do + nodeSet~union(self) + end + -- wild card request with an explicit namespace?, return + -- just URI matches + else if name~localName == "*" then do + loop node over self + if name~namespaceURI == node~namespaceURI then nodeSet~append(node) + end + end + -- no wild cards, so we're looking for explicit matches + else do + loop node over self + if name~matchesNode(node) then nodeSet~appendNode + end + end + + return nodeSet + +-- extract the nodes of the indicated type +::method getTypedItems + expose owner + use strict arg type + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + if type == 0 | node~nodeType == type then do + nodeSet~append(node) + end + end + +-- methods for axis manipulations on nodesets + +-- return the combined ancestor axis of the contents +::method ancestorAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~ancestorAxis) + end + return nodeSet + +-- return the combined ancestor-or-self axis of the contents +::method ancestorOrSelfAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~ancestorOrSelfAxis) + end + return nodeSet + +-- return the combined attribute axis of the contents +::method attributeAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~attributeAxis) + end + return nodeSet + +-- return the combined child axis of the contents +::method childAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~childAxis) + end + return nodeSet + +-- return the combined descendant axis of the contents +::method descendantAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~descendantAxis) + end + return nodeSet + +-- return the combined reversed descendant axis of the contents +::method reversedDescendantAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~reversedDescendantAxis) + end + return nodeSet + +-- return the combined descendant-or-self axis of the contents +::method descendantOrSelfAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~descendantOrSelfAxis) + end + return nodeSet + +-- return the combined following axis of the contents +::method followingAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~followingAxis) + end + return nodeSet + +-- return the combined following-sibling axis of the contents +::method followingSiblingAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~followingSiblingAxis) + end + return nodeSet + + +-- return the combined namespace axis of the contents +::method namespaceAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~namespaceAxis) + end + return nodeSet + +-- return the combined parent axis of the contents +::method parentAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~parentAxis) + end + return nodeSet + +-- return the combined preceding axis of the contents +::method precedingAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~precedingAxis) + end + return nodeSet + +-- return the combined preceding-sibling axis of the contents +::method precedingSiblineAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~precedingSiblingAxis) + end + return nodeSet + +-- return the combined self axis of the contents +::method selfAxis + expose owner + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + nodeSet~union(node~selfAxis) + end + return nodeSet + +-- these are self containing +::attribute containingNodeSet get + return self + +-- filter this node set based on an expression criteria, returning +-- a new node set +::method filter + expose owner + use strict arg context, predicate + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + -- evaluate the predicate expression against this node and container + -- context. + if predicate.evaluatePredicate(node, self, s) then + nodeSet~append(node) + end + + return nodeSet + +-- extract the nodes by qualified name, returning a new nodeset +::method getElementsByQualifiedName + expose owner + use strict arg qname + + -- get a result nodeset for the base + nodeSet = .nodeset~new(owner) + + loop node over self + -- evaluate the predicate expression against this node and container + -- context. + if qname~matchesNode(node) then + nodeSet~append(node) + end + + return nodeSet + +-- determine the index position of a given node within the nodeset. +-- returns -1 for not found +::method positionOf + use strict arg target + + loop i = 0 to self~length + if self~item(i) then return i + end + return -1 -- not found + +-- test if the node contains a give target node +::method contains + use strict arg target + return self~positionOf(target) \= -1 + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: NamedNodeMap */ @@ -1193,10 +1594,28 @@ ::method changed self~ownerdocument~changed +-- return a change count for the node...this just returns +-- the document change count ::method changes return self~ownerdocument~changes +-- select a set of nodes using an xpath expression +::method selectNodeSet + use strict arg path + -- any errors are just treated as selection failures and return an + -- empty node set + signal on syntax + + -- parse the expression and execute using this node as the starting context + parser = .XpathParser~new(self~document, path) + expr = parse~parse + return expr~evaluate(self, .nil) + + syntax: + -- just return an empty node set + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Node */ @@ -1207,9 +1626,137 @@ ::attribute ctr class private ::attribute id private +-- retrieve the ancestor axis +::attribute ancestorAxis get + parentNode = self~parentNode + -- if not at the top of the tree, have our parent handle this + if parentNode~nodeType \= self~DOCUMENT_NODE then + return parentNode~ancestorOrSelfAxis + -- at the top, so there are no ancestors. Just return an empty + -- nodeset + else return .NodeSet~new(self~document, parentNode) +-- retrieve the ancestor-or-self axis +::attribute ancestorOrSelfAxis get + -- merge the self list with the ancestor + return self~selfAxis~union(self~ancestorAxis) + +-- retrieve the attribute axis +::attribute attributeAxis get + -- node set of attributes + + --TODO: Make sure NodeImpl has an attributes method and attributes + -- returns the appropriate thing + return .nodeset~new(self~document, self~parentNode, self~attributes) + +-- retrieve the child axis +::attribute childAxis get + return .nodeset~new(self~document, self~parentNode, self~childNodes) + +-- retrieve the descendant axis +::attribute descendantAxis get + nodeSet = .nodeset~new(self~document, self~parentNode) + -- merge in all of the descendants + loop child over self~childNodes + nodeSet~union(child~descendantOrSelfAxis) + end + return nodeSet + +-- retrieve the reversed descendant axis. This +-- builds the list in reverse descenant order +::attribute reversedDescendantAxis get + nodeSet = .nodeset~new(self~document, self~parentNode) + + children = self~childNodes + -- merge in all of the descendants in reverse order + loop i = children~length to 1 by -1 + nodeSet~union(children[i]~reversedDescendantOrSelfAxis) + end + return nodeSet + +-- descendant axis + self +::attribute descendantOrSelfAxis get + return self~selfAxis~union(self~descendantAxis) + +-- and the reversed version of the descendant + self axis +::attribute reversedDescendantOrSelfAxis get + return self~selfAxis~union(self~reversedDescendantAxis) + +-- The following axis...this is all of the following siblings + +-- their descendants +::attribute followingAxis get + nodeSet = .nodeSet~new(self~document, self~parentNode) + + nextSibling = self~nextSibling + -- if we have a sibling, then get its descendant axis and + -- also get its following axis. + if nextSibling \== .nil then do + nodeSet~append(nextSibling) + nodeSet~union(nextSibling~descendantAxis) + nodeSet~union(nextSibling~followingAxis) + end + +-- following sibling axis is like the following axis, but omits the +-- children of the siblings +::attribute followingSiblingAxis get + nodeSet = .nodeSet~new(self~document, self~parentNode) + + nextSibling = self~nextSibling + -- if we have a sibling, then get its descendant axis and + -- also get its following axis. + if nextSibling \== .nil then do + nodeSet~append(nextSibling) + nodeSet~union(nextSibling~followingSiblingAxis) + end + +-- the nodeset containing just the parent (if it exists) +::attribute parentAxis get + nodeSet = .nodeSet~new(self~document, self~parentNode) + + if self~parentNode \= .nil then nodeSet~append(self~parentNode) + return nodeSet + +-- The preceding axis...this is all of the preceding siblings + +-- their descendants +::attribute precedingAxis get + nodeSet = .nodeSet~new(self~document, self~parentNode) + + previousSibling = self~previousSibling + -- if we have a sibling, then get its descendant axis and + -- also get its preceding axis. + if previousSibling \== .nil then do + nodeSet~append(previousSibling) + nodeSet~union(previousSibling~descendantAxis) + nodeSet~union(previousSibling~precedingAxis) + end + +-- preceding sibling axis is like the preceding axis, but omits the +-- children of the siblings +::attribute precedingSiblingAxis get + nodeSet = .nodeSet~new(self~document, self~parentNode) + + nextSibling = self~nextSibling + -- if we have a sibling, then get its descendant axis and + -- also get its preceding axis. + if nextSibling \== .nil then do + nodeSet~append(previousSibling) + nodeSet~union(previousSibling~precedingSiblingAxis) + end + +-- the nodeset containing just this node +::attribute selfAxis get + nodeSet = .nodeSet~new(self~document, self~parentNode) + nodeSet~append(self) + return nodeSet + +-- the nodeset containing the tree root +::attribute rootAxis get + nodeSet = .nodeSet~new(self~document, self~parentNode) + nodeSet~append(self~document~documentElement) + return nodeSet + -- methods of NodeList that the node implements directly. superclasses will --- implement this more full +-- implement this more fully /*----------------------------------------------------------------------------*/ /* Method: item */ @@ -6640,3 +7187,1956 @@ ::method renamedElement use strict arg oldElement, newElement + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Section: XPath parser and evaluation engine */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + + +::class "XPath" +::constant INVALID_OPERATOR_ERROR "Invalid XPath operator found" +::constant INVALID_EXPRESSION_ERROR "Invalid XPath expression." +::constant INVALID_VARIABLE_REFERENCE_ERROR "Variable references not supported" +::constant MISSING_QUOTE_ERROR "Missing closing literal string quote" +::constant MISSING_PAREN_ERROR "Missing closing parentheses" +::constant INVALID_AXIS_NAME_ERROR "Invalid XPath axis name" +::constant INVALID_TYPE_TEST_ERROR "Invalid node type." +::constant INVALID_NAME_TEST_ERROR "Invalid node name type." +::constant MISSING_ARGUMENT_ERROR "Missing function argument." +::constant INCORRECT_FUNCTION_ARGUMENTS_ERROR "Incorrect function arguments." +::constant NODESET_ERROR "Expression did not evaluate to a node set." +::constant UNKNOWN_FUNCTION_ERROR "Unknown function name in expression." + +-- raise an error for an xpath problem +::method xpathError class + use strict arg reason + raise syntax 93.900 array(reason) + +-- a queue of tokens +::class "TokenQueue" +::method init + expose queue currentToken + queue = .queue~new + -- this is used for reading the tokens + currentToken = 1 + +-- add a token to the queue +::method addToken + expose queue + use strict arg token + queue~queue(token) + +-- reset the token position to the beginning +::method rewind + expose currentToken + currentToken = 1 + +-- test if there are more tokens +::method hasMore + expose queue currentToken + return currentToken <= queue~size + +-- get the next token, stepping the position +::method nextToken + expose queue currentToken + item = queue[currentToken] + currentToken += 1 + return item + +-- back up a token in the queue +::method previousToken + expose currentToken + + if currentToken > 1 then currentToken += 1 + +-- peek at the next (current) token +::method peekToken + expose queue currentToken + return queue[currentToken] + +-- remove the first token from the queue +::method pop + expose queue + queue~pop + + +-- a generic token value. Most of the work here is done via class methods. +-- the token itself is very general and very simple +::class "XPathToken" + +-- set up all of the initial token types +::method setup class + expose simpleOperators namedOpertors nodeTypes axisTypes + simpleOperators = .directory~new + namedOperators = .directory~new + nodeTypes = .directory~new + axisTypes = .directory~new + + -- this is a dummy marker token used as the first one + self~dummy = .XPathToken~new('') + -- special terminator token function argument lists + self~function_arg = .XPathToken~new(',)') + + -- create the various constant tokens + self~open_paren = .XPathToken~new('(') + self~close_paren = .XPathToken~new(')', .true) + self~open_bracket = .XPathToken~new('[') + self~close_bracket = .XPathToken~new(']', .true) + self~period = .XPathToken~new('.', .true) + self~double_period = .XPathToken~new('..', .true) + self~at_sign = .XPathToken~new('@') + self~comma = .XPathToken~new(',') + self~double_colon = .XPathToken~new('::') + self~slash = .XPathToken~new('/') + self~double_slash = .XPathToken~new('//') + self~union = .XPathOperatorToken~new('|', 0) + self~addition = .XPathOperatorToken~new('+', 6) + self~subtraction = .XPathOperatorToken~new('-', 6) + self~equal = .XPathOperatorToken~new('=', 3) + self~not_equal = .XPathOperatorToken~new('!=', 3) + self~less_than = .XPathOperatorToken~new('<', 4) + self~less_than_equal = .XPathOperatorToken~new('<=', 4) + self~greater_than = .XPathOperatorToken~new('>', 4) + self~greater_than_equal = .XPathOperatorToken~new('>=', 4) + self~multiply = .XPathOperatorToken~new('*', 5) + self~wildcard = .XPathToken~new('*', .true) + + -- this is a subset of the operator tokens. The ones + -- in this list can be resolved immediately just off of a + -- single character. Others will need some additional processing + simpleOperators["open_paren"] = self~open_paren + simpleOperators["close_paren"] = self~close_paren + simpleOperators["open_bracket"] = self~open_bracket + simpleOperators["close_bracket"] = self~close_bracket + simpleOperators["at_sign"] = self~at_sign + simpleOperators["comma"] = self~comma + simpleOperators["union"] = self~union + simpleOperators["addition"] = self~addition + simpleOperators["subtraction"] = self~subtraction + simpleOperators["equal"] = self~equal + + self~and = .XPathOperatorToken~new('and', 2) + self~or = .XPathOperatorToken~new('or', 1) + self~mod = .XPathOperatorToken~new('mod', 5) + self~div = .XPathOperatorToken~new('div', 5) + + -- the named operators + namedoperators["and"] = self~and + namedoperators["or"] = self~or + namedoperators["mod"] = self~mod + namedoperators["div"] = self~div + + self~comment = .XPathToken~new("NODETYPE", , 'comment') + self~text = .XPathToken~new("NODETYPE", , 'text') + self~processing_instruction = .XPathToken~new("NODETYPE", , 'processing_instruction') + self~node = .XPathToken~new("NODETYPE", , 'node') + self~element = .XPathToken~new("NODETYPE", , 'element') + + -- quick resolution table for the node types + nodetypes["comment"] = self~comment + nodetypes["text"] = self~text + nodetypes["processing_instruction"] = self~processing_instruction + nodetypes["node"] = self~node + nodetypes["element"] = self~element + + self~ancestor = .XPathToken~new('ancestor') + self~ancestor_or_self = .XPathToken~new('ancestor_or_self') + self~attribute = .XPathToken~new('attribute') + self~child = .XPathToken~new('child') + self~descendant = .XPathToken~new('descendant') + self~descendant_or_self = .XPathToken~new('descendant_or_self') + self~following = .XPathToken~new('following') + self~following_sibling = .XPathToken~new('following_sibling') + self~namespace = .XPathToken~new('namespace') + self~parent = .XPathToken~new('parent') + self~preceding = .XPathToken~new('preceding') + self~preceding_sibling = .XPathToken~new('preceding_sibling') + self~self = .XPathToken~new('self') + + -- build the axis table for quick parsing + axistypes["ancestor"] = self~ancestor + axistypes["ancestor_or_self"] = self~ancestor_or_self + axistypes["attribute"] = self~attribute + axistypes["child"] = self~child + axistypes["desendant"] = self~descendant + axistypes["desendant_or_self"] = self~descendant_or_self + axistypes["following"] = self~following + axistypes["following_sibling"] = self~following_sibling + axistypes["namespace"] = self~namespace + axistypes["parent"] = self~parent + axistypes["preceding"] = self~preceding + axistypes["preceding_sibling"] = self~preceding_sibling + axistypes["self"] = self~self + + +-- singletons for the different imutable operator types +::attribute dummy class +::attribute function_arg class +::attribute open_paren class +::attribute close_paren class +::attribute open_bracket class +::attribute close_bracket class +::attribute period class +::attribute double_period class +::attribute at_sign class +::attribute comma class +::attribute double_colon class +::attribute slash class +::attribute double_slash class +::attribute union class +::attribute addition class +::attribute subtraction class +::attribute equal class +::attribute not_equal class +::attribute less_than class +::attribute less_than_equal class +::attribute greater_than class +::attribute greater_than_equal class +::attribute multiply class +::attribute wildcard class +::attribute and class +::attribute or class +::attribute mod class +::attribute div class +::attribute node class +::attribute text class +::attribute element class +::attribute processing_instruction class +::attribute comment class +::attribute ancestor class +::attribute ancestor_or_self class +::attribute attribute class +::attribute child class +::attribute descendant class +::attribute descendant_or_self class +::attribute following class +::attribute following_sibling class +::attribute namespace class +::attribute parent class +::attribute preceding class +::attribute preceding_sibling class +::attribute preceding_self class +::attribute self class + +-- create a literal string token +::method literalToken class + use strict arg value + return .XPathToken~new("LITERAL", .true, value) + +-- create a function token +::method functionToken class + use strict arg prefix, name + return .XPathToken~new("FUNCTION", .false, name, prefix) + +-- create a namespace token +::method nameToken class + use strict arg name + return .XPathToken~new("NCNAME", .true, name) + +-- create a qualified name token +::method qualifiedNameToken class + use strict arg prefix, name + return .XPathToken~new("QNAME", .true, name, prefix) + +-- create a number token +::method numberToken class + use strict arg value + return .XPathToken~new("NUMBER", .true, value) + +-- create a variable reference token +::method variableReferenceToken class + use strict arg prefix, name + return .XPathToken~new("VARIABLE", .true, name, prefix) + + -- resolve an operator token based on the character. + -- returns .nil if the operator is not simply resolvable +::method resolveSimpleOperator class + expose simpleOperators + use strict arg op + return simpleOperators[op] + + -- resolve an operator token based on the operator name. + -- returns .nil if the operator is not simply resolvable +::method resolveNamedOperator class + expose namedOperators + use strict arg op + return namedOperators[op] + + -- resolve a node type token based on the name. + -- returns .nil if the operator is not simply resolvable +::method resolveNodeType class + expose nodeTypes + use strict arg op + return nodeTypes[op] + + + -- resolve a axis type token based on the name. + -- returns .nil if the operator is not simply resolvable +::method resolveAxis class + expose axisTypes + use strict arg op + return axisTypes[op] + +::method init + expose isMultTarget name prefix + use strict arg type, isMultTarget = .false, name = .nil, prefix = .nil + +-- the identifier of the token. For operators, this will be +-- the operator type itself. All operator tokens are singletons. +-- This can also be STRING, NAME, QNAME, or NUMBER +::attribute type GET +-- indicates whether this token can be used as a multiply target +::attribute isMultTarget GET +::attribute prefix GET +::attribute name GET + +-- special test for operator tokens -- default is always false +::attribute isOperator GET + +-- special subclass for the operators +::class "XPathOperatorToken" subclass XPathToken +::method init + expose precedence + use strict arg type, precedence + -- operators use default values for everything else + self~init:super(type) + +-- Override of the operator test +::attribute isOperator GET + return .true +-- operator precedence value +::attribute precedence GET + +-- a class to scan an xpath expression and break it up into its tokens. +::class "XPathScanner" +::method init class + expose nonascii namecharacters + nonascii = xrange('80'x, 'ff'x) + namecharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_' || nonascii + +::constant whitespace '090A0D20'x +::constant other '2325263F5C5E607B7D7E7F'x +::constant quote '''"' +::constant digit '0123456789' +::constant letter 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' +-- all characters above '80'x +::attribute nonascii GET +-- all characters valid at the start of an xpath name. This is letters, +-- underscore, and the nonascii characters +::attribute namecharacters GET + +-- raise an error as the result of a scanning error +::method error private + use strict arg currentOffset, msg + raise syntax 93.900 array('Error at offset' currentOffset':' msg, currentOffset) + +-- scan an expression string, breaking this up into a list of tokens. +::method scanExpression + use strict arg data + + currentOffset = 1 + endOffset = data~length + + -- create a queue for the tokens and make the first token a dummy marker + tokens = .tokenqueue~new + tokens~addqueue(.XPathToken~dummy) + + loop name scan forever + -- skip over any blanks + currentOffset = data~verify(self~whitespace, currentOffset) + -- hit the end of what we're parsing? Done + if currentOffset > endOffset then leave + -- skip over any blanks + currentOffset = data~verify(self~whitespace, currentOffset) + -- all whitespace left, we're done + if currentOffset = 0 then leave scan + + ch = data~subchar(currentOffset) + -- some single character tokens can be resolved and handled + -- quickly if this is one of these, we can go around + token = .XPathToken~resolveSimpleOperator(ch) + if token \== .nil then do + tokens~addToken(token) + currentOffset += 1 + iterate scan + end + + -- something requiring a little more processing + select + -- potentially "::" + when ch == ':' then do + currentOffset += 1 + ch = data~subchar(currentOffset) + -- this also catches eof-of-line because subchar will return + -- "" for out-of-range. + if ch \== ':' then self~error(currentOffset - 1, "Invalid token ':'") + tokens~addToken(.XPathToken~double_colon) + currentOffset += 1 + end + -- can be either '/' or '//' + when ch == '/' then do + currentOffset += 1 + -- single colon at the end is not valid + if currentOffset > endOffset then do + tokens~addToken(.XPathToken~slash) + leave scan + end + -- grab the next character and see if this is a + -- double or a single + ch = data~subchar(currentOffset) + if ch == '/' then do + tokens~addToken(.XPathToken~doubleslash) + currentOffset += 1 + end + else do + tokens~addToken(.XPathToken~slash) + end + end + -- non-equality operator...potentially + when ch == '!' then do + currentOffset += 1 + -- single bang at the end is not valid + ch = data~subchar(currentOffset) + -- only '=' is valid after a '!' + if ch \== '=' then self~error(currentOffset - 1, "Invalid token '!'") + tokens~addToken(.XPathToken~not_equal) + currentOffset += 1 + end + -- the relative operators can be either "<" or "<=" + when ch == '<' then do + currentOffset += 1 + -- Just a less than + if currentOffset > endOffset then do + tokens~addToken(.XPathToken~less_than) + currentOffset += 1 + end + else do + ch = data~subchar(currentOffset) + -- have the "="? + if ch == '=' then do + tokens~addToken(.XPathToken~less_than_equal) + currentOffset += 1 + end + else do + -- just the single form + tokens~addToken(.XPathToken~less_than) + end + end + end + -- and the greater than forms + when ch == '>' then do + currentOffset += 1 + -- Just a less than + if currentOffset > endOffset then do + tokens~addToken(.XPathToken~greater_than) + currentOffset += 1 + end + else do + ch = data~subchar(currentOffset) + -- have the "="? + if ch == '=' then do + tokens~addToken(.XPathToken~greater_than_equal) + currentOffset += 1 + end + else do + -- just the single form + tokens~addToken(.XPathToken~greater_than) + end + end + end + -- have a quoted string. This is defined by the spec as + -- + -- [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'" + -- + -- either-or on the delimiters and no escaping + when ch~matchChar(1, self~quote) then do + currentOffset += 1 + -- find the closing point + endquote = data~pos(ch, currentOffset) + if endquote = 0 then self~error(currentOffset - 1, "Missing close quote on string") + value = data~substr(currentOffset, endQuote - (currentOffset)) + -- add a literal token + tokens~addToken(.XPathToken~literalToken(value)) + currentOffset = endquote + 1 + end + -- this is potentially a number. The xpath rule for numbers is: + -- [30] Number ::= Digits ('.' Digits?)? | '.' Digits + when ch == '.' then do + -- are we at the end? This can't be a number so add a + -- period token and get out + if currentOffset = endOffset then do + tokens~addToken(.XPathToken~period) + currentOffset += 1 + leave scan + end + -- get the next character + ch = data~subchar(currentOffset + 1) + -- another period is a double period token + if ch == '.' then do + tokens~addToken(.XPathToken~double_period) + currentOffset += 2 + end + -- period followed by '/' or '|' scans as a period token + else if ch == '/' then do + tokens~addToken(.XPathToken~period) + currentOffset += 1 + end + else if ch == '|' then do + tokens~addToken(.XPathToken~period) + currentOffset += 1 + end + -- have a digit...bingo, this is a number + else if ch~matchChar(1, self~digits) then do + -- scan off a number + currentOffset = self~scanNumber(tokens, data, currentOffset, endOffset); + end + -- a period followed by whitespace is only legal if this is the last token + -- OR the next token is a '|'. This scans a single period in that case. + else if ch~matchChar(1, self~whitespace) then do + nonblank = data~verify(self~whitespace, currentOffset + 1) + if nonBlank = 0 then do + tokens~addToken(.XPathToken~period) + currentOffset = endOffset + 1 + end + else if data~subchar(nonBlank) == '|' then do + tokens~addToken(.XPathToken~period) + currentOffset = nonBlank + end + else do + -- this is an error + self~xpathError("Invalid XPath expression") + end + end + end + -- a number, as defined by the xpath spec + -- + -- [30] Number ::= Digits ('.' Digits?)? | '.' Digits + -- [31] Digits ::= [0-9]+ + -- + when ch~matchChar(1, self~digit) then do + -- scan off a number + currentOffset = self~scanNumber(tokens, data, endOffset, currentOffset); + end + -- a * can be either a wildcard selector on a name or the multiply + -- operation, depending on what the previous token was + -- + -- [37] NameTest ::= '*' | NCName ':' '*' | QName + -- [34] MultiplyOperator ::= '*' + -- + -- + -- 3.7 Lexical Structure + -- + -- If there is a preceding token and the preceding token is not one of @, ::, (, [, , or + -- an Operator, then a * must be recognized as a MultiplyOperator. + -- + -- Otherwise, the token must not be recognized as a MultiplyOperator. + -- + when ch == '*' then do + if tokens~lastToken~isMultTarget then do + tokens~addToken(.XPathToken~multiply) + end + else do + tokens~addToken(.XPathToken~wildcard) + end + currentOffset += 1 + end + -- a name of some sort. These are complicated, because the meaning depends + -- both on the preceeding token AND the following tokens. The spec definitions are: + -- + -- 3.7 Lexical Structure + -- + -- If there is a preceding token and the preceding token is not one of @, ::, (, [, , or + -- an Operator, then an NCName must be recognized as an OperatorName. + -- + -- If the character following an NCName (possibly after intervening ExprWhitespace) is (, + -- then the token must be recognized as a NodeType or a FunctionName. + -- + -- If the two characters following an NCName (possibly after intervening ExprWhitespace) + -- are ::, then the token must be recognized as an AxisName. + -- + -- Otherwise, the token must not be recognized as an OperatorName, a NodeType, a + -- FunctionName, or an AxisName. + -- + -- [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div' + -- [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node' + -- [35] FunctionName ::= QName - NodeType + -- [6] AxisName ::= (see above) + -- + -- [37] NameTest ::= '*' | NCName ':' '*' | QName + -- [5] NCName ::= (Letter | '_') (NCNameChar)* + -- [?] NCNameChar ::= Letter | Digit | '.' | '-' | '_' (ascii subset of 'NCNameChar') + -- [?] QName ::= (NCName ':')? NCName + -- [?] Letter ::= [A-Za-z] (ascii subset of 'Letter') + -- [?] Digit ::= [0-9] (ascii subset of 'Digit') + -- + when ch~matchChar(1, self~nameCharacters) then do + nameOffset = currentOffset + -- scan off the name + currentOffset = self~NCName(data, currentOffset, endOffset) + -- NB: This will return a null string if we're past the end + -- of the string. This is a convenient eol marker. + ch = data~subChar(currentOffset) + -- extract the name + name = data~substr(nameOffset, currentOffset - nameOffset) + -- no prefix yet + prefix = "" + -- potential qualified name form? We need to look + -- ahead a little, then check out the previous token to + -- understand how this needs to be treated. + if ch == ':' then do + -- this is just a standard name...so far. + nametype = "NAME" + currentOffset += 1 + -- invalid name if at the end + if currentOffset > endOffset then self~error(currentOffset - 1, "Missing local name part for qualified name") + ch = data~subchar(currentOffset) + -- wildcarded qualified name? + if ch == '*' then do + currentOffset += 1 + ch = data~subchar(currentOffset) + -- this is a more complicated name type + nametype = "NCNAME" + end + -- double colon form is an axis name + else if ch == ':' then do + currentOffset += 1 + ch = data~subchar(currentOffset) + -- the axis forms require special attention later + nametype = "AXIS" + end + -- this is a qualified name form + else do + -- the previously parsed name is now the prefix + prefix = name + nameOffset = currentOffset + -- scan off the trailing name + currentOffset = self~scanNCName(data, currentOffset, endOffset) + -- this is an error if not followed by a name + if nameOffset = currentOffset then self~error(currentOffset - 1, "Missing local name part for qualified name") + -- get the following character (note that ch will be '' if + -- there isn't anything left + ch = data~subchar(currentOffset) + -- get the name part + name = data~substr(nameOffset, currentOffset - nameOffset) + end + end + -- whitespace is allowed here, so skip over it + currentOffset = self~skipWhiteSpace(data, currentOffset, endOffset) + ch = data~charAt(currentOffset) + -- + -- If there is a preceding token and the preceding token is not one of @, ::, (, [, , or + -- an Operator, then an NCName must be recognized as an OperatorName. + -- + if tokens~lastToken~isMultTarget then do + -- resolve to a the appropriate operator + token = .XPathToken~resolveNamedOperator(name) + if token == .nil then self~error(currentOffset - 1, "invalid named operator" name) + tokens~addToken(token) + -- ok, this was an operator, but it might have been disguised as a + -- complex name...diagnose that + if nametype \= "NAME" then self~error(currentOffset - 1, "operator name used as a qualified name") + end + -- some sort of valid name expected here...but this might also be a + -- nodetype or function name if followed by a '(' + else do + -- if we have a simple name followed by a paren, this is special + if ch == '(' & nametype == "NAME" then do + nodetype = .XPathToken~resolveNodeType(name) + if nodetype \= .nil then do + tokens~addToken(nodetype) + end + else do + tokens~addToken(.XPathToken~functionToken(prefix, name)) + end + -- add the open paren that indicates the special nature + tokens~addToken(.XPathToken~openParen) + currentOffset += 1 + end + -- ok, now check for axis names...We might already have detected this, but there could have + -- been intervening whitespace before the double colon + else if nametype == "AXIS" | (ch == ':' & data.subchar(currentOffset + 1) == ':') then do + axis = .XPathToken~resolveAxis(name) + if axis == .nil then self~error(currentOffset - 1, "Invalid axis name" name) + tokens~addToken(axis) + -- add the double colon marker + tokens~addToken(.XPathToken~double_colon) + -- if we detected this here, then step over the double colon + if nametype \= "AXIS" then currentOffset += 1 + end + else do + if nametype == "NCNAME" then do + -- get a namespace indicator + tokens~addToken(.XPathToken~nameToken(name)) + end + -- just a qualified name (finally!) + else do + -- get a qualified name indicator + tokens~addToken(.XPathToken~qualifiedNameToken(prefix, name)) + end + end + end + end + -- an external variable reference + -- + -- [36] VariableReference ::= '$' QName + -- + when ch == '$' then do + currentOffset += 1 + -- invalid name if at the end + if currentOffset > endOffset then self~error(currentOffset - 1, "Missing variable reference name") + nameOffset = currentOffset + currentOffset = self~scanNCName(data, currentOffset, endOffset) + if nameOffset = currentOffset then self~error(currentOffset - 1, "Missing variable reference name") + ch = data~subchar(currentOffset) + name = data~substr(nameOffset, currentOffset - nameOffset) + prefix = "" + -- if this has the form of a qualified name, then the name we just scanned off is the + -- prefix + if ch == ':' then do + prefix = name + currentOffset += 1 + -- invalid name if at the end + if currentOffset > endOffset then self~error(currentOffset - 1, "Invalid qualified name") + nameOffset = currentOffset + currentOffset = self~scanNCName(data, currentOffset, endOffset) + if nameOffset = currentOffset then self~error(currentOffset - 1, "Invalid qualified name") + name = data~substr(nameOffset, currentOffset - nameOffset) + end + tokens~addToken(.XPathToken~variableReferenceToken(prefix, name)) + end + -- some sort of invalid token type + otherwise do + self~error(currentOffset - 1, "Invalid character in expression" ch) + end + end + end + -- everything is scanned, and we have a queue of tokens to process now + -- we need to pull the dummy token from the front + tokens~pull + return tokens + +-- scan an NCNAME from the expression. A NCNAME is defined as: +-- +-- +-- [5] NCName ::= (Letter | '_') (NCNameChar)* +-- [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender +-- +::method scanNCName + use strict arg data, currentOffset, endOffset + ch = data~subchar(currentOffset) + -- use the XMLCHAR class to check this... + -- if not a valid first character, we're done + if \XMLChar~isNameStart(ch) then do + return currentOffset + end + + currentOffset = data~verify(xmlchars~name, currentOffset + 1) + if currentOffset = 0 then currentOffset = endOffset + 1 + return currentOffset + +-- scan off a number value, defined as +-- +-- +-- [30] Number ::= Digits ('.' Digits?)? | '.' Digits +-- [31] Digits ::= [0-9]+ +-- +::method scanNumber + use arg tokens, data, currentOffset, endOffset + + start = currentOffset + -- we know we at least have a valid first character, which might be a period + -- scan over any leading digits + currentOffset = data~verify(self~digits, currentOffset) + -- are we at a period now? + if data~match(currentOffset, '.') then do + period = currentOffset + currentOffset = data~verify(self~digit, currentOffset) + if currentOffset = 0 then currentOffset = period + 1 + end + + number = data~substr(start, currentOffset - start) + tokens~addToken(.XPathToken~numbertoken(number)) + return currentOffset; + +-- test for a node match +::class "NodeTest" +::method init + expose nameTest typeTest + use strict arg nameTest = .nil, typeTest = (.Node~ANY_NODE) + +-- apply the match logic +::method apply + expose nameTest typeTest + use strict arg nodeset + + if nameTest \= .nil then return nodeset~getNamedItems(nameTest) + else nodeset~getTypedItems(typeTest) + +-- base class for an xpath expression term +::class XpathExpr +-- evaluate the expression +::method evaluate + use strict arg context, container + return .nil + +::method evaluateBoolean + use strict arg context, container + + value = self~evaluate(context, container) + + if \value~datatype('o') then XPath~error(.Xpath~BOOLEAN_ERROR) + return value + +::method evaluateString + use strict arg context, container + + value = self~evaluate(context, container) + + if \value~isA(.string) then XPath~error(.Xpath~STRING_VALUE_ERROR) + return value + +::method evaluateNumber + use strict arg context, container + + value = self~evaluate(context, container) + + if \value~datatype('Number') then XPath~error(.Xpath~NUMBER_VALUE_ERROR) + return value + +::method evaluateNodeSet + use strict arg context, container + + value = self~evaluate(context, container) + + if \value~isA(.NodeSet) then XPath~error(.Xpath~NODESET_VALUE_ERROR) + return value + +::method evaluatePredicate + use strict arg context, container, proximityPosition + + value = self~evaluate(context, container) + if value~isA(.string), value~datatype('Number') then + return result = proximityPosition + -- xpath has funny rules for boolean true/false, so this requires + -- some inspection + return self~convertBoolean(result) + +-- Apply the xpath rules for boolean true/false to an expression result +::method convertBoolean + use strict arg value + + -- special rules for string values + if value~isA(.string), value~datatype('Number') then do + -- if this is a numberic value, then non-zero is true, zero is false + if value~datatype('Number') then + -- non-exact comparison here... + return value \= 0 + -- the strings true and false are special + if value == "true" then return .true + if vallue == "false" then return .false + -- if this is a string value, then a null string is false, any other value + -- is true + return value \== "" + end + -- nodesets convert to boolean based on an empty test + else if value~isa(.NodeSet) then return value~length > 0 + -- other than the 4 basic types is ambiguously defined by the standard, + -- so we'll just assume the answer is false for now. + return .false + +-- convert a value to a numeric value. Things don't really map that +-- well for Rexx values, so for strings that aren't numeric, we'll +-- just return the final option of 0. +::method convertNumber + use strict arg value + if value~isa(.String) then do + -- if numeric, then return it directly + if value~datatype('Number') then return value + -- the string true converts to the numeric version + if value == "true" then return .true + -- the default "not good value" result (which also handles + -- "false" + return 0 + end + else if value~isa(.nodeset) then do + -- nodesets have a string value...convert this and then + -- try to convert to numeric form + return self~convertNumber(self~convertString(value)) + end + return 0 -- unknown type...this is zero + +-- convert an object value to a string value. +::method convertString + use strict arg value + + -- already a string, then return directly. Note that this also + -- handles the number category. Strictly speaking, we should also + -- be returning "true" and "false", but this would mess up some + -- very common numeric values. + if value~isa(.string) then return value + -- if this is a node set, return the string value of the first + -- node. If the set is empty, return a null string + if value~isa(.nodeset) then do + if value~length = 0 then return "" + else return value[0]~nodeValue + end + -- last option...just return the string form of the object + return value~string + +-- an axis evaluation step in an expression +::class "XpathStep" subclass xpathexpr +::method init + expose axis nodeTest predicates + use strict arg axis, nodeTest = (.NodeTest~new(.Node~ANY_NODE)), predicates = (.array~new) + +::method evaluate + expose axis nodeTest + use strict arg context, container + + -- use the axis name to request our initial nodeset value + nodeSet = context~send(axis) + -- apply any type filtering + nodeSet = nodeTest~apply(nodeSet) + -- now filter by predicates + nodeSet = self~filterByPredicates(context, nodeSet) + return nodeSet + +-- apply and predicate filtering to this step +::method filterByPredicates + expose predicates + -- apply each predicate in turn + loop predicate over predicates + nodeSet = nodeSet~filter(context, predicate) + end + + return nodeSet + +-- a dyadic expression term +::class "XPathDyadicOperator" subclass XPathExpr +::method init + expose handler left right + -- the handler is the string name of the method to invoke + use strict arg handler, left, right + +::method evaluate + expose handler + -- just pass this along to the appropriate handler method using the + -- same arguments + forward message(handler) + +-- the operator methods +::method operatorPlus + expose left right + + return leftTerm~evaluateNumber(context) + rightTerm~evaluateNumber(context) + +::method operatorMinus + expose left right + + return leftTerm~evaluateNumber(context) - rightTerm~evaluateNumber(context) + +::method operatorMultiply + expose left right + + return leftTerm~evaluateNumber(context) * rightTerm~evaluateNumber(context) + +::method operatorDivide + expose left right + + return leftTerm~evaluateNumber(context) / rightTerm~evaluateNumber(context) + +::method operatorMod + expose left right + + return leftTerm~evaluateNumber(context) // rightTerm~evaluateNumber(context) + +::method operatorAnd + expose left right + + return leftTerm~evaluateBoolean(context) & rightTerm~evaluateBoolean(context) + +::method operatorOr + expose left right + + return leftTerm~evaluateBoolean(context) | rightTerm~evaluateBoolean(context) + +-- comparison methods +::method compareEqual + use strict arg left, right + return left = right + +::method compareNotEqual + use strict arg left, right + return left \= right + +::method compareLessThan + use strict arg left, right + return left < right + +::method compareLessThanEqual + use strict arg left, right + return left <= right + +::method compareGreaterThan + use strict arg left, right + return left > right + +::method compareGreaterThanEqual + use strict arg left, right + return left >= right + +-- returns true if the string value of any two members of the nodesets are true +-- using the comparison method +::method compareNodeSets + use strict arg comparison, left, right + + loop leftNode over left + loop rightNode over right + -- do the comparison method, and if true, return + if self~send(comparison, leftNode~nodeValue, rightNode~nodeValue) then + return .true + end + end + + -- nothing compared true, so false + return .false + +::method compareNodeSetToValue + use strict arg comparison, left, right, converter + + loop leftNode over left + if self~send(comparison, self~send(converter, left~nodeValue), right) then return .true + end + + return .false + +-- the equality operator. This is complicated by the different pairing +-- types that can occur between left and right +::method operatorEqual + expose left right + use strict arg context, container + + leftValue = left~evaluate(context) + rightValue = right~evaluate(context) + + -- handle booleans first, since the same comparison rules + -- apply to NodeSet values also. Boolean in this context + -- is the string "true" or "false" + if leftVal == "true" | leftValue == "false" then + return self~convertBoolean(leftVal) == self~convertBoolean(rightVal) + else if rightVal == "true" | rightValue == "false" then + return self~convertBoolean(leftVal) == self~convertBoolean(rightVal) + + -- nodeset comparisons + if leftVal~isA(.nodeset) then do + if rightVal~isA(.nodeset) then + return self~compareNodeSets("COMPAREEQUAL", leftVal, rightVal) + -- doing numeric comparisons? + if rightVal~isa(.string), rightVal~datatype('Number') then + return self~compareNodeSetToValue("COMPAREEQUAL", leftVal, rightVal, "CONVERTNUMBER") + -- string compare + return self~compareNodeSetToValue("COMPAREEQUAL", leftVal, rightVal, "CONVERTSTRING") + end + else if rightVal~isa(.nodeset) then do + -- doing numeric comparisons? + if leftVal~isa(.string), leftVal~datatype('Number') then + return self~compareNodeSetToValue("COMPAREEQUAL", rightVal, leftVal, "CONVERTNUMBER") + -- string compare + return self~compareNodeSetToValue("COMPAREEQUAL", rightVal, leftVal, "CONVERTSTRING") + end + else if leftVal~isa(.string), leftVal~datatype('Number') then + return leftVal = self~convertNumber(rightVal) + else if rightVal~isa(.string), rightVal~datatype('Number') then + return self~convertNumber(leftVal) = rightVal + else return leftVal == rightVal + +-- the inequality operator. This is complicated by the different pairing +-- types that can occur between left and right +::method operatorNotEqual + expose left right + use strict arg context, container + + leftValue = left~evaluate(context) + rightValue = right~evaluate(context) + + -- handle booleans first, since the same comparison rules + -- apply to NodeSet values also. Boolean in this context + -- is the string "true" or "false" + if leftVal == "true" | leftValue == "false" then + return self~convertBoolean(leftVal) \= self~convertBoolean(rightVal) + else if rightVal == "true" | rightValue == "false" then + return self~convertBoolean(leftVal) \= self~convertBoolean(rightVal) + + -- nodeset comparisons + if leftVal~isA(.nodeset) then do + if rightVal~isA(.nodeset) then + return self~co... [truncated message content] |
From: <bi...@us...> - 2012-07-08 01:04:07
|
Revision: 8013 http://oorexx.svn.sourceforge.net/oorexx/?rev=8013&view=rev Author: bigrixx Date: 2012-07-08 01:04:00 +0000 (Sun, 08 Jul 2012) Log Message: ----------- Some work on DOM Level 3 features Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-07 23:31:12 UTC (rev 8012) +++ incubator/orxutils/xml/xmldom.cls 2012-07-08 01:04:00 UTC (rev 8013) @@ -119,6 +119,8 @@ ::method normalize abstract ::method removeChild abstract ::method replaceChild abstract +::method lookupPrefix +::method lookupNamespaceURI -- an abstract attribute interface definition ::class "Attr" mixinclass Node public @@ -1535,16 +1537,44 @@ use strict arg other return self~identityHash = other~identityHash +-- resolve the prefix that a node is using for a given namespace URI ::method lookupPrefix use strict arg uri - raise syntax 93.963 -- not supported -::method isDefaultNamespace - use strict arg uri - raise syntax 93.963 -- not supported + -- this is the default behavior used for many nodes. Other nodes + -- will override this to provide different behaviors. + -- see if we have an element ancestor. + -- if we have one, ask for this from the element + ancestor = self~getElementAncestor + if ancestor \== .nil then return ancestor~lookupPrefix(uri) + return .nil + +-- resolve the namespace uri that a node is using for a given prefix ::method lookupNamespaceURI use strict arg prefix + + -- this is the default behavior used for many nodes. Other nodes + -- will override this to provide different behaviors. + + -- see if we have an element ancestor. + -- if we have one, ask for this from the element + ancestor = self~getElementAncestor + if ancestor \== .nil then return ancestor~lookupNamespaceURI(prefix) + return .nil + +-- find the first ancestor of this node that is an +-- element node +::method getElementAncestor + parent = self~parentNode + loop while parent \== .nil + if parent~nodeType == .Node~ELEMENT_NODE then return parent + parent = parent~parentNode + end + return .nil + +::method isDefaultNamespace + use strict arg uri raise syntax 93.963 -- not supported ::method isEqualNode @@ -2150,6 +2180,20 @@ self~isNormalized = .true +-- resolve the prefix that a node is using for a given namespace URI +::method lookupPrefix + use strict arg uri + + -- always returns .nil + return .nil + +-- resolve the namespace that a node is using for a given prefix +::method lookupNamespaceURI + use strict arg uri + + -- always returns .nil + return .nil + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Document */ @@ -2358,9 +2402,25 @@ self~setEventListeners(target, nodeListeners~copy) +-- resolve the prefix that a node is using for a given namespace URI +::method lookupPrefix + use strict arg uri + -- ask the root element for this (if we have one) + root = self~documentElement + if root \= .nil then return root~lookupPrefix(uri) + return .nil +-- resolve the namespace that a node is using for a given prefix +::method lookupNamespaceURI + use strict arg prefix + -- ask the root element for this (if we have one) + root = self~documentElement + if root \= .nil then return root~lookupNamespaceURI(prefix) + return .nil + + /** * Introduced in DOM Level 2. <p> * Distribution engine for DOM Level 2 Events. @@ -3033,6 +3093,30 @@ end end +-- resolve the prefix that a node is using for a given namespace URI +::method lookupPrefix + use strict arg uri + + -- if this node is owned and the owner is an attribute, then + -- pass along the lookup + ownerNode = self~ownerNode + if ownerNode \== .nil, ownerNode~nodeType == .Node~ELEMENT_NODE then + return ownerNode~lookupPrefix(uri) + + return .nil + +-- resolve the namespace that a node is using for a given prefix +::method lookupNamespaceURI + use strict arg prefix + + -- if this node is owned and the owner is an attribute, then + -- pass along the lookup + ownerNode = self~ownerNode + if ownerNode \== .nil, ownerNode~nodeType == .Node~ELEMENT_NODE then + return ownerNode~lookupNamespaceURI(prefix) + + return .nil + ::attribute idAttribute SET ::method isId @@ -4025,8 +4109,97 @@ return previous +-- resolve the prefix that a node is using for a given namespace URI +::method resolvePrefix + use strict arg uri + -- pass this along to the specialized lookup method + return self~lookupNamespacePrefix(uri, self) +-- resolve the prefix that a node is using for a given namespace URI +::method lookupNamespacePrefix private + use strict arg uri, originalElement + + namespace = self~namespaceURI + prefix = self~prefix + + -- the dom spec algorithm says that if the element has a namespace URI and + -- prefix, then perform the prefix lookup and see if that prefix actually + -- matches the uri. If it does, that gets returned. + if namespace == uri then do + if prefix \== .nil then do + if namespace = originalElement~lookupNamespaceURI(prefix) then + return prefix + end + end + + -- ok, no luck above, now check the attributes for the + -- appropriate definitions + + if self~hasAttributes then do + loop attribute over self~attributes + prefix = attribute~prefix + value = attribute~nodeValue + namespace = attribute~namespaceURI + if namespace == "http://www.w3.org/2000/xmlns/" then do + if attribute~nodeName == "xmlns" || (prefix == "xmlns" & value == uri) then do + localName = attribute~localName + if uri == originalElement~lookupNamespaceUri(localName) then return localName + end + end + end + end + + -- last chance...pass this up the element chain and ask again, using + -- the same original element + ancestor = self~getElementAncestor + if ancestor \= .nil then return ancestor~lookupNamespacePrefix(uri, originalElement) + -- unresolved + return .nil + +-- look up the namespace associate with a prefix +::method lookupNamespace + use strict arg specifiedPrefix + + namespace = self~namespaceURI + prefix = self~prefix + if namespace \== .nil then do + -- if the prefixes match, then return the namespace. Note that + -- this works even if both prefixes are .nil + if prefix == specifiedPrefix then return namespace + end + + -- ok, no luck above, now check the attributes for the + -- appropriate definitions + + if self~hasAttributes then do + loop attribute over self~attributes + prefix = attribute~prefix + value = attribute~nodeValue + namespace = attribute~namespaceURI + if namespace == "http://www.w3.org/2000/xmlns/" then do + -- if asking for the default namespace and this is the xmlns + -- attribute, then return the value, if it has one + if specifiedPrefix == .nil & attribute~nodeName = "xmlns" then do + if value \= "" then return value + else return .nil + end + else if prefix == "xmlns" & attribute~localname == specifiedPrefix then do + if value \= "" then return value + else return .nil + end + end + end + end + + -- last chance...pass this up the element chain and ask again, using + -- the same original element + ancestor = self~getElementAncestor + if ancestor \= .nil then return ancestor~lookupNamespaceURI(uri) + -- unresolved + return .nil + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: CharacterData -- base class for all nodes that carry character data */ @@ -4445,7 +4618,21 @@ ::attribute systemId ::attribute baseURI +-- resolve the prefix that a node is using for a given namespace URI +::method lookupPrefix + use strict arg uri + -- always returns .nil + return .nil + +-- resolve the namespace that a node is using for a given prefix +::method lookupNamespaceURI + use strict arg prefix + + -- always returns .nil + return .nil + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Entity -- an entity value */ @@ -4482,7 +4669,20 @@ ::attribute notationName ::attribute baseURI +-- resolve the prefix that a node is using for a given namespace URI +::method lookupPrefix + use strict arg uri + -- always returns .nil + return .nil + +-- resolve the namespace that a node is using for a given prefix +::method lookupNamespaceURI + use strict arg prefix + + -- always returns .nil + return .nil + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: EntityReference */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-08 16:41:46
|
Revision: 8016 http://oorexx.svn.sourceforge.net/oorexx/?rev=8016&view=rev Author: bigrixx Date: 2012-07-08 16:41:39 +0000 (Sun, 08 Jul 2012) Log Message: ----------- more DOM level 3 additions Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-08 05:42:29 UTC (rev 8015) +++ incubator/orxutils/xml/xmldom.cls 2012-07-08 16:41:39 UTC (rev 8016) @@ -119,8 +119,9 @@ ::method normalize abstract ::method removeChild abstract ::method replaceChild abstract -::method lookupPrefix -::method lookupNamespaceURI +::method lookupPrefix abstract +::method lookupNamespaceURI abstract +::method textContent abstract -- an abstract attribute interface definition ::class "Attr" mixinclass Node public @@ -892,7 +893,7 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: NamedNodeMap */ +/* Class: NamedNodeMapImpl */ /* Private methods */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -964,6 +965,20 @@ return .nil +-- determine the relative ordering of two contained nodes. If a +-- precedes b, return true, otherwise return false +::method precedes + expose attributes + use strict arg a, b + + if attributes \= .nil then do + loop node over attributes + if node == a then return .true + if node == .b then return .false + end + end + return .false + ::attribute ownerNode ::attribute hasDefaults ::attribute changed @@ -1377,6 +1392,14 @@ ::CLASS "NodeImpl" public inherit Node +-- DocumentPosition indicators +::constant DOCUMENT_POSITION_DISCONNECTED 1 +::constant DOCUMENT_POSITION_PRECEDING 2 +::constant DOCUMENT_POSITION_FOLLOWING 4 +::constant DOCUMENT_POSITION_CONTAINS 8 +::constant DOCUMENT_POSITION_IS_CONTAINED 16 +::constant DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC 32 + -- initialize a counter to give new nodes a unique id ::method init class expose ctr @@ -1525,14 +1548,244 @@ ::method compareDocumentPosition use strict arg other - raise syntax 93.963 -- not supported + -- if comparing a node against itself, then this is always equal + if self == other then return 0 + + -- this must be from the same dom type + if other \== .nil, \other~isa(.NodeImpl) then + .DomErrors~raiseError(.DomErrors~Not_supported_err) + + -- get the owners of the two nodes + if self~nodeType == .Node~DOCUMENT_NODE then + thisOwner = self + else thisOwner = self~ownerDocument + if other~nodeType == .Node~DOCUMENT_NODE then + otherOwner = other + else otherOwner = other~ownerDocument + + -- just punt and return a disconnected indicator if these have + -- different owners + if thisOwner \= otherOwner then + return self~DOCUMENT_POSITION_DISCONNECTED + + -- Find the ancestor of each node, and the distance each node is from + -- its ancestor. + -- During this traversal, look for ancestor/descendent relationships + -- between the 2 nodes in question. + -- We do this now, so that we get this info correct for attribute nodes + -- and their children. + + thisAncestor = self + otherAncestor = other + + thisDepth = 0 + otherDepth = 0 + + node = self + loop while node \= .nil + thisDepth += 1 + -- we're a descendant of other...this is an easy test. Other precedes us + -- and also contains us + if node == other then + return self~DOCUMENT_POSITION_CONTAINS + DOCUMENT_POSITION_PRECEDING + + thisAncestor = node + node = node~parentNode + end + -- we've reached the top without finding other. Now repeat for other to see + -- if we can find ourself. + node = other + loop while node \= .nil + otherDepth += 1 + -- we're a descendant of other...this is an easy test. Other follows us + -- and also contains us + if node == self then + return self~DOCUMENT_POSITION_CONTAINS + DOCUMENT_POSITION_FOLLOWING + + otherAncestor = node + node = node~parentNode + end + + thisAncestorType = thisAncestor~nodeType + otherAncestorType = otherAncestor~nodeType + thisNode = self + otherNode = other + + -- there's special casing for ENTITY, NOTATION, DOCTYPE and ATTRIBUTES, so + -- we need to pay attention to the types. This occurs because the document + -- type is sort of a side chain to the document. + + -- a child of a notation or entity...we need to step up a level and see + -- if we're decended from the other ancestor. + if thisAncestorType == .Node~NOTATION_NODE | thisAncestorType == .Node~ENTITY_NODE then do + container = thisOwner~doctype + if container = otherAncestor then + return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_PRECEDING + -- now look for the reverse relationship + if otherAncestorType == .Node~NOTATION_NODE | otherAncestorType == .Node~ENTITY_NODE then do + -- if the nodes are of different types, the order depends on the + -- type number + if thisAncestorType \= otherAncestorType then do + if thisAncestorType > otherAncestorType then + return self~DOCUMENT_POSITION_PRECEDING + else return self~DOCUMENT_POSITION_FOLLOWING + end + else do + -- this is either part of the doctype notations or entities, + -- so query the appropriate list + if thisAncestorType == .Node~NOTATION_NODE then do + if container~notations~precedes(otherAncestor, thisAncestor) then + return self~DOCUMENT_POSITION_PRECEDING + else + return self~DOCUMENT_POSITION_FOLLOWING + end + else do + if container~entities~precedes(otherAncestor, thisAncestor) then + return self~DOCUMENT_POSITION_PRECEDING + else + return self~DOCUMENT_POSITION_FOLLOWING + end + end + end + end + -- owned by a document type + else if thisAncestorType == .Node~DOCUMENT_TYPE_NODE then do + if otherNode == thisOwner then + return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_PRECEDING + else if thisOwner \== .nil & thisOwner == otherOwner then + return self~DOCUMENT_POSITION_FOLLOWING + end + -- an attribute + else if thisAncestorType == .Node~ATTRIBUTE_NODE then do + thisNode = thisAncestor~ownerElement + if otherAncestorType == .Node~ATTRIBUTE_NODE then do + otherNode = otherAncestor~ownerElement + -- if these attributes are owned by the same element, + -- life is easy...just check the container + if otherNode == thisNode then do + if thisNode~attributes~precedes(other, this) then + return self~DOCUMENT_POSITION_PRECEDING + else return self~DOCUMENT_POSITION_FOLLOWING + end + + -- owned by different elements...see if one element is an ancestor of + -- the other + thisDepth = 0 + node = thisNode + loop while node \= .nil + thisDepth += 1 + -- the other node is an ancestor of the owning element, which + -- means it precedes this one + if node == otherNode then + return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_PRECEDING + thisAncestor = node + node = node~parentNode + end + end + end + -- still unresolved...we need to repeat most of the above from the + -- perspective of the other node now + if otherAncestorType == .Node~NOTATION_NODE | otherAncestorType == .Node~ENTITY_NODE then do + container = thisOwner~doctype + if container = this then + return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_FOLLOWING + otherNode = thisOwner + otherAncestor = thisOwner + end + -- owned by a document type + else if otherAncestorType == .Node~DOCUMENT_TYPE_NODE then do + if thisNode == otherOwner then + return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_FOLLOWING + else if otherOwner \== .nil & thisOwner == otherOwner then + return self~DOCUMENT_POSITION_PRECEDING + end + -- an attribute. We already know they are not both attributes + else if otherAncestorType == .Node~ATTRIBUTE_NODE then do + otherDepth = 0 + otherNode = otherAncestor~ownerElement + node = otherNode + loop while node \= .nil + otherDepth += 1 + -- the other node is an descendent of the reference node's element, which + -- means it follows this one + if node == otherNode then + return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_FOLLOWING + otherAncestor = node + node = node~parentNode + end + end + + -- thisAncestor and otherAncestor must be the same at this point, + -- otherwise, the original nodes are disconnected + if thisAncestor \= otherAncestor then do + return self~DOCUMENT_POSITION_DISCONNECTED + end + + -- Go up the parent chain of the deeper node, until we find a node + -- with the same depth as the shallower node + if thisDepth > otherDepth then do + loop for thisDepth - otherDepth + thisNode = thisNode~parentNode + end + -- Check if the node we have reached is in fact "otherNode". This can + -- happen in the case of attributes. In this case, otherNode + -- "precedes" this. + if thisNode == otherNode then + return self~DOCUMENT_POSITION_PRECEDING; + end + -- moving up the way + else do + loop for otherDepth - thisDepth + otherNode = otherNode~parentNode + end + -- Check if the node we have reached is in fact "thisNode". This can + -- happen in the case of attributes. In this case, otherNode + -- "follow" this. + if thisNode == otherNode then + return self~DOCUMENT_POSITION_PRECEDING; + end + -- We now have nodes at the same depth in the tree. Find a common + -- ancestor. + thisNodeParent = thisNode~parentNode + otherNodeParent = otherNode~parentNode + loop while thisNodeParent \= otherNodeParent + thisNode = thisNodeParent + otherNode = otherNodeParent + thisNodeParent = thisNodeParent~parentNode + otherNodeParent = otherNodeParent~parentNode + end + + -- At this point, thisNode and otherNode are direct children of + -- the common ancestor. + -- See whether thisNode or otherNode is the leftmost + + current = thisNodeParent~firstChild + loop while current \= .nil + if current == otherNode then + return self~DOCUMENT_POSITION_PRECEDING + else if current == thisNode then + return self~DOCUMENT_POSITION_FOLLOWING + current = current~nextSibling + end + + -- should never get here...throw up our hands and + -- say they are disconnected. + return self~DOCUMENT_POSITION_DISCONNECTED + +-- get the default text content for a node. This is +-- the same as the nodevalue for many node types ::attribute textContent GET forward message("NODEVALUE") +-- default set text content operation. For most nodes, +-- this sets the nodevalue. ::attribute textContent SET forward message("NODEVALUE=") +-- verify that two nodes are in fact the same node. +-- since we use direct references rather than some sort of +-- proxy, this is a very easy determination. ::method isSameNode use strict arg other return self~identityHash = other~identityHash @@ -2043,6 +2296,9 @@ self~ownerDocument~replacedNode(self) return oldChild +-- default textContent behavior for most node types that +-- allow children. This concatenates all child text nodes into a +-- single string ::attribute textContent GET use strict arg @@ -2090,6 +2346,9 @@ return \child~isIgnorableWhitespace +-- default text content method for nodes that allow children. This +-- will remove ALL child nodes and replace them with a single text node +-- with the new content ::attribute textContent SET use strict arg text child = self~firstChild @@ -4589,7 +4848,18 @@ use strict arg return notations +-- override for text content. For this type, it always +-- returns .nil +::attribute textContent GET + use strict arg + return .nil +-- override for setting text content. For this type, it has no effect. +::attribute textContent SET + use strict arg value + -- this is a NOP for nodes where this has no meaning. + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Notation */ @@ -4632,7 +4902,18 @@ -- always returns .nil return .nil +-- override for text content. For this type, it always +-- returns .nil +::attribute textContent GET + use strict arg + return .nil +-- override for setting text content. For this type, it has no effect. +::attribute textContent SET + use strict arg value + -- this is a NOP for nodes where this has no meaning. + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Entity -- an entity value */ @@ -6917,13 +7198,16 @@ end return oldChild +-- document override for text content. For this type, it always +-- returns .nil ::attribute textContent GET use strict arg return .nil +-- override for setting text content. For this type, it has no effect. ::attribute textContent SET use strict arg value - -- this is a NOP + -- this is a NOP for nodes where this has no meaning. ::method getFeature expose xpathEvaluator This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-08 17:26:47
|
Revision: 8017 http://oorexx.svn.sourceforge.net/oorexx/?rev=8017&view=rev Author: bigrixx Date: 2012-07-08 17:26:40 +0000 (Sun, 08 Jul 2012) Log Message: ----------- Some work on DOM Level 3 features Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-08 16:41:39 UTC (rev 8016) +++ incubator/orxutils/xml/xmldom.cls 2012-07-08 17:26:40 UTC (rev 8017) @@ -236,6 +236,9 @@ ::method removeNamedItemNS abstract ::method setNamedItem abstract ::method setNamedItemNS abstract +::method publicID abstract +::method systemID abstract +::method internalSubset abstract -- abstract notation definition ::class "Notation" mixinclass Node public @@ -979,6 +982,26 @@ end return .false +-- compare two NamedNodeMaps for equality. To be equal, each named item in +-- each collection must be equal to the equivalent item in the other map. +-- order is not important +::method isEqual + expose attributes + use strict arg other + + -- these can't be equal if they contain a different number of items + if self~length \= other~length then return .false + + -- these are independent of order, so we need to look up by name + -- and compare the items. Any mismatch is a failure + loop attr over attributes + otherAttr = other~getNamedItemNS(attr~namespaceURI, attr~name) + if otherAttr == .nil then return .false + if \attr~isEqualNode(otherAttr) then return .false + end + -- passed all of the tests...yay! + return .true + ::attribute ownerNode ::attribute hasDefaults ::attribute changed @@ -986,14 +1009,6 @@ /*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/* Class: NamedNodeMap */ -/* Public methods */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - - -/*----------------------------------------------------------------------------*/ /* Method: getNamedItem */ /* Description: get a named item. */ /*----------------------------------------------------------------------------*/ @@ -1832,33 +1847,40 @@ ::method isEqualNode use strict arg other + -- a node is always equal to itself + if self == other then return .true - if self == other then do - return .true - end + -- the spec defines the following properties as required to be equal + -- in order to pass + if self~nodetype \= other~nodetype then return .false + if self~nodename \= other~nodename then return .false - if self~nodetype \= other~nodetype then do - return .false - end + if self~localname \= other~localname then return .false - if self~nodename \= other~nodename then do - return .false - end + if self~namespaceURI \= other~namespaceURI then return .false + if self~prefix \= other~prefix then return .false + if self~nodevalue \= other~nodevalue then return .false - if self~localname \= other~localname then do - return .false - end + -- the attributes, must be equivalent. For attributes, they + -- must all exist on both nodes and have the same values. Order + -- is not important. + thisAttr = self~attributes + otherAttr = other~attributes - if self~namespaceURI \= other~namespaceURI then do - return .false + -- if we have attributes, compare the sets + if thisAttr \== .nil then do + if otherAttr == .nil then return .false + if \thisAttr~isEqual(otherAttr) then return .false end + else if otherAttr \== .nil then return .false - if self~prefix \= other~prefix then do - return .false - end + thisChildren = self~children + otherChildren = other~children - if self~nodevalue \= other~nodevalue then do - return .false + if thisChildren~length \= otherChildren~length then return .false + -- the children must be equal at every position...order is dependent here. + loop i = 0 for this~children + if \thisChildren~item(i)~isEqualNode(otherChildren~item(i)) then return .false end ::method getFeature @@ -4787,35 +4809,21 @@ ::class "DocumentTypeImpl" public subclass NodeImpl inherit DocumentType - /*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/* Class: DocumentType */ -/* Private methods */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/* Class: DocumentType */ -/* Public methods */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - - -/*----------------------------------------------------------------------------*/ /* Method: init */ /* Description: instance initialization. */ /*----------------------------------------------------------------------------*/ ::method init - use strict arg name - self~nodeName = name - self~nodeType = 10 + expose publicID systemID + use strict arg self~nodename, publicID, systemID + self~nodeType = .Node~DOCUMENT_TYPE_NODE self~nodeValue = .nil self~entities = .NamedNodeMapImpl~new self~notations = .NamedNodeMapImpl~new + self~publicID = .nil + self~systemID = .nil + self~internalSubset = .nil /*----------------------------------------------------------------------------*/ /* Method: name */ @@ -4859,7 +4867,26 @@ use strict arg value -- this is a NOP for nodes where this has no meaning. +-- override for the default node isEqual method. DocumentType nodes have +-- different equality rules +::method isEqualNode + use strict arg other + if other~nodeType \== self~nodeType then return .false + if self~publicId \= other~publicId then return .false + if self~systemId \= other~systemId then return .false + if self~internalSubset \= other~internalSubset then return .false + + -- the notations and entities must be equal + if \self~notations~isEqual(other~notations) then return .false + return self~entities~isEqual(other~entities) + +-- general attributes +::attribute internalSubset +::attribute publicID +::attribute systemID + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Notation */ @@ -5106,7 +5133,7 @@ ::method createDocumentType use strict arg qualifiedName, publicID, systemID self~checkQName(qualifiedName) - return .DocumentType(.nil, qualifiedName, publicID, systemID) + return .DocumentTypeImpl(qualifiedName, publicID, systemID) ::method checkQName use strict arg qname This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-08 20:45:23
|
Revision: 8018 http://oorexx.svn.sourceforge.net/oorexx/?rev=8018&view=rev Author: bigrixx Date: 2012-07-08 20:45:17 +0000 (Sun, 08 Jul 2012) Log Message: ----------- rework attr node for DOM level 3 additions Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-08 17:26:40 UTC (rev 8017) +++ incubator/orxutils/xml/xmldom.cls 2012-07-08 20:45:17 UTC (rev 8018) @@ -127,9 +127,10 @@ ::class "Attr" mixinclass Node public ::method name abstract ::method ownerElement abstract -::method isSpecified abstract +::method specified abstract ::method value abstract ::method "value=" abstract +::method isId abstract -- an abstract characterdata interface definition ::class "CharacterData" mixinclass Node public @@ -174,6 +175,7 @@ ::method implementation abstract ::method version abstract ::method importNode abstract +::method adoptNode abstract ::method "encoding=" abstract -- abstract documentfragment definition @@ -1259,7 +1261,7 @@ attributes[i] = attribute previous~ownerNode = self~ownerNode~ownerDocument previous~isOwned = .false - previous~isSpecified = .true + previous~specified = .true end else do if attributes = .nil then do @@ -1290,7 +1292,7 @@ attributes[index] = attribute previous~ownerNode = self~ownerNode~ownerDocument previous~isOwned = .false - previous~isSpecified = .true + previous~specified = .true end else do if attributes = .nil then do @@ -1361,7 +1363,7 @@ newAttr~ownerNode = self~ownerNode newAttr~isOwned = .true -- mark this as a default value - newAttr~isSpecified = .false + newAttr~specified = .false attributes[index] = newAttr setdefault = .true -- if this is the id attribute, make sure the document knows @@ -1379,8 +1381,8 @@ -- detach from usage attr~ownerNode = .nil attr~isOwned = .false - attr~isSpecified = .true - attr~idAttribute = .false + attr~specified = .true + attr~isId = .false -- notify the document ownerDocument~removedAttrNode(attr, self~ownerNode, name) @@ -3284,25 +3286,23 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "AttrImpl" public subclass NodeImpl inherit Attr +::class "AttrImpl" public subclass ParentNode inherit Attr ::method init - expose value nodeName textNode namespaceURI localName type idAttribute prefix - value = .nil + expose nodeName textNode namespaceURI localName type isId prefix type = .nil - textNode = .nil namespaceURI = .nil localName = .nil prefix = .nil - idAttribute = .false + isId = .false use strict arg ownerDoc, nodeName, namespaceURI = .nil, explicitLocalName = .nil self~init:super(ownerDoc) self~setName(nodeName) if explicitLocalName \= .nil then do localName = explicitLocalName end - self~isSpecified = .false - self~hasStringValue = .true + self~specified = .false +-- process a name change for this attribute ::method setName private expose namespaceURI localName prefix use arg qname @@ -3362,18 +3362,6 @@ ::attribute localName GET -::attribute ownerDocument SET private - expose value - use strict arg doc - forward class(super) continue - if \self~hasStringValue then do - child = value - do while child \= .nil - child~ownerDocument = doc - child = child~nextSibling - end - end - -- resolve the prefix that a node is using for a given namespace URI ::method lookupPrefix use strict arg uri @@ -3398,28 +3386,15 @@ return .nil -::attribute idAttribute SET +::attribute isId -::method isId - expose idAttribute - return idAttribute - ::method cloneNode expose value use strict arg deep = .false newNode = self~cloneNode:super(deep) - if \self~hasStringValue then do - close~value = .nil - child = value - do while child \= .nil - newNode~appendChild(child~cloneNode(.true)) - child = child~nextSibling - end - end - - newNode~isSpecified = .true + newNode~specified = .true return newNode ::attribute nodeType GET @@ -3477,126 +3452,61 @@ -- we provide all of our own type information directly return this - -- name is the same as nodename ::attribute name GET forward message("NODENAME") ::attribute name SET forward message("NODENAME=") +-- set the attribute value ::attribute value SET - expose value textNode use strict arg newValue + -- we might need to send mutation events, so get the old value + if self~ownerDocument~hasMutationEvents then + -- get the old value (normalized) + oldValue = self~textcontent:super - oldvalue = "" + -- this gets handled by normal text content removal/addition + forward message("TEXTCONTENT=") class(super) continue - -- we might need to process an old value if it's a serious of text nodes - if value \= .nil then do - if self~ownerDocument~hasMutationEvents then do - if self~hasMutationEvents then do - -- if we have a string value and we need to - -- broadcast mutation events, then we need to - -- convert this into a text node for the event - if self~hasStringValue then do - oldValue = value - if textNode == .nil then do - textNode = self~ownerDocument~createTextNode(value) - end - else do - textNode~data = value - end - -- set the value to be a text node rather than a string - value = textNode - textNode~ownerNode = this - textNode~isOwned = .true - self~removeChild(textNode, .true) - end - else do - oldValue = self~value - do while value \= .nil - self~removeChild(value, .true) - end - end - end - end - else do - if self~hasStringValue then do - oldValue = value - end - else do - -- discard any text children - oldValue = self~value - firstChild = value - firstChild ownerNode = self~ownerDocument - end - -- remove the existing value - value = .nil - end - end - - self~isSpecified = .true - if self~ownerDocument~hasMutationEvents then do - self~insertBefore(self~ownerDocument~createTextNode(newValue), .nil, .true) - self~hasStringValue = .false + self~specified = .true + if self~ownerDocument~hasMutationEvents then self~ownerDocument~modifiedAttrValue(self, oldvalue) - end - else do - value = newValue - self~changed - end + else self~changed if self~isId & self~ownerElement \= .nil then do self~ownerDocument~putIdentifier(newvalue, ownerElement) end +-- set the value of the attribute. This adds a text node to the attribute +-- node ::attribute value GET - expose value use strict arg - -- no set value is a null string - if value == .nil then do - return "" - end - -- if already a string, then return it directly - if value~isA(.String) then do - return value - end + -- this is the same as text content with the addition of the + -- buildTextContent override + forward message("TEXTCONTENT") class(super) - -- this is a potential chain of child nodes - firstChild = value - - if firstChild~nodeType == .Node~ENTITY_REFERENCE_NODE then do - data = firstChild~entryRefValue - end - else do - data = firstChild~nodeValue - end - -- no data at this point, return a null string - if data == .nil then do - return "" - end - - node = firstChild~nextSibling - -- if the only child node, we're done - if node == .nil then do - return data - end - - buffer = .mutableBuffer~new(data) - - do while node \= .nil - if firstChild~nodeType == .Node~ENTITY_REFERENCE_NODE then do - data = firstChild~entryRefValue - if data \= .nil then do - buffer~append(data) - end +-- override to the Node buildTextContent method to include +-- entity reference nodes in the mix +::method buildTextContent private + use arg buffer + child = self~firstChild + do while child \= .nil + if child~nodeType == .Node~ENTITY_REFERENCE_NODE then + data = child~entryRefValue + else if self~hasTextContent(child) then + data = child~nodeValue + if data \== .nil then do + buffer~append(data) end - else do - buffer~append(firstChild~nodeValue) - end - node = node~nextSibling + child = child~nextSibling end - return buffer~string +-- overrides to make sure this passes through the value attributes +::attribute textContent GET + forward message("VALUE") +::attribute textContent SET + forward message("VALUE=") ::attribute element GET use strict arg @@ -3612,204 +3522,8 @@ forward message("ELEMENT") -- some attribute properties -::attribute hasStringValue -::attribute isSpecified +::attribute specified -::method hasChildNodes - expose value - use strict arg - return value \= .nil - -::method childNodes - -- we handle the node list methods directly - use strict arg - return self - -::method firstChild - expose value - use strict arg - self~makeChildNode - return value - -::method lastChild - expose value - use strict arg - - self~makeChildNode - - child = value - previous = .nil - - do while child \= .nil - previous = child - child = child~nextSibling - end - - return previous - -::method insertBefore - expose value - use strict arg newChild, refChild, replace = .false - - -- if this is a fragment, transfer each of the - -- children from the fragment to ourselves - if newChild~nodeType == .Node~DOCUMENT_FRAGMENT_MODE then do - do while newChild~hasChildNodes - self~insertBefore(newChild~firstChild, refChild) - end - return newChild - end - -- already here? This is a little silly, but the event model - -- requires us to remove it and the reinsert - if newChild == refChild then do - refChild = refChild~nextSibling - self~removeChild(newChild) - self~insertBefore(newChild, refChild) - return newChild - end - -- ensure if we just have a string value that it is converted into a text - -- node - self~makeChildNode - - self~ownerDocument~insertingNode(self, replace) - -- detach from any existing parent node - oldParent = newChild~parentNode - - if oldParent \= .nil then do - oldParent~removeChild(newNode) - end - - newNode~ownerNode = this - newNode~isOwned = .true - - firstChild = value - -- no existing value, this case is easy - if firstChild == .nil then do - value = newChild - end - else do - -- append operation? - if refNode == .nil then do - lastChild = self~lastChild - lastChild~nextSibling = newNode - newNode~previousSibling = lastChild - end - -- normal insertion - else do - if refChild == firstChild then do - newNode~nextSibling = firstChild - firstChild~previousSibling = newNode - newNode~previousSibling = .nil - value = newNode - end - else do - previous = refNode~previousSibling - newNode~nextSibling = refNode - previous~nextSibling = newNode - refNode~previousSibling = newNode - newNode~previousSibling = previous - end - end - end - - -- record the change - self~changed - - self~ownerDocument~insertedNode(self, newNode, replace) - - return newChild - -::method removeChild - expose value - use strict arg oldChild, replace = .false - - if value~isA(.string) then do - return .nil - end - - self~ownerDocument~removingNode(self, oldNode, replace) - - -- removing the first? - if oldNode == value then do - value = oldNode~nextSibling - if value \= .nil then do - value~previousSibling = .nil - end - end - else do - previous = oldNode~previousSibling - next = oldNode~nextSibling - previous~nextSibling = next - if next \= .nil then do - next~previousSibling = previous - end - end - - oldNode~ownerNode = self~ownerDocument - oldNode~isOwned = .false - oldNode~nextSibling = .nil - oldNode~previousSibling = .nil - - self~changed - - ownerDocument~removedNode(self, replace) - - return oldNode - -::method replaceChild - use strict arg newChild, oldChild - - self~makeChildNode - self~ownerDocument~replacingNode(self) - self~insertBefore(newChild, oldChild, .true) - if newChild \= oldChild then do - self~removeChild(oldChild, .true) - end - - self~ownerDocument~repacingNode(self) - return oldChild - --- NodeList methods -::attribute length GET - expose value - use strict arg - - if value~isA(.string) then do - return 1 - end - - child = value - length = 0 - do while child \= .nil - length += 1 - child = child~nextSibling - end - - return length - -::method item - expose value - use strict arg index - - if value~isA(.String) then do - if index \= 0 then do - return .nil - end - self~makeChildNode - return value - end - else do - if index < 0 then do - return .nil - end - node = value - do i = 0 to index while node \= .nil - node = node~nextSibling - end - return node - end - - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Element */ @@ -4138,7 +3852,7 @@ ::method setIdAttributeNode use strict arg at, makeId - at~idAttribute = makeId + at~isId = makeId if makeId then do self~ownerDocument~putIdentifier(at~value, this) end @@ -4154,7 +3868,7 @@ return end - at~idAttribute = makeId + at~isID = makeId if makeId then do self~ownerDocument~putIdentifier(at~value, this) end @@ -4170,7 +3884,7 @@ return end - at~idAttribute = makeId + at~isId = makeId if makeId then do self~ownerDocument~putIdentifier(at~value, this) end @@ -7369,7 +7083,7 @@ sourceAttrs = source~attributes if sourceAttrs \= .nil then do do attr over sourceAttrs - if attr~isSpecified | cloningDoc then do + if attr~specified | cloningDoc then do -- if we're just importing, ignore the default attributes. newAttr = self~importNode(attr, .true, cloningDoc, reversedIdentifiers) if attr~localName == .nil then do @@ -7401,15 +7115,8 @@ else do newNode = self~createAttributeNS(source~namespaceURI, source~nodeName) end - -- we'll do a deep copy, unless this can be avoided in the simple - -- cases + -- we'll do a deep copy deep = .true - -- if we have a string value, we can just copy that and - -- avoid doing the deep copy - if attr~hasStringValue then do - newNode~value = attr~value - deep = .false - end end when type == .Node~TEXT_NODE then do newNode = self~createTextNode(source~nodeValue) @@ -7487,6 +7194,9 @@ end return newNode +-- adopt a node from another document. This does not copy the +-- tree, but rather removes from its existing owner and +-- inserts into the new document. ::method adoptNode expose docType use strict arg source @@ -7505,7 +7215,7 @@ end -- this is now specified, since it's no longer -- derived from a default associated with an element - source~isspecified = .true + source~specified = .true -- change the owner source~ownerDocument = self end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-09 00:29:54
|
Revision: 8019 http://oorexx.svn.sourceforge.net/oorexx/?rev=8019&view=rev Author: bigrixx Date: 2012-07-09 00:29:47 +0000 (Mon, 09 Jul 2012) Log Message: ----------- more DOM 3 cleanup work Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-08 20:45:17 UTC (rev 8018) +++ incubator/orxutils/xml/xmldom.cls 2012-07-09 00:29:47 UTC (rev 8019) @@ -253,6 +253,22 @@ ::method target abstract ::method "data=" abstract +-- interface class for implementing a user data handler +::class "UserDataHandler" mixinclass object +::constant NODE_CLONED 1 +::constant NODE_IMPORTED 2 +::constant NODE_DELETED 3 +::constant NODE_RENAMED 4 +::constant NODE_ADOPTED 5 + +-- called as handle(key, data, srcNode, destNode) +::method handle + +-- interface class for implementing a DOM event handler +::class "DOMEventListener" mixinclass object +-- called as handleEvent(event) +::method handleEvent + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Section: Concrete implementation of the DOM classes */ @@ -1207,7 +1223,7 @@ ::attribute attributes PRIVATE --- some convience methods for Rexx collection appearances +-- some convienence methods for Rexx collection appearances ::method makearray expose attributes use strict arg @@ -1435,13 +1451,12 @@ /*----------------------------------------------------------------------------*/ ::method init - expose ownerNode childNodes nodeId + expose ownerNode nodeId userData use strict arg ownerNode = .nil nodeId = self~class~getId - childNodes = .NodeListImpl~new + userData = .nil -- no userdata self~isowned = .false -- unowned until we are added as a child self~readonly = .false -- newly created nodes can be altered - self~isFirstChild = .false -- not the first child until added to something. self~isOwned = .false -- not owned until attached self~isIgnorableWhitespace = .false -- only text nodes have this @@ -1522,7 +1537,6 @@ -- private attributes used for the implementation ::attribute isowned ::attribute readonly -::attribute isFirstChild -- default implementations designed to be overridden ::method hasChildNodes @@ -1889,13 +1903,15 @@ use strict arg feature, version return .nil +-- associate an object to a key on this node. ::method setUserData - use strict arg key, date, handler - raise syntax 93.963 -- not supported + use strict arg key, data, handler + return self~ownerDocument~setUserData(self, key, data, handler) +-- retrieve userdata associated with this node for a given key ::method getUserData use strict arg key - raise syntax 93.963 -- not supported + return self~ownerDocument~setUserData(self, key) -- handle mutation events ::method changed @@ -2118,7 +2134,6 @@ -- detach the new instance from the context newNode~previousSibling = .nil newNode~nextSibling = .nil - newNode~isFirstChild = .false return newNode @@ -2479,13 +2494,13 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: Document */ +/* Class: DocumentImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ ::class "DocumentImpl" subclass ParentNode public inherit Document ::method init - expose iterators ranges eventListeners grammarAccess doctype hasMutationEvents - use arg doctype = .nil, grammarAccess = .false + expose iterators ranges eventListeners doctype hasMutationEvents + use arg doctype = .nil self~init:super iterators = .nil @@ -2589,10 +2604,16 @@ end end +::method removedAttrNode + use strict arg attr, oldOwner, name +::method renamedAttrNode + use strict arg oldAttr, newAttr + + ::method createEvent use strict arg type - if type~caselessEquals("Events") then do + if type~caselessEquals("Event") then do return .DOMEvent~new end else if type~caselessEquals("MutationEvent") then do @@ -2609,7 +2630,7 @@ use strict arg node, listeners if eventListeners == .nil then do - eventListeners = new table + eventListeners = .table~new end if listeners == .nil then do @@ -3205,7 +3226,6 @@ self~dispatchAggregateEvents(oldOwner) -::method renamedAttrNode ::method renamedElement ::class "EventListenerImpl" public @@ -3226,6 +3246,7 @@ return phase == useCapture & type == eventType +-- invoke an event handler with ::method invoke expose listener use strict arg event @@ -3272,14 +3293,6 @@ bubbles -= 1 end -::class "EnclosingAttr" public -::method init - expose node oldValue - use strict arg node, oldValue - -::attribute node GET -::attribute oldValue GET - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Attr */ @@ -6810,27 +6823,21 @@ /*----------------------------------------------------------------------------*/ ::class "CoreDocument" subclass DocumentImpl public ::method init - expose docType docElement encoding actualEncoding version standalone documentURI - - userdata identifiers domNormalizer configuration xpathEvaluator changes - - allowGrammerAccess errorChecking documentNumber nodeCounter nodeTable - use strict arg docType = .nil, grammarAccess = .false + expose docType docElement version standalone documentURI - + userdata identifiers changes - + documentNumber nodeCounter nodeTable + use strict arg docType = .nil self~init:super(.nil) -- we are our own owning document for purposes of child appends self~ownerDocument = self docElement = .nil - encoding = .nil - actualEncoding = .nil version = .nil standalone = .false documentURI = .false userData = .nil identifiers = .nil - domNormalizer = .nil - configuration = .nil - xpathEvaluator = .nil changes = 0 - errorChecking = .true documentNumber = 0 nodeCounter = 0 nodeTable = .nil @@ -6841,10 +6848,12 @@ appendChild(docType) end +-- get the node type ::attribute nodeType GET use strict arg return .Node~DOCUMENT_NODE +-- the node name is a constant for documents ::attribute nodeName GET use strict arg return "#document" @@ -6878,9 +6887,7 @@ end end - newDoc~allowGrammarAccess = self~allowGrammarAccess - newDoc~errorChecking = self~errorChecking - +-- insert a node into the document ::method insertBefore expose docElement docType use strict arg newChild, refChild @@ -6892,8 +6899,8 @@ end -- do a normal insert self~insertBefore:super(newChild, refChild) - -- we only have two types of children, so cache each of - -- type types + -- we have two special types of children, so cache each + -- type if type == .Node~ELEMENT_NODE then do docElement = newChild end @@ -6902,6 +6909,7 @@ end return newChild +-- override for a remove child ::method removeChild expose docElement docType use strict arg oldChild @@ -7038,12 +7046,6 @@ return .DomImplementation~getDOMImplementation -::attribute errorChecking -::attribute strictErrorChecking - -::attribute inputEncoding -::attribute xmlEncoding - ::attribute documentURI ::attribute changes GET @@ -7294,6 +7296,32 @@ return .nil +-- rename a target node using the new namespaceURI and qualified name +::method renameNode + use strict arg node, namespaceURI, name + + newNode = node + if node~nodeType == .Node~ELEMENT_NODE then do + node~rename(namespaceURI, name) + self~callUserDataHandlers(node, .nil, .UserDataHandler~NODE_RENAMED) + self~renamedElement(node, node) + end + else if node~nodeType == .Node~ATTRIBUTE_NODE then do + -- detach the attr from its owning element + owner = node~ownerElement + if owner \= .nil then + owner~removeAttributeNode(node) + -- rename and reattach, if we have an owner + node~rename(namespaceURI, name) + if owner \= .nil then + owner~setAttributeNodeNS(node) + self~callUserDataHandlers(node, .nil, UserDataHandler~NODE_RENAMED) + -- fire AttributeNameChanged event + self~renamedAttrNode(node, node) + end + else + self~domError(.DOMException~NOT_SUPPORTED_ERR) + ::method clearIdentifiers private expose identifers if identifers \= .nil then do @@ -7308,25 +7336,22 @@ self~removeIdentifier(name) end else do - if identifiers == .nil then do + if identifiers == .nil then identifiers = .directory~new - end identifers[name] = element end ::method removeIdentifier expose identifiers use strict arg name - if identifiers == .nil then do + if identifiers == .nil then return - end identifers~remove(name) ::method identifiers - if identifiers == .nil then do + if identifiers == .nil then identifiers = .directory~new - end return identifers~allIndexes @@ -7342,74 +7367,102 @@ expose changes changes += 1 -::method addEventListener - use strict arg node, type, listener, useCapture - -- this is a nop +-- call user data handlers when a node is deleted +::method callUserDataHandlers + expose userData + use strict arg node, copyNode, operation + -- if no userdata, then this is easy + if userData == .nil then return -::method removeEventListener - use strict arg node, type, listener, useCapture + -- get the userdata for this node + userData = node~userDataRecord + if userData == .nil then return + if userData~isempty then return -::method copyEventListeners - use strict arg source, target + loop key over userData + dataRecord = userData[key] + if dataRecord~handler \== .nil then + dataRecord~handler~handle(operation, key, dataRecord~data, node, copyNode) + end -::method dispatchEvent - use strict arg node, event -::method replacedText - use strict arg node +-- associate an object to a key on this node +::method setUserData + expose userdata + use strict arg node, key, data, handler -::method deletedText - use strict arg node, offset, count + -- .nil for data means delete this key + if data == .nil then do + -- can only delete if we have data + if userdata \== .nil then do + -- this is keyed to the node instance + nodeData = userData[node] + if nodeData \== .nil then do + oldData = nodeData~remove(key) + if oldData \== .nil then return oldData~data + end + end + return .nil + end + else do + if userData == .nil then do + userData = .IdentityTable~new + nodeData = .Directory~new + userData[node] = nodeData + end + else do + nodeData = userData[node] + if nodeData = .nil then do + nodeData = .Directory~new + userData[node] = nodeData + end + end + -- just use a directory object for this + userRecord = .directory~new + userRecord~data = data + userRecord~handler = handler + oldData = nodeData[key] + nodeData[key] = userRecord + if oldData \== .nil then return oldData~data + end + return .nil -::method insertedText - use strict arg node, offset, count +-- retrieve the object associated to a key on this node +::method getUserData + expose userData + use strict arg node, key -::method modifyingCharacterData - use strict arg node, replace + -- no user data registered, so nothing to return + if userData == .nil then return .nil + nodeData = userData[node] + if nodeData == .nil then return .nil -::method modifiedCharacterData - use strict arg node, oldValue, value, replace + userRecord = nodeData[key] + if userRecord \== .nil then return userRecord~data + return .nil -::method insertingNode - use strict arg node, replace +-- retrieve the userdata table for a given node +::method getUserDataTable + expose userData -::method insertedNode - use strict arg node, newInternal, replace + if userData == .nil then return .nil + return userData[null] -::method removingNode - use strict arg node, oldChild, replace - -::method removedNode - use strict arg node, replace - -::method replacingNode +-- remove a nodes user data table +::method removeUserDataTable + expose userdata use strict arg node -::method replacedNode - use strict arg node + if userData == .nil then return .nil + return userData~remove(node) -::method replacingData +-- set a user data table for a node. +::method setUserDataTable + expose userData use strict arg node + if userData == .nil then userData = .IdentityTable~new + if data \== .nil then userData[node] = data -::method replacedCharacterData - use strict arg node, oldValue, value - -::method modifiedAttrValue - use strict arg attr, oldValud - -::method setAttrNode - use strict arg attr, previous - -::method removedAttrNode - use strict arg attr, oldOwner, name - -::method renamedAttrNode - use strict arg oldAttr, newAttr - -::method renamedElement - use strict arg oldElement, newElement - - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Section: XPath parser and evaluation engine */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-09 11:38:43
|
Revision: 8020 http://oorexx.svn.sourceforge.net/oorexx/?rev=8020&view=rev Author: bigrixx Date: 2012-07-09 11:38:32 +0000 (Mon, 09 Jul 2012) Log Message: ----------- add isDefaultNamespace support Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-09 00:29:47 UTC (rev 8019) +++ incubator/orxutils/xml/xmldom.cls 2012-07-09 11:38:32 UTC (rev 8020) @@ -122,6 +122,7 @@ ::method lookupPrefix abstract ::method lookupNamespaceURI abstract ::method textContent abstract +::method isDefaultNamespace -- an abstract attribute interface definition ::class "Attr" mixinclass Node public @@ -1847,6 +1848,18 @@ if ancestor \== .nil then return ancestor~lookupNamespaceURI(prefix) return .nil +-- test if the current node is using a given namespace as the default +::method isDefaultNamespace + use strict arg uri + -- see if we have an element ancestor. + -- if we have one, ask for this from the element + ancestor = self~getElementAncestor + if ancestor \== .nil then return ancestor~isDefaultNamespace(uri) + return .false + +-- this is the default behavior used for many nodes. Other nodes +-- will override this to provide different behaviors. + -- find the first ancestor of this node that is an -- element node ::method getElementAncestor @@ -1857,10 +1870,6 @@ end return .nil -::method isDefaultNamespace - use strict arg uri - raise syntax 93.963 -- not supported - ::method isEqualNode use strict arg other -- a node is always equal to itself @@ -2492,6 +2501,13 @@ -- always returns .nil return .nil +-- perform a default namespace test for a node +::method isDefaultNamespace + use strict arg uri + + -- always returns .false for this type + return .false + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: DocumentImpl */ @@ -2724,7 +2740,16 @@ if root \= .nil then return root~lookupNamespaceURI(prefix) return .nil +-- test if the current node is using a given namespace as the default +::method isDefaultNamespace + use strict arg uri + -- ask the root element for this (if we have one) + root = self~documentElement + if root \= .nil then return root~isDefaultNamespace(uri) + return .false + + /** * Introduced in DOM Level 2. <p> * Distribution engine for DOM Level 2 Events. @@ -3399,6 +3424,17 @@ return .nil +-- test if the current node is using a given namespace as the default +::method isDefaultNamespace + use strict arg uri + + -- if this node is owned and the owner is an attribute, then + -- pass along the lookup + ownerNode = self~ownerNode + if ownerNode \== .nil, ownerNode~nodeType == .Node~ELEMENT_NODE then + return ownerNode~isDefaultNamespace(uri) + return .false + ::attribute isId ::method cloneNode @@ -4118,7 +4154,7 @@ return previous -- resolve the prefix that a node is using for a given namespace URI -::method resolvePrefix +::method lookupPrefix use strict arg uri -- pass this along to the specialized lookup method @@ -4207,7 +4243,37 @@ -- unresolved return .nil +-- test if the current node is using a given namespace as the default +::method isDefaultNamespace + use strict arg uri + namespace = self~namespaceURI + prefix = self~prefix + + -- if there's no prefix in use, any namespace for this element + -- will be from a default, so just compare. This also handles + -- the situation where any of these are .nil + if prefix == .nil | prefix == "" then do + return namespace == uri + end + + -- if the node has attributes, then we need to look for an xmlns + -- attribute and compare that + if self~hasAttributes then do + attr = self~getAttributeNodeNS("http://www.w3.org/2000/xmlns/", "xmlns") + if attr \== .nil then return uri == attr~nodeValue + end + + return .false + + -- if this node is owned and the owner is an attribute, then + -- pass along the lookup + ownerNode = self~ownerNode + if ownerNode \== .nil, ownerNode~nodeType == .Node~ELEMENT_NODE then + return ownerNode~isDefaultNamespace(uri) + return .false + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: CharacterData -- base class for all nodes that carry character data */ @@ -4656,6 +4722,13 @@ -- always returns .nil return .nil +-- perform a default namespace test for a node +::method isDefaultNamespace + use strict arg uri + + -- always returns .false for this type + return .false + -- override for text content. For this type, it always -- returns .nil ::attribute textContent GET @@ -4718,6 +4791,13 @@ -- always returns .nil return .nil +-- perform a default namespace test for a node +::method isDefaultNamespace + use strict arg uri + + -- always returns .false for this type + return .false + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: EntityReference */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-09 15:14:10
|
Revision: 8021 http://oorexx.svn.sourceforge.net/oorexx/?rev=8021&view=rev Author: bigrixx Date: 2012-07-09 15:13:59 +0000 (Mon, 09 Jul 2012) Log Message: ----------- more DOM 3 cleanup work Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-09 11:38:32 UTC (rev 8020) +++ incubator/orxutils/xml/xmldom.cls 2012-07-09 15:13:59 UTC (rev 8021) @@ -146,7 +146,9 @@ -- abstract text definition ::class "Text" mixinclass CharacterData public -::method splitText +::method splitText abstract +::method wholeText abstract +::method replaceWholeText abstract -- abstract CDATA section definition ::class "CDATASection" mixinclass Text public @@ -4407,101 +4409,28 @@ use strict arg return "#text" -::method getWholeText +-- return the string created by merging the values of all logically adjacent +-- text nodes. This includes both Text and CData nodes. +::method wholeText use strict arg - buffer = .mutablebuffer~new - data = self~data - if data \= .nil then do - buffer~append(data) + -- the parent node contains all of the siblings, so everything is done + -- relative to that + parent = self~parentNode + -- no parent means no siblings, so our value is all we have + if parent == .nil then return self~textContent + + buffer = .mutableBuffer~new + loop node over parent~children + if node~nodeType == .Node~TEXT_NODE | node~nodeType == .Node~CDATA_NODE then + buffer~append(node~nodeValue) + else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then + buffer~append(node~entityRefValue) end - self~getWholeTextBackward(self~previousSibling, buffer, self~parentNode) - self~getWholeTextForward(self~nextSibling, buffer, self~parentNode) - return buffer~string -::method getWholeTextForward - use arg node, buffer, parent - - processingEntity = .false - if parent \= .nil then do - processingEntity = parent~nodeType == .Node~ENTITY_REFERENCE_NODE - end - - do while node \= .nil - type= node~nodeType - -- unwind the entity references as a unit - if type == .Node~ENTITY_REFERENCE_NODE then do - if self~getWholeTextForward(node~firstChild, buffer, node) then do - return .true - end - end - -- a text node, just add the text content to the buffer - else if type == .Node~TEXT_NODE | type = .Node~CDATA_SECTION_NODE then do - node~buildTextContent(buffer) - end - else do - -- we're finished if we found a non-text node - return .true - end - node = node~nextSibling - end - - -- we've run through everything, but if we started with the child of an - -- entity reference, we need to check the siblings for additional logical - -- text nodes - if processingEntity then do - self~getWholeTextForward(parent~nextSibling, buffer, parent~parentNode) - return .true - end - - return .false - -::method getWholeTextBackward - use strict arg node, buffer, parent - - processingEntity = .false - if parent \= .nil then do - processingEntity = parent~nodeType == .Node~ENTITY_REFERENCE_NODE - end - - do while node \= .nil - type= node~nodeType - -- unwind the entity references as a unit - if type == .Node~ENTITY_REFERENCE_NODE then do - if self~getWholeTextBackward(node~lastChild, buffer, node) then do - return .true - end - end - -- a text node, just add the text content to the buffer - else if type == .Node~TEXT_NODE | type = .Node~CDATA_SECTION_NODE then do - node~insertTextContent(buffer) - end - else do - -- we're finished if we found a non-text node - return .true - end - node = node~previousSibling - end - - -- we've run through everything, but if we started with the child of an - -- entity reference, we need to check the siblings for additional logical - -- text nodes - if processingEntity then do - self~getWholeTextBackward(parent~previousSibling, buffer, parent~parentNode) - return .true - end - - return .false - -::method insertTextContent private - use arg buffer - content = self~nodeValue - if content \= .nil then do - buffer~insert(1, content) - end - +-- replace all the text of a text node ::method replaceWholeText use strict arg content @@ -4515,54 +4444,27 @@ return .nil end - self~data = content - currentNode = self + self~nodeValue = content - previous = currentNode~previousSibling - do while previous \= .nil - -- remove any logically adjacent text or entity reference nodes - nodetype = previous~nodeType - if nodeType = .Node~TEXT_NODE | - - nodeType = .Node~CDATA_SECTION_NODE | - - nodeType = .Node~ENTITY_REFERENCE_NODE - then do - -- remove the node from the parent - parent~removeChild(previous) - end - else do - -- non-text node found, time to quit - leave - end - -- we keep pulling the previous sibling of the current - -- until we find a non-text node - previous = currentNode~previousSibling - end + -- no parent, there's nothing to replace + if parent == .nil then return self - -- now remove the trailing siblings - next = currentNode~nextSibling - - do while next \= .nil + loop node over parent + -- leave our own node in the child list...just delete the siblings + if node == self then iterate -- remove any logically adjacent text or entity reference nodes - nodetype = next~nodeType + nodetype = node~nodeType if nodeType = .Node~TEXT_NODE | - - nodeType = .Node~CDATA_SECTION_NODE | - - nodeType = .Node~ENTITY_REFERENCE_NODE - then do + nodeType = .Node~CDATA_SECTION_NODE -- remove the node from the parent - parent~removeChild(next) - end - else do - -- non-text node found, time to quit - leave - end - -- we keep pulling the previous sibling of the current - -- until we find a non-text node - next = currentNode~nextSibling + then parent~removeChild(node) end -- this is now the only text node - return currentNode + return self +-- split the text at the indicated position, creating a new node with +-- the split off text and updating the value of the target node ::method splitText use strict arg offset @@ -4811,55 +4713,67 @@ self~init:super(ownerDoc) baseURI = .nil +-- override for the nodetype ::attribute nodeType GET use strict arg return .Node~ENTITY_NODE +-- entity references are created with a name ::attribute nodeName GET expose name use strict arg return name +-- retrieve the value of the entity reference ::attribute entityRefValue GET use strict arg - value = "" firstChild = self~firstChild - if firstChild == .nil then do - return .nil - end - if firstChild~nodeType == .Node~ENTITY_REFERENCE_NODE then do - value = firstChild~entityRefValue - end - else if firstChild~nodeType == .Node~TEXT_NODE then do - value = firstChild~nodeValue - end - else do - return .nil - end + -- no value if there are no children + if firstChild == .nil then return "" + -- an entity reference may contain elements too...we only care about + -- the real text node children. We can optimize this slightly for + -- the common case of just a single child node if firstChild~nextSibling == .nil then do - return value + -- get the value + if firstChild~nodeType == .Node~ENTITY_REFERENCE_NODE then + return firstChild~entityRefValue + else if firstChild~nodeType == .Node~TEXT_NODE then + return firstChild~nodeValue + else return .nil end - else do - buffer = .mutablebuffer~new(value) - next = firstChild~nextSibling - do while next \= .nil - if next~nodeType == .Node~ENTITY_REFERENCE_NODE then do - value = next~entityRefValue - end - else if next~nodeType == .Node~TEXT_NODE then do - value = next~nodeValue - end - else do - return .nil - end - buffer~append(value) - next = next~nextSibling + buffer = .mutablebuffer~new(value) + appended = .false + loop node over self + -- only entity references, text, and cdata nodes are of interest here + if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do + buffer~append(next~entityRefValue) + appended = .true end - return buffer~string + else if next~nodeType == .Node~TEXT_NODE | next~nodeType == .Node~CDATA_SECTION_NODE then do + buffer~append(next~nodeValue) + appended = .true + end end + -- if we actually found text nodes of some sort, return the value + return buffer~string + +-- test if modification or replacement of an entity reference is allowed. +-- for this to be true, the children can only be text, cdata, or entity reference +-- nodes +::method isModificationAllowed + use strict arg + + loop node over self + nodeType = node~nodeType + if nodeType == .Node~TEXT_NODE | nodType = .Node~CDATA_SECTION_NODE | .Node~ENTITY_REFERENCE_NODE then iterate + return .false + end + + return .true + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: ProcessingInstruction */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-09 17:53:49
|
Revision: 8022 http://oorexx.svn.sourceforge.net/oorexx/?rev=8022&view=rev Author: bigrixx Date: 2012-07-09 17:53:43 +0000 (Mon, 09 Jul 2012) Log Message: ----------- Some error cleanup Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-09 15:13:59 UTC (rev 8021) +++ incubator/orxutils/xml/xmldom.cls 2012-07-09 17:53:43 UTC (rev 8022) @@ -94,6 +94,9 @@ ::constant DOCUMENT_FRAGMENT_NODE 11 ::constant NOTATION_NODE 12 +::method nodeName abstract +::method nodeValue abstract +::method "nodeValue=" abstract ::method appendNode abstract ::method cloneNode abstract ::method attributes abstract @@ -103,10 +106,7 @@ ::method localName abstract ::method namespaceUri abstract ::method nextSibling abstract -::method nodeName abstract ::method nodeType abstract -::method nodeValue abstract -::method "nodeValue=" abstract ::method ownerDocument abstract ::method parentNode abstract ::method prefix abstract @@ -219,13 +219,18 @@ ::method setAttributeNode abstract ::method setAttributeNodeNS abstract ::method setAttributeNS abstract +::method setIdAttribute abstract +::method setIdAttributeNS abstract +::method setIdAttributeNode abstract -- abstract Entity definition ::class "Entity" mixinclass Node public -::method encoding abstract +::method xmlEncoding abstract ::method notationName abstract ::method systemId abstract -::method version abstract +::method publicId abstract +::method xmlVersion abstract +::method inpugEncoding -- abstract entityreference definition ::class "EntityReference" mixinclass Node public @@ -1527,7 +1532,7 @@ return .nil ::attribute prefix SET -- this is an error by default - .DomErrors~raiseError(.DomErrors~NAMESPACE_ERR) + .DomErrors~raiseError(.DomException~NAMESPACE_ERR) -- for node types that don't support a real localname, -- this is the same as nodeName ::attribute localName GET @@ -1564,17 +1569,17 @@ ::method insertBefore use strict arg newChild, refChild -- not implemented in the base node - .DomErrors~raiseError(.DomErrors~Hierarchy_request_err) + .DomErrors~raiseError(.DomException~Hierarchy_request_err) ::method replaceChild use strict arg newChild, oldChild -- not implemented in the base node - .DomErrors~raiseError(.DomErrors~Hierarchy_request_err) + .DomErrors~raiseError(.DomException~Hierarchy_request_err) ::method removeChild use strict arg oldChild -- not implemented in the base node - .DomErrors~raiseError(.DomErrors~Not_found_err) + .DomErrors~raiseError(.DomException~Not_found_err) ::method appendChild use strict arg newChild @@ -1588,7 +1593,7 @@ -- this must be from the same dom type if other \== .nil, \other~isa(.NodeImpl) then - .DomErrors~raiseError(.DomErrors~Not_supported_err) + .DomErrors~raiseError(.DomException~Not_supported_err) -- get the owners of the two nodes if self~nodeType == .Node~DOCUMENT_NODE then @@ -2638,7 +2643,7 @@ return .MutationEvent~new end else do - .DomErrors~raiseError(.DomErrors~NOT_SUPPORTED_ERR) + .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) end ::attribute hasMutationEvents @@ -3525,7 +3530,7 @@ self~ownerDocument~modifiedAttrValue(self, oldvalue) else self~changed - if self~isId & self~ownerElement \= .nil then do + if self~isId & self~ownerElement \== .nil then do self~ownerDocument~putIdentifier(newvalue, ownerElement) end @@ -3900,49 +3905,38 @@ return .DeepNodeList~new(self, localName, namespaceURI) +-- set a node on the element as an id attribute ::method setIdAttributeNode - use strict arg at, makeId + use strict arg attr, makeId - at~isId = makeId - if makeId then do - self~ownerDocument~putIdentifier(at~value, this) - end - else do - self~ownerDocument~removeIdentifier(at~value) - end + self~makeAttributeId(attr, makeId) +-- set a named attribute as an id value for the element ::method setIdAttribute use strict arg name, makeId - at = self~getAttributeNode(name) - if at == .nil then do - return - end + attr = self~getAttributeNode(name) + if attr == .nil then return - at~isID = makeId - if makeId then do - self~ownerDocument~putIdentifier(at~value, this) - end - else do - self~ownerDocument~removeIdentifier(at~value) - end + self~makeAttributeId(attr, makeId) +-- set an attribute to be an id attribute by namespace/localname ::method setIdAttributeNS use strict arg namespaceURI, localname, makeId - at = self~getAttributeNodeNS(namspaceURI, localname) - if at == .nil then do - return - end + attr = self~getAttributeNodeNS(namspaceURI, localname) + if attr == .nil then return + self~makeAttributeId(attr, makeId) - at~isId = makeId - if makeId then do - self~ownerDocument~putIdentifier(at~value, this) - end - else do - self~ownerDocument~removeIdentifier(at~value) - end +-- private method shared between the different setIdAttributeXXX methods +::method makeAttributeId private + use strict arg attr, makeId + attr~isID = makeId + if makeId then self~ownerDocument~putIdentifier(attr~value, self) + else self~ownerDocument~removeIdentifier(attr~value) + +-- retrieve any schema typeName set on this element ::attribute typeName GET expose type use strict arg @@ -4651,7 +4645,7 @@ ::class "EntityImpl" public subclass ParentNode inherit Entity ::method init - expose name publicId systemId XmlEncoding inputEncoding XMLversion notationName baseURI + expose name publicId systemId XmlEncoding inputEncoding XMLversion notationName use strict arg ownerDoc, name self~init:super(ownerDoc) publicId = .nil @@ -4660,7 +4654,6 @@ inputEncoding = .nil XmlVersion = .nil notationName = .nil - baseURI = .nil ::attribute nodeType GET use strict arg @@ -4673,11 +4666,10 @@ ::attribute publicId ::attribute systemId -::attribute XmlVersion -::attribute XmlEncoding +::attribute xmlVersion +::attribute xmlEncoding ::attribute inputEncoding ::attribute notationName -::attribute baseURI -- resolve the prefix that a node is using for a given namespace URI ::method lookupPrefix @@ -4863,29 +4855,29 @@ length = qname~length if index = 1 | index = length | lastIndex \= index then do - .DomErrors(.DomErrors~NAMESPACE_ERR) + .DomErrors~raiseError(.DomException~NAMESPACE_ERR) end start = 1 if index > 1 then do if \.XMLChar~isNCNameStart(gname~subChar(start)) then do - .DomErrors~raiseError(.DomErrors~INVALID_CHARACTER_ERR) + .DomErrors~raiseError(.DomException~INVALID_CHARACTER_ERR) end do i = 2 to index if \.XMLChar~isNCName(gname~subChar(i)) then do - .DomErrors~raiseError(.DomErrors~INVALID_CHARACTER_ERR) + .DomErrors~raiseError(.DomException~INVALID_CHARACTER_ERR) end end start = index + 1 end if \.XMLChar~isNCNameStart(gname~subChar(start)) then do - .DomErrors~raiseError(.DomErrors~INVALID_CHARACTER_ERR) + .DomErrors~raiseError(.DomException~INVALID_CHARACTER_ERR) end do i = start + 1 to length if \.XMLChar~isNCName(gname~subChar(i)) then do - .DomErrors~raiseError(.DomErrors~INVALID_CHARACTER_ERR) + .DomErrors~raiseError(.DomException~INVALID_CHARACTER_ERR) end end @@ -4894,7 +4886,7 @@ use strict arg namespaceURI = .nil, qualifiedName = .nil, doctype = .nil if doctype \= .nil, doctype~ownerDocument \= .nil then do - .DomErrors~raiseError(.DomErrors~WRONG_DOCUMENT_ERR) + .DomErrors~raiseError(.DomException~WRONG_DOCUMENT_ERR) end doc = .CoreDocument~new(doctype) @@ -4919,34 +4911,66 @@ return .nil +::class "DOMException" public +::constant INDEX_SIZE_ERR 1 +::constant DOMSTRING_SIZE_ERR 2 +::constant HIERARCHY_REQUEST_ERR 3 +::constant WRONG_DOCUMENT_ERR 4 +::constant INVALID_CHARACTER_ERR 5 +::constant NO_DATA_ALLOWED_ERR 6 +::constant NO_MODIFICATION_ALLOWED_ERR 7 +::constant NOT_FOUND_ERR 8 +::constant NOT_SUPPORTED_ERR 9 +::constant INUSE_ATTRIBUTE_ERR 10 +::constant INVALID_STATE_ERR 11 +::constant SYNTAX_ERR 12 +::constant INVALID_MODIFICATION_ERR 13 +::constant NAMESPACE_ERR 14 +::constant INVALID_ACCESS_ERR 15 +::constant VALIDATION_ERR 16 +::constant TYPE_MISMATCH_ERR 16 -::class "DOMErrors" public -::constant HIERARCHY_REQUEST_ERR "An attempt was made to insert a node where it is not permitted." -::constant INDEX_SIZE_ERR "The index or size is negative, or greater than the allowed value." -::constant INUSE_ATTRIBUTE_ERR "An attempt is made to add an attribute that is already in use elsewhere." -::constant INVALID_ACCESS_ERR "A parameter or an operation is not supported by the underlying object." -::constant INVALID_CHARACTER_ERR "An invalid or illegal XML character is specified." -::constant INVALID_MODIFICATION_ERR "An attempt is made to modify the type of the underlying object." -::constant INVALID_STATE_ERR "An attempt is made to use an object that is not, or is no longer, usable." -::constant NAMESPACE_ERR "An attempt is made to create or change an object in a way which is incorrect with regard to namespaces." -::constant NOT_FOUND_ERR "An attempt is made to reference a node in a context where it does not exist." -::constant NOT_SUPPORTED_ERR "The implementation does not support the requested type of object or operation." -::constant NO_DATA_ALLOWED_ERR "Data is specified for a node which does not support data." -::constant NO_MODIFICATION_ALLOWED_ERR "An attempt is made to modify an object where modifications are not allowed." -::constant SYNTAX_ERR "An invalid or illegal string is specified." -::constant VALIDATION_ERR "A call to a method such as insertBefore or removeChild would make the Node invalid with respect to document grammar." -::constant WRONG_DOCUMENT_ERR "A node is used in a different document than the one that created it." -::constant TYPE_MISMATCH_ERR "The value type for this parameter name is incompatible with the expected value type." +-- instance item for DOM errors. This is attached to the condition information +::method init + expose code message + use strict arg code, message -::constant BAD_BOUNDARYPOINTS_ERR "The boundary-points of a Range do not meet specific requirements." -::constant INVALID_NODE_TYPE_ERR "The container of a boundary-point of a Range is being set to either a node of an invalid type or a node with an ancestor of an invalid type." +::method string + expose code message + return "DOM Error" code":" message + +-- central class for raising DOMException events. +::class "DOMErrors" public subclass DomException +::method init class + expose messageTable + messageTable = .array~new + messageTable[.DomException~HIERARCHY_REQUEST_ERR] = "An attempt was made to insert a node where it is not permitted." + messageTable[.DomException~INDEX_SIZE_ERR] = "The index or size is negative, or greater than the allowed value." + messageTable[.DomException~INUSE_ATTRIBUTE_ERR] = "An attempt is made to add an attribute that is already in use elsewhere." + messageTable[.DomException~INVALID_ACCESS_ERR] = "A parameter or an operation is not supported by the underlying object." + messageTable[.DomException~INVALID_CHARACTER_ERR] = "An invalid or illegal XML character is specified." + messageTable[.DomException~INVALID_MODIFICATION_ERR] = "An attempt is made to modify the type of the underlying object." + messageTable[.DomException~INVALID_STATE_ERR] = "An attempt is made to use an object that is not, or is no longer, usable." + messageTable[.DomException~NAMESPACE_ERR] = "An attempt is made to create or change an object in a way which is incorrect with regard to namespaces." + messageTable[.DomException~NOT_FOUND_ERR] = "An attempt is made to reference a node in a context where it does not exist." + messageTable[.DomException~NOT_SUPPORTED_ERR] = "The implementation does not support the requested type of object or operation." + messageTable[.DomException~NO_DATA_ALLOWED_ERR] = "Data is specified for a node which does not support data." + messageTable[.DomException~NO_MODIFICATION_ALLOWED_ERR] = "An attempt is made to modify an object where modifications are not allowed." + messageTable[.DomException~SYNTAX_ERR] = "An invalid or illegal string is specified." + messageTable[.DomException~VALIDATION_ERR] = "A call to a method such as insertBefore or removeChild would make the Node invalid with respect to document grammar." + messageTable[.DomException~WRONG_DOCUMENT_ERR] = "A node is used in a different document than the one that created it." + messageTable[.DomException~TYPE_MISMATCH_ERR] = "The value type for this parameter name is incompatible with the expected value type." + +-- raise an error using the DOMException error numbers ::method raiseError class - use arg message + expose messageTable + use arg code - raise syntax 98.900 array(message) -- just raise this as a user execution error + raise syntax 98.900 array(.DOMException~new(code, messageTable[code])) -- just raise this as a user execution error + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: DOMEvent */ @@ -5718,10 +5742,6 @@ realEnd = endContainer~parentNode end - if realStart \= realEnd then do - DomErrors~raiseError(.DomErrors~BAD_BOUNDARY_POINTS_ERR) - end - frag = self~extractContents() self~insertNode(newParent) newParent~appendChild(frag) @@ -6332,7 +6352,7 @@ use strict arg refNode, offset if offset < 0 then do - .DOMErrors~raiseError(.DOMErrors~INDEX_SIZE_ERR) + .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) end type= refNode~nodeType @@ -6340,12 +6360,12 @@ if nodeType == .Node~TEXT_NODE | nodeType == .Node~CDATA_SECTION_NODE | - nodeType == .Node~COMMENT_NODE | nodeType == .Node~PROCESSING_INSTRUCTION_NODE then do if offset > refNode~nodeValue~length then do - .DOMErrors~raiseError(.DOMErrors~INDEX_SIZE_ERR) + .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) end end else do if offset > refNode~childNodes~length then do - .DOMErrors~raiseError(.DOMErrors~INDEX_SIZE_ERR) + .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) end end @@ -7170,10 +7190,10 @@ newNode~systemId = source~systemId end when type == .Node~DOCUMENT_NODE then do - .DomErrors~raiseError(.DomErrors~NOT_SUPPORTED_ERR) + .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) end otherwise do - .DomErrors~raiseError(.DomErrors~NOT_SUPPORTED_ERR) + .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) end end @@ -7216,10 +7236,10 @@ source~ownerDocument = self end when type == .Node~ENTITY_NODE | type == .Node~NOTATION_NODE then do - .DomErrors~raiseError(.DomErrors~NO_MODIFICATION_ALLOWED_ERR) + .DomErrors~raiseError(.DomException~NO_MODIFICATION_ALLOWED_ERR) end when type == .Node~DOCUMENT_NODE | type == .Node~DOCUMENT_TYPE_NODE then do - .DomErrors~raiseError(.DomErrors~NOT_SUPPORTED_ERR) + .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) end when type == .Node~ENTITY_REFERENCE_NODE then do parent = source~parentNode @@ -7265,31 +7285,6 @@ -- return the adopted node return source -::method getElementById - use strict arg id - - return self~getIdentifer(id) - -::method getIdentifier - expose identifers - use strict arg id - if identifers == .nil then do - return .nil - end - - element = identifers[id] - if element \= .nil then do - parent = element~parentNode - do while parent \= .nil - if parent == self then do - return element - end - parent = parent~parentNode - end - end - - return .nil - -- rename a target node using the new namespaceURI and qualified name ::method renameNode use strict arg node, namespaceURI, name @@ -7314,35 +7309,69 @@ self~renamedAttrNode(node, node) end else - self~domError(.DOMException~NOT_SUPPORTED_ERR) + .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) +-- clear our identifiers table ::method clearIdentifiers private expose identifers - if identifers \= .nil then do + if identifers \= .nil then identifiers~empty + +-- retrieve an element by an id attribute +::method getElementById + use strict arg id + + return self~getIdentifer(id) + +-- retrieve an element node by its identifier +::method getIdentifier + expose identifers + use strict arg id + + if identifers == .nil then return .nil + + element = identifers[id] + + if element \= .nil then do + parent = element~parentNode + do while parent \= .nil + if parent == self then do + return element + end + parent = parent~parentNode + end end + return .nil + +-- add an element as being identified using an ID attribute name ::method putIdentifier expose identifiers use strict arg name, element - if element == .nil then do + -- if no element given, this is a deletion for the name + if element == .nil then self~removeIdentifier(name) - end + -- add this to the global identifiers table else do if identifiers == .nil then identifiers = .directory~new identifers[name] = element end +-- remove a name from the document identifier table ::method removeIdentifier expose identifiers use strict arg name + + -- no identifiers? removal is easy if identifiers == .nil then return - + -- remove from the table...we don't really care if + -- there's anything there or not. identifers~remove(name) +-- retrieve the identifiers name set as an array ::method identifiers if identifiers == .nil then identifiers = .directory~new This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-09 21:25:15
|
Revision: 8023 http://oorexx.svn.sourceforge.net/oorexx/?rev=8023&view=rev Author: bigrixx Date: 2012-07-09 21:25:09 +0000 (Mon, 09 Jul 2012) Log Message: ----------- A lot of event work Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-09 17:53:43 UTC (rev 8022) +++ incubator/orxutils/xml/xmldom.cls 2012-07-09 21:25:09 UTC (rev 8023) @@ -277,6 +277,12 @@ -- called as handleEvent(event) ::method handleEvent +-- interface for the DOM objects that allow attaching of event listeners +::class "DOMEventTarget" mixinclass object +::method addEventListener abstract +::method removeEventListener abstract +::method dispatchEvent abstract + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Section: Concrete implementation of the DOM classes */ @@ -1431,7 +1437,7 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::CLASS "NodeImpl" public inherit Node +::CLASS "NodeImpl" public inherit Node DOMEventTarget -- DocumentPosition indicators ::constant DOCUMENT_POSITION_DISCONNECTED 1 @@ -1954,7 +1960,27 @@ syntax: -- just return an empty node set +-- methods for the DOMEventTracker interface +-- add a listener to this node +::method addEventListener + use strict arg type, listener, useCapture + + self~ownerDocument~addEventListener(self, type, listener, useCapture) + +-- remove a listener attached to this node +::method removeEventListener + use strict arg type, listener, useCapture + + self~ownerDocument~removeEventListener(self, type, listener, useCapture) + +-- dispatch an event on this node context +::method dispatchEvent + use strict arg event + + self~ownerDocument~dispatchEvent(self, event) + + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: Node */ @@ -2640,7 +2666,7 @@ return .DOMEvent~new end else if type~caselessEquals("MutationEvent") then do - return .MutationEvent~new + return .DOMMutationEvent~new end else do .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) @@ -2648,87 +2674,94 @@ ::attribute hasMutationEvents +-- set a set of event listeners for a given node ::method setEventListeners expose eventListeners use strict arg node, listeners + -- if this is the first listener request, create the + -- listener table if eventListeners == .nil then do - eventListeners = .table~new + eventListeners = .identitytable~new end + -- no listeners provided? Just remove the listeners for this node if listeners == .nil then do eventListeners~remove(node) - if eventListeners~isEmpty then do + -- if there are no more listeners, turn off even checking + if eventListeners~isEmpty then self~hasMutationEvents = .false - end end else do + -- add this to the listener table and make sure the + -- event flag is turned on eventListeners[node] = listeners self~hasMutationEvents = .true end +-- retrieve the event listeners for a target node ::method getEventListeners expose eventListeners use strict arg node - if eventListeners == .nil then do - return .nil - end + + if eventListeners == .nil then return .nil return eventListeners[node] -- EventTarget support +-- add an event listener for a node ::method addEventListener - use strict arg node, type, listener, useCapture + use strict arg node, eventName, listener, useCapture - if type == .nil | type == "" | listener == .nil then do - return - end - - self~removeEventListener(node, type, listener, useCapture) - + -- we need a good type and listener for this to work + if type == .nil | type == "" | listener == .nil then return + -- remove any existing event listener for this node and type + self~removeEventListener(node, eventName, listener, useCapture) + -- get the listener list for this node, creating one if needed nodeListeners = self~getEventListeners(node) if nodeListeners == .nil then do - nodeListeners = .List~new + nodeListeners = .list~new self~setEventListeners(node, nodeListeners) end - nodeListeners~append(.EventListener~new(type, listener, useCapture)) - - capture = self~lookupCapture(type) + nodeListeners~append(.EventListenerDescriptor~new(eventName, listener, useCapture)) + -- look up the capture record for this eventName and record the fact + capture = self~lookupCapture(eventName) capture~addListener(useCapture) +-- remove an event listener from the tables ::method removeEventListener use strict arg node, type, listener, useCapture - if type == .nil | type == "" | listener == .nil then do - return - end + if type == .nil | type == "" | listener == .nil then return + nodeListeners = self~getEventListeners(node) - if nodeListeners == .nil then do - return - end + if nodeListeners == .nil then return do le over nodeListeners if le~equals(type, listener, useCapture) then do nodeListeners~removeItem(le) if nodeListeners~isEmpty then do - self~eventListeners(node, .nil) + self~setEventListeners(node, .nil) end + -- remove this from the capture tables as well + capture = self~lookupCapture(eventName) + capture~removeListener(useCapture) return end end +-- copy event listeners to another node ::method copyEventListeners - use strict arg source, target + use strict arg sourceNode, targetNode - nodeListeners = self~getEventListeners(source) - if nodeListeners == .nil then do - return - end + nodeListeners = self~getEventListeners(sourceNode) + if nodeListeners == .nil then return + -- just copy the event listener table over to the new + -- node + self~setEventListeners(targetNode, nodeListeners~copy) - self~setEventListeners(target, nodeListeners~copy) - -- resolve the prefix that a node is using for a given namespace URI ::method lookupPrefix use strict arg uri @@ -2811,22 +2844,21 @@ ::method dispatchEvent private use strict arg node, event - -- don't do anything if there are no listeners - capture = lookupCapture(event~type) - if capture~total == 0 then do - return event~preventDefault - end + -- check the capture descriptors. If there are no active listeners + -- for this event type, then we don't dispatch this + capture = self~lookupCapture(event~type) + if capture~total == 0 then return event~defaultPrevented -- initialize the events dispatch status event~target = node - event~stopPropagation = .false - event~preventDefault = .false + event~propagationStopped = .false + event~defaultPrevented = .false -- capture the event parentage chain parents = .array~new previous = node parent = previous~parentNode - loop while parent \= .nil + loop while parent \== .nil parents~append(parent) previous = parent parent = parent~parentNode @@ -2834,37 +2866,44 @@ -- capturing phase if capture~captures > 0 then do - event~eventPhase = .Event~CAPTURING_PHASE - do parentNode over parents - if event~stopPropagation then do - leave - end + event~eventPhase = .DOMEvent~CAPTURING_PHASE + -- we need to send this up the parent chain. At any + -- point, a listener may turn on the propagation flag, + -- so we stop doing this at that poing + loop parentNode over parents + if event~propagationStopped then leave event~currentTarget = parentNode + -- for each ancestor node, dispatch a call if there + -- is a listener defined for this event type on the node listeners = self~getEventListeners(parentNode) - if nodeListeners \= .nil then do + if nodeListeners \== .nil then do -- NB: Do over takes a snapshot copy, so -- this is thread safe - do listener over nodeListeners + loop listener over nodeListeners if listener~matches(event~type, .true) then do listener~invoke(event) + -- if the immediate stop has been turned on, we're done dispatching + if event~stoppedImmediatePropagation then return event~defaultPrevented end end end end end - -- both AT_TARGET and BUGGLE use non-capturing listeners + -- both AT_TARGET and BUBBLE use non-capturing listeners if capture~bubbles > 0 then do - event~eventPhase = .Event~AT_TARGET + event~eventPhase = .DOMEvent~AT_TARGET event~currentTarget = node nodeListeners = self~getEventListeners(node) - if \event~stopPropagation & nodeListeners \= .nil then do + if \event~propagationStopped & nodeListeners \= .nil then do -- NB: Do over takes a snapshot copy, so -- this is thread safe - do listener over nodeListeners + loop listener over nodeListeners if listener~matches(event~type, .false) then do listener~invoke(event) + -- if the immediate stop has been turned on, we're done dispatching + if event~stoppedImmediatePropagation then return event~defaultPrevented end end end @@ -2875,18 +2914,18 @@ -- instead immediately advance to the default phase. -- Note that not all events bubble. if event~bubbles then do - event~eventPhase = .Event~BUBBLING_PHASE + event~eventPhase = .DOMEvent~BUBBLING_PHASE do parent over parents - if event~stopPropagation then do - leave - end + if event~propagationStopped then leave event~currentTarget = parent - nodeListeners = self~getEventListeners(node) + nodeListeners = self~getEventListeners(parent) if nodeListeners \= .nil then do do listener over nodeListener if listener~matches(event~type, .false) then do listener~invoke(event) + -- if the immediate stop has been turned on, we're done dispatching + if event~stoppedImmediatePropagation then return event~defaultPrevented end end end @@ -2894,9 +2933,10 @@ end end - return event~preventDefault + return event~defaultPevented -::method lookupCapture PRIVATE +-- look up the capture information for a given event type +::method lookupCapture private expose captures use strict arg type if caputures == .nil then do @@ -2904,8 +2944,9 @@ end capture = captures[type] + -- create a tracker if this is the first request for this type if capture == .nil then do - capture = .EventTracer~new + capture = .EventTracker~new captures[type] = capture end @@ -2942,12 +2983,12 @@ owner = .nil if enclosingAttr \= .nil then do - capture = self~lookupCapture(.MutationEvent~DOM_ATTR_MODIFIED) + capture = self~lookupCapture(.DOMMutationEvent~DOM_ATTR_MODIFIED) owner = enclosingAttr~ownerElement if capture~total then do if owner \= .nil then do - me = .MutationEvent~new - me.initMutationEvent(.MutationEvent~DOM_ATTR_MODIFIED, .true. - + me = .DOMMutationEvent~new + me.initMutationEvent(.DOMMutationEvent~DOM_ATTR_MODIFIED, .true. - .false, enclosingAttr, oldvalue, enclosingAttr~nodeValue, - enclosing~nodeName, change) owner~dispatchEvent(me) @@ -2955,10 +2996,10 @@ end end - capture = self~lookupCapture(.MutationEvent~DOM_SUBTREE_MODIFIED) + capture = self~lookupCapture(.DOMMutationEvent~DOM_SUBTREE_MODIFIED) if capture~total > 0 then do - me = .MutationEvent~new - me.initMutationEvent(.MutationEvent~DOM_SUBTREE_MODIFIED, .true. - + me = .DOMMutationEvent~new + me.initMutationEvent(.DOMMutationEvent~DOM_SUBTREE_MODIFIED, .true. - .false, .nil, .nil, .nil, .nil, 0) owner~dispatchEvent(me) @@ -2979,7 +3020,7 @@ savedEnclosingAttr = .nil - capture = self~captureLookup(.MutationEvent~DOM_ATTR_MODIFIED) + capture = self~captureLookup(.DOMMutationEvent~DOM_ATTR_MODIFIED) if capture~total > 0 then do eventAncestor = .nil do forever @@ -3028,10 +3069,10 @@ use strict arg node, oldValue, value, replace if \replace then do - capture = self~lookupCapture(.MutationEvent.DOM_CHARACTER_DATA_MODIFIED) + capture = self~lookupCapture(.DOMMutationEvent.DOM_CHARACTER_DATA_MODIFIED) if capture~total > 0 then do - me = .MutationEvent~new - me~initMutationEvent(.MutationEvent~DOM_CHARACTER_DATA_MODIFIED, - + me = .DOMMutationEvent~new + me~initMutationEvent(.DOMMutationEvent~DOM_CHARACTER_DATA_MODIFIED, - .true, .false, .nil, oldValue, value, .nil, 0) self~dispatchEvent(node, me) end @@ -3069,15 +3110,15 @@ expose savedEnclosingAttr use strict arg node, newInternal, replace - capture = self~lookupCapture(.MutationEvent~DOM_NODE_INSERTED) + capture = self~lookupCapture(.DOMMutationEvent~DOM_NODE_INSERTED) if capture~total > 0 then do - me = .MutationEvent~new - me~initMutationEvent(.MutationEvent~DOM_NODE_INSERTED, .true. .false, - + me = .DOMMutationEvent~new + me~initMutationEvent(.DOMMutationEvent~DOM_NODE_INSERTED, .true. .false, - node, .nil, .nil, .nil, 0) self~dispatchEvent(newInternal, me) end - capture = self~lookupCapture(.MutationEvent~DOM_NODE_INSERTED_INTO_DOCUMENT) + capture = self~lookupCapture(.DOMMutationEvent~DOM_NODE_INSERTED_INTO_DOCUMENT) if capture~total > 0 then do eventAncestor = .node if savedEnclosingAttr \= .nil then do @@ -3094,8 +3135,8 @@ end end if eventAncestor~nodeType == .Node~DOCUMENT_NODE then do - me = .MutationEvent~new - me~initMutationEvent(.MutationEvent~DOM_NODE_INSERTED_INTO_DOCUMENT, - + me = .DOMMutationEvent~new + me~initMutationEvent(.DOMMutationEvent~DOM_NODE_INSERTED_INTO_DOCUMENT, - .false, .false, .nil, .nil, .nil, .nil, 0) self~dispatchEventToSubtree(newInternal, me) end @@ -3154,15 +3195,15 @@ self~saveEnclosingAttr(node) end - capture = self~lookupCapture(.MutationEvent~DOM_NODE_REMOVED) + capture = self~lookupCapture(.DOMMutationEvent~DOM_NODE_REMOVED) if capture~total > 0 then do - me = .MutationEvent~new - me~initMutationEvent(.MutationEvent~DOM_NODE_REMOVED, .true, .false, + me = .DOMMutationEvent~new + me~initMutationEvent(.DOMMutationEvent~DOM_NODE_REMOVED, .true, .false, node, .nil, .nil, .nil, 0) self~dispatchEvent(oldChild, me) end - capture~captureLookup(.MutationEvent~DOM_NODE_REMOVED_FROM_DOCUMENT) + capture~captureLookup(.DOMMutationEvent~DOM_NODE_REMOVED_FROM_DOCUMENT) if capture~total then do eventAncestor = self if savedEnclosingAttr \= .nil then do @@ -3176,8 +3217,8 @@ end end if eventAncestor~nodeType == .Node~DOCUMENT_NODE then do - me = new .MutationEvent~new - me~initMutationEvent(.MutationEvent~DOM_NODE_REMOVED_FROM_DOCUMENT, + me = new .DOMMutationEvent~new + me~initMutationEvent(.DOMMutationEvent~DOM_NODE_REMOVED_FROM_DOCUMENT, .false, .false, .nil, .nil, .nil, .nil, 0) self~dispatchEventToSubtree(oldChild, me) end @@ -3221,7 +3262,7 @@ use strict arg attr, oldValue if hasMutationEvents then do - self~dispatchAggregateEvents(attr, attr, oldvalue, .MutationEvent~MODIFICATION) + self~dispatchAggregateEvents(attr, attr, oldvalue, .DOMMutationEvent~MODIFICATION) end ::method setAttrNode @@ -3230,10 +3271,10 @@ if hasMutationEvents then do if previous == .nil then do - self~dispatchAggregateEvents(attr~ownerNode, attr, .nil, .MutationEvent~ADDITION) + self~dispatchAggregateEvents(attr~ownerNode, attr, .nil, .DOMMutationEvent~ADDITION) end else do - self~dispatchAggregateEvents(attr~ownerNode, attr, previous~nodeValue, .MutationEvent~MODIFICATION) + self~dispatchAggregateEvents(attr~ownerNode, attr, previous~nodeValue, .DOMMutationEvent~MODIFICATION) end end @@ -3248,11 +3289,11 @@ ::method mutationEventsRemovedAttrNode use strict arg attr, oldOwner, name - capture = self~lookupCapture(.MutationEvent~DOM_ATTR_MODIFIED) + capture = self~lookupCapture(.DOMMutationEvent~DOM_ATTR_MODIFIED) if capture~total > 0 then do - me = .MutationEvent~new - me~initMutationEvent(.MutationEvent~DOM_ATTR_MODIFIED, .true, .false, attr, - attr~nodeValue, .nil, name, .MutationEvent~REMOVAL) + me = .DOMMutationEvent~new + me~initMutationEvent(.DOMMutationEvent~DOM_ATTR_MODIFIED, .true, .false, attr, + attr~nodeValue, .nil, name, .DOMMutationEvent~REMOVAL) self~dispatchEvent(oldOwner, me) end @@ -3260,7 +3301,7 @@ ::method renamedElement -::class "EventListenerImpl" public +::class "EventListenerDescriptor" public ::method init expose type useCapture listener use strict arg type, listener, useCapture @@ -3291,7 +3332,8 @@ return -- all errors are just ignored -::class "EventTrackerImpl" public +-- internal class for tracking named event trackers +::class "EventTracker" ::method init expose captures total bubble total @@ -3305,12 +3347,8 @@ total += 1 - if useCapture then do - captures += 1 - end - else do - bubbles += 1 - end + if useCapture then captures += 1 + else bubbles += 1 ::method removeListener expose captures total bubbles @@ -3318,12 +3356,8 @@ total -= 1 - if useCapture then do - captures -= 1 - end - else do - bubbles -= 1 - end + if useCapture then captures -= 1 + else bubbles -= 1 /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -4967,7 +5001,6 @@ expose messageTable use arg code - raise syntax 98.900 array(.DOMException~new(code, messageTable[code])) -- just raise this as a user execution error @@ -4977,17 +5010,28 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ ::class "DOMEvent" public +::constant NONE 0 +::constant CAPTURING_PHASE 1 +::constant AT_TARGET 2 +::constant BUBBLING_PHASE 3 + + + ::method init - expose initialized target eventPhase currentTarget timeStamp stopPropagation preventDefault + expose type initialized cancelable target eventPhase currentTarget timeStamp propagationStopped defaultPrevented isTrusted immediatePropagationStopped + type = .nil initialized = .false currentTarget = .nil eventPhase = .nil timeStamp = .DateTime~new - stopPropagation = .false - preventDevault = .false + propagationStopped = .false + defaultPrevented = .false + cancelable = .false + isTrusted = .false -- spec requires this initially be false + immediatePropagationStopped = .false ::method initEvent - expose type bubbles cancelable initialized target eventPhase currentTarget timeStamp stopPropagation preventDefault + expose type bubbles cancelable initialized use strict arg type, bubbles, cancelable initialized = .true @@ -4998,18 +5042,31 @@ ::attribute target GET ::attribute type GET ::attribute timeStamp GET +::attribute defaultPrevented +::attribute propagationStopped +::attribute isTrusted GET +::method preventDefault + expose defaultPrevented + use strict arg + defaultPrevented = .true + ::method stopPropagation - expose stopPropagation + expose propagationStopped use strict arg - stopPropagation = .true + propagationStopped = .true -::method preventDefault - expose preventDefault +::method stopImmediatePropagation + expose immediatePropagationStopped use strict arg - preventDefault = .true + immediatePropagationStopped = .true -::class "MutationEvent" subclass DOMEvent public + +::class "DOMMutationEvent" subclass DOMEvent public +::constant MODIFICATION 1 +::constant ADDITION 2 +::constant REMOVAL 3 + ::constant DOM_SUBTREE_MODIFIED "DOMSubtreeModified" ::constant DOM_NODE_INSERTED "DOMNodeInserted" ::constant DOM_NODE_REMOVED "DOMNodeRemoved" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-10 00:21:24
|
Revision: 8024 http://oorexx.svn.sourceforge.net/oorexx/?rev=8024&view=rev Author: bigrixx Date: 2012-07-10 00:21:17 +0000 (Tue, 10 Jul 2012) Log Message: ----------- A lot of cleanup of the DocumentTraversal stuff Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-09 21:25:09 UTC (rev 8023) +++ incubator/orxutils/xml/xmldom.cls 2012-07-10 00:21:17 UTC (rev 8024) @@ -262,7 +262,7 @@ ::method "data=" abstract -- interface class for implementing a user data handler -::class "UserDataHandler" mixinclass object +::class "UserDataHandler" public mixinclass object ::constant NODE_CLONED 1 ::constant NODE_IMPORTED 2 ::constant NODE_DELETED 3 @@ -273,18 +273,122 @@ ::method handle -- interface class for implementing a DOM event handler -::class "DOMEventListener" mixinclass object +::class "DOMEventListener" public mixinclass object -- called as handleEvent(event) ::method handleEvent -- interface for the DOM objects that allow attaching of event listeners -::class "DOMEventTarget" mixinclass object +::class "DOMEventTarget" public mixinclass object ::method addEventListener abstract ::method removeEventListener abstract ::method dispatchEvent abstract /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: DocumentTraversal */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +-- interface for supporting document traversal methods +::class "DocumentTraversal" mixinclass object +::method createNodeIterator abstract +::method createTreeWalker abstract + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: NodeIterator */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "NodeIterator" public mixinclass object + +::method root abstract +::method whatToShow abstract +::method filter abstract +::method expandEntityReferences abstract + +::method nextNode abstract +::method previousNode abstract +::method detach abstract + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: TreeWalker */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "TreeWalker" public mixinclass Object +::method root abstract +::method whatToShow abstract +::method filter abstract +::method expandEntityReferences abstract +::method currentNode abstract +::method "CURRENTNODE=" abstract + +::method parentNode +::method firstChild +::method lastChild +::method previousSibling abstract +::method nextSibling abstract +::method previousNode abstract +::method nextNode abstract + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: NodeFilter */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "NodeFilter" mixinclass Object public +-- constants returned by acceptNode +::constant FILTER_ACCEPT 1 +::constant FILTER_REJECT 2 +::constant FILTER_SKIP 3 + +-- whatToShow values +::constant SHOW_ALL -1 +::constant SHOW_ELEMENT 1 +::constant SHOW_ATTRIBUTE 2 +::constant SHOW_TEXT 4 +::constant SHOW_CDATA_SECTION 8 +::constant SHOW_ENTITY_REFERENCE 16 +::constant SHOW_ENTITY 32 +::constant SHOW_PROCESSING_INSTRUCTION 64 +::constant SHOW_COMMENT 128 +::constant SHOW_DOCUMENT 256 +::constant SHOW_DOCUMENT_TYPE 512 +::constant SHOW_DOCUMENT_FRAGMENT 1024 +::constant SHOW_NOTATION 2048 + +-- use to filter the individual nodes +::method acceptNode + use strict arg node + -- default implementation accepts everything + return self~FILTER_ACCEPT + +-- helper method to test a particular flag setting against +-- a mask of what to show. Return .true if this is in the mask, +-- .false otherwise +::method isShowing class + use strict arg whatToShow, test + + -- this is easy + if whatToShow == .NodeFilter~SHOW_ALL then + return .true + -- convert both values to a binary string, then pad out to 11 digits for the + -- mapping + flagValues = whatToShow~d2x~x2b~right(12, 0) + testFlags = test~d2x~x2b~right(12, 0) + + -- by bitanding these together, if there are position matches, + -- we'll end up with 1s in the matching locations, allowing us to + -- return .true + return flagValues~bitand(testFlags) \= 0 + + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Section: Concrete implementation of the DOM classes */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -2546,7 +2650,7 @@ /* Class: DocumentImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "DocumentImpl" subclass ParentNode public inherit Document +::class "DocumentImpl" subclass ParentNode public inherit Document DocumentTraversal ::method init expose iterators ranges eventListeners doctype hasMutationEvents use arg doctype = .nil @@ -2568,32 +2672,32 @@ -- this is a singleton return .ooRexxDOM~implementation +-- create a NodeIterator instance for the DocumentTraversal interface ::method createNodeIterator expose iterators use strict arg root, whatToShow, filter, entityReferenceExpansion = .true - iterator = .NodeIterator~new(self, root, whatToShow, filter, entityReferenceExpansion) + iterator = .NodeIteratorImpl~new(self, root, whatToShow, filter, entityReferenceExpansion) - if iterators = .nil then do - iterators = .list~new - end + -- we keep track of the iterators so we can dispatch update events to them + if iterators = .nil then iterators = .list~new iterators~append(iterator) return iterator +-- create a tree walker for moving through the nodes ::method createTreeWalker use strict arg root, whatToShow, filter, entityReferenceExpansion = .true - return .TreeWalker~new(root, whatToShow, filter, entityReferenceExpansion) + return .TreeWalkerImpl~new(root, whatToShow, filter, entityReferenceExpansion) +-- remove an iterator from tracking as a result of a detach call ::method removeNodeIterator expose iterators use strict arg nodeIterator - if nodeIterator == .nil | iterators == .nil then do - return - end + if nodeIterator == .nil | iterators == .nil then return - iterators~remove(iterator) + iterators~removeItem(iterator) ::method createRange expose ranges @@ -5015,8 +5119,6 @@ ::constant AT_TARGET 2 ::constant BUBBLING_PHASE 3 - - ::method init expose type initialized cancelable target eventPhase currentTarget timeStamp propagationStopped defaultPrevented isTrusted immediatePropagationStopped type = .nil @@ -5095,136 +5197,52 @@ use strict arg type, bubble, cancelable, relatedNode, prevValue, newValue, attrName, attrChange self~initEvent(type, canBubble, cancelable) - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: NodeFilter */ +/* Class: NodeIteratorImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "NodeFilter" mixinclass Object public --- constants returned by acceptNode -::constant FILTER_ACCEPT 1 -::constant FILTER_REJECT 2 -::constant FILTER_SKIP 3 - --- whatToShow values -::constant SHOW_ALL -1 -::constant SHOW_ELEMENT 1 -::constant SHOW_ATTRIBUTE 2 -::constant SHOW_TEXT 4 -::constant SHOW_CDATA_SECTION 8 -::constant SHOW_ENTITY_REFERENCE 16 -::constant SHOW_ENTITY 32 -::constant SHOW_PROCESSING_INSTRUCTION 64 -::constant SHOW_COMMENT 128 -::constant SHOW_DOCUMENT 256 -::constant SHOW_DOCUMENT_TYPE 512 -::constant SHOW_DOCUMENT_FRAGMENT 1024 -::constant SHOW_NOTATION 2048 - --- use to filter the individual nodes -::method acceptNode - use strict arg node - -- default implementation accepts everything - return self~FILTER_ACCEPT - -::method isShowing - use strict arg whatToShow, test - - if whatToShow == .NodeFilter~SHOW_ALL then do - flagValues = "11111111111" -- we'll set all flags to true - end - else do - -- convert this to a binary string, then pad out to 11 digits for the - -- mapping - flagValues = whatToShow~d2x~x2b~right(11, 0) - end - - whatToShowFlags = .directory~new - parse var flagValues whatToShowFlags[.Node~ELEMENT] +1 - - whatToShowFlags[.Node~ATTRIBUTE] +1 - - whatToShowFlags[.Node~TEXT] +1 - - whatToShowFlags[.Node~CDATA_SECTION] +1 - - whatToShowFlags[.Node~ENTITY_REFERENCE] +1 - - whatToShowFlags[.Node~ENTITY] +1 - - whatToShowFlags[.Node~PROCESSING_INSTRUCTION] +1 - - whatToShowFlags[.Node~COMMENT] +1 - - whatToShowFlags[.Node~DOCUMENT] +1 - - whatToShowFlags[.Node~DOCUMENT_TYPE] +1 - - whatToShowFlags[.Node~DOCUMENT_FRAGMENT] +1 - - whatToShowFlags[.Node~NOTATION] +1 - - return whatToShowFlags[test] - - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/* Class: NodeIterator */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -::class "NodeIterator" public +::class "NodeIteratorImpl" public inherit NodeIterator ::method init expose document root currentNode whatToShowFlags whatToShow nodeFilter entityReferenceExpansion forward use strict arg document, root, whatToShow = (.NodeFilter~SHOW_ALL), nodeFilter = .nil, entityReferenceExpansion = .false - if whatToShow == .NodeFilter~SHOW_ALL then do - flagValues = "11111111111" -- we'll set all flags to true - end - else do + -- convert the whatToShow flags into a string of binary digits that can be + -- easily tested + if whatToShow == .NodeFilter~SHOW_ALL then + whatToShowFlags = "111111111111" -- we'll set all flags to true -- convert this to a binary string, then pad out to 11 digits for the -- mapping - flagValues = whatToShow~d2x~x2b~right(11, 0) - end - - whatToShowFlags = .directory~new - parse var flagValues whatToShowFlags[.Node~ELEMENT] +1 - - whatToShowFlags[.Node~ATTRIBUTE] +1 - - whatToShowFlags[.Node~TEXT] +1 - - whatToShowFlags[.Node~CDATA_SECTION] +1 - - whatToShowFlags[.Node~ENTITY_REFERENCE] +1 - - whatToShowFlags[.Node~ENTITY] +1 - - whatToShowFlags[.Node~PROCESSING_INSTRUCTION] +1 - - whatToShowFlags[.Node~COMMENT] +1 - - whatToShowFlags[.Node~DOCUMENT] +1 - - whatToShowFlags[.Node~DOCUMENT_TYPE] +1 - - whatToShowFlags[.Node~DOCUMENT_FRAGMENT] +1 - - whatToShowFlags[.Node~NOTATION] +1 - + else whatToShowFlags = whatToShow~d2x~x2b~right(12, 0) forward = .true -- we start iterating in a forward direction +-- attributes defined by the interface ::attribute root GET ::attribute whatToShow GET ::attribute filter GET ::attribute expandEntityReferences GET +-- retrieve the next node in the iteration sequence. Returns .nil at +-- the end ::method nextNode expose root currentNode forward use strict arg - if root == .nil then do - return .nil - end - + -- a null root is unusual, but not illegal + if root == .nil then return .nil nextNode = currentNode - do forever + loop forever -- if we're backing up, repeat the current node - if \forward & nextNode \= .nil then do - nextNode = currentNode - end + if \forward & nextNode \== .nil then nextNode = currentNode else do - if \entityReferenceExpansion, nextNode \= .nil, nextNode~nodeType == .Node~ENTITY_REFERENCE_NODE then do - nextNode = self~nextNode(nextNode, .false) - end - else do - nextNode = self~nextNode(nextNode, .true) - end + if \entityReferenceExpansion, nextNode \= .nil, nextNode~nodeType == .Node~ENTITY_REFERENCE_NODE then + nextNode = self~locateNextNode(nextNode, .false) + else nextNode = self~locateNextNode(nextNode, .true) end forward = .true -- did not find a next node, return .nil - if nextNode = .nil then do - return .nil - end + if nextNode = .nil then return .nil -- now try the filters if self~acceptNode(nextNode) then do @@ -5236,32 +5254,24 @@ -- keep looping until we find something good end - return .nil -- no acceptable nodes found - +-- back up to the previous node ::method previousNode expose root currentNode forward use strict arg - if root == .nil | currentNode = .nil then do - return .nil - end + -- nothing to work from...we're done + if root == .nil | currentNode = .nil then return .nil previousNode = currentNode - do forever - if forward & previousNode \= .nil then do - previousNode = currentNode - end - else do - previousNode = self~previousNode(previousNode) - end + loop forever + if forward & previousNode \= .nil then previousNode = currentNode + else previousNode = self~previousNode(previousNode) -- this is going backwards forward = .false - if previousNode = .nil then do - return .nil - end + if previousNode = .nil then return .nil if self~acceptNode(previousNode) then do currentNode = previousNode @@ -5269,100 +5279,88 @@ end end - return .nil - +-- a test to determine what should be accepted ::method acceptNode private expose nodeFilter whatToShowFlags use arg node + nodeFlag = (2**(node~nodetype - 1))~d2x~x2b~right(12, 0) - if nodeFilter == .nil then do - return whatToShowFlags[node~nodeType] - end - else do - return whatToShowFlags[node~nodeType] & nodeFilter~acceptNode(node) == .NodeFilter~FILTER_ACCEPT - end + -- test the flags first + if whatToShowFlags~bitxor(nodeflag) = 0 then return .false + -- then filter + if nodeFilter \= .nil then + return nodeFilter~acceptNode(node) == .NodeFilter~FILTER_ACCEPT + -- true based on the flags + return .true +-- internal method to locate the next node ::method locateNextNode private expose root use strict arg node, visitChildren - if node == .nil then do - return .nil - end + -- might have already reached the end + if node == .nil then return .nil if visitChildren then do - if node~hasChildNodes then do - return node~firstChild - end + if node~hasChildNodes then return node~firstChild end -- back to the root? We're done - if node == root then do - return .nil - end + if node == root then return .nil -- use the next sibling if it exists result = node~nextSibling - if result \= .nil then do - return result - end + if result \= .nil then return result -- go up to the parent parent = node~parentNode - do while parent \= .nil & parent \= root + loop while parent \== .nil & parent \== root result = parent~nextSibling - if result \= .nil then do - return result - end + if result \= .nil then return result parent = parent~parentNode end + -- end of the nodes, return .nil return .nil +-- internal node to locate a previous node ::method locatePreviousNode private expose root entityReferenceExpansion use strict arg node -- back to the root? We're done - if node == root then do - return .nil - end + if node == root then return .nil -- use the next sibling if it exists result = node~previousSibling - if result == .nil then do + if result == .nil then -- if no previous sibling, then step up to the parent return node~parentNode - end -- if the sibling has children, drill down to the last last child if result~hasChildNodes & \(\entityReferenceExpansion & result~nodeType == .Node~ENTITY_REFERENCE_NODE) then do - do while result~hasChildNodes + loop while result~hasChildNodes result = result~lastChild end end return result +-- remove a node from the iteration ::method removeNode expose forward currentNode use strict arg node - if node = .nil then do - return - end - delete = self~matchNodeOrParent(node) + if node = .nil then return - if forward then do - currentNode = self~locatePreviousNode(deleted) - end + deleted = self~matchNodeOrParent(node) + + if forward then currentNode = self~locatePreviousNode(deleted) else do next = self~locateNextNode(deleted, .false) - if next \= .nil then do - currentNode = next - end + if next \= .nil then currentNode = next else do - currentNode = self~locatedPreviousNode(deleted) + currentNode = self~locatePreviousNode(deleted) forward = .true end end @@ -5371,20 +5369,17 @@ expose currentNode root use strict arg node - if currentNode == .nil then do - return .nil - end + if currentNode == .nil then return .nil target = currentNode - do while target \= root - if node == target then do - return target - end + loop while target \= root + if node == target then return target target = target~parentNode end return .nil +-- detach this iterator from the document ::method detach expose root currentNode document @@ -6560,11 +6555,11 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: TreeWalker */ +/* Class: TreeWalkerImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "TreeWalker" public +::class "TreeWalkerImpl" inherit TreeWalker ::method init expose currentNode root whatToShow nodeFilter entityReferenceExpansion whatToShowFlags use strict arg root, self~whatToShow, nodeFilter, entityReferenceExpansion @@ -6579,95 +6574,77 @@ ::attribute whatToShow SET expose whatToShow whatToShowFlags use strict arg whatToShow - - if whatToShow == .NodeFilter~SHOW_ALL then do - flagValues = "11111111111" -- we'll set all flags to true - end - else do + -- convert the whatToShow flags into a string of binary digits that can be + -- easily tested + if whatToShow == .NodeFilter~SHOW_ALL then + whatToShowFlags = "111111111111" -- we'll set all flags to true -- convert this to a binary string, then pad out to 11 digits for the -- mapping - flagValues = whatToShow~d2x~x2b~right(11, 0) - end + else whatToShowFlags = whatToShow~d2x~x2b~right(12, 0) - whatToShowFlags = .directory~new - parse var flagValues whatToShowFlags[.Node~ELEMENT] +1 - - whatToShowFlags[.Node~ATTRIBUTE] +1 - - whatToShowFlags[.Node~TEXT] +1 - - whatToShowFlags[.Node~CDATA_SECTION] +1 - - whatToShowFlags[.Node~ENTITY_REFERENCE] +1 - - whatToShowFlags[.Node~ENTITY] +1 - - whatToShowFlags[.Node~PROCESSING_INSTRUCTION] +1 - - whatToShowFlags[.Node~COMMENT] +1 - - whatToShowFlags[.Node~DOCUMENT] +1 - - whatToShowFlags[.Node~DOCUMENT_TYPE] +1 - - whatToShowFlags[.Node~DOCUMENT_FRAGMENT] +1 - - whatToShowFlags[.Node~NOTATION] +1 - +-- retrieve the parent node of the ::attribute parentNode GET expose currentNode - if currentNode = .nil then do - return .nil - end + if currentNode = .nil then return .nil + -- if we have a parent, then that becomes the + -- new current node + node = currentNode~parentNode + if node \= .nil then currentNode = node + return node +-- retrieve the last child of the current node position ::method lastChild expose currentNode use strict arg - if currentNode == .nil then do - return .nil - end - + if currentNode == .nil then return .nil + -- skip forward to the last child node = self~getLastChild(currentNode) - if node \= .nil then do - currentNode = node - end - + if node \= .nil then currentNode = node return node +-- retrieve the previous sibling of the current node position ::method previousSibling expose currentNode use strict arg - node = self~getPreviousSibline(currentNode) - if node \= .nil then do - currentNode = node - end - + -- locate the previous sibling + node = self~getPreviousSibling(currentNode) + if node \= .nil then currentNode = node return node +-- get the next sibling of the current node ::method nextSibling expose currentNode use strict arg node = self~getNextSibling(currentNode) - if node \= .nil then do - currentNode = node - end - + if node \= .nil then currentNode = node return node +-- retrieve the previous node in the tree walking order ::method previousNode expose currentNode use strict arg - if currentNode == .nil then do - return .nil - end + if currentNode == .nil then return .nil + -- get the previous sibling. If we don't have one, + -- then it's time to step up to the parent level node = self~getPreviousSibling(currentNode) if node == .nil then do node = self~getParentNode(currentNode) - if result \= .nil then do - currentNode = node - return node - end - return .nil + if node \= .nil then currentNode = node + return node end + -- in traversal order, we would be coming up from the depths, + -- so first we go the last child of that sibling, and keep + -- drilling down to the last child of each one in order lastChild = self~getLastChild(node) - previos = lastChild + previous = lastChild - do while lastChild \= .nil + loop while lastChild \= .nil previous = lastChild lastChild = self~getLastChild(previous) end @@ -6679,28 +6656,26 @@ return lastChild end - if node \= .nil then do - currentNode = node - return currentNode - end + -- didn't find a last child, so we're returning the sibling, + -- which we know not to be .nil at this point + currentNode = node + return currentNode - return .nil - +-- get the next node in the sequence ::method nextNode expose currentNode use strict arg - if currentNode == .nil then do - return .nil - end + if currentNode == .nil then return .nil + -- first choice is a child of this node node = self~getFirstChild(currentNode) if node \= .nil then do currentNode = node return node end - + -- ok, step to the next sibling node node = self~getNextSibling(currentNode) if node \= .nil then do @@ -6708,6 +6683,7 @@ return node end + -- ok, up to the parent parent = self~getParentNode(currentNode) do while parent \= .nil node = self~getNextSibling(parent) @@ -6715,178 +6691,143 @@ currentNode = node return node end - + -- no siblings, try from its parent parent = self~getParentNode(parent) end - + -- reached the root...we're finished return .nil +-- special method to retrieve a parent node. This also applies +-- filtering logic to the process ::method getParentNode private expose currentNode - if node == .nil | node == root then do - return .nil - end + if node == .nil | node == root then return .nil newNode = node~parentNode - if newNode == .nil then do - return .nil - end + if newNode == .nil then return .nil - if self~acceptNode(newNode) == .NodeFilter~FILTER_ACCEPT then do + if self~acceptNode(newNode) == .NodeFilter~FILTER_ACCEPT then return newNode - end - -- if skipped or rejected, try for another parent + -- if skipped or rejected, recursively try for another parent return self~getParentNode(newNode) +-- retrieve the next sibling node for the traversal, applying filtering logic +-- to the retrieval ::method getNextSibling private expose root use strict arg node, startNode = (root) - if node == .nil | node == startNode then do - return .nil - end + if node == .nil | node == startNode then return .nil newNode = node~nextSibling if newNode == .nil then do newNode = node~parentNode - if newNode = .nil | newNode == startNode then do - return .nil - end - - if self~acceptNode(newNode) == .NodeFilter~FILTER_SKIP then do + if newNode = .nil | newNode == startNode then return .nil + -- if filtered out, then try this recursively + if self~acceptNode(newNode) == .NodeFilter~FILTER_SKIP then return self~getNextSibling(newNode, startNode) - end - return .nil end + -- filter the node here accept = self~acceptNode(newNode) - if accept == .NodeFilter~FILTER_ACCEPT then do - return newNode - end + -- accepted, return this + if accept == .NodeFilter~FILTER_ACCEPT then return newNode + -- told to skip...try for a child first, and if there + -- are no children, try for another sibling else if accept == .NodeFilter~FILTER_SKIP then do child = self~getFirstChild(newNode) - if child == .nil then do - return self~getNextSibling(newNode, startNode) - end - return child - end - else do + if child \== .nil then + return child return self~getNextSibling(newNode, startNode) end + -- rejection basically means pretend this doesn't exist + else return self~getNextSibling(newNode, startNode) +-- retrieve the previous sibling, applying filtering logic ::method getPreviousSibling private expose root use strict arg node, startNode = (root) - if node == .nil | node == startNode then do - return .nil - end + if node == .nil | node == startNode then return .nil newNode = node~previousSibling if newNode == .nil then do newNode = node~parentNode - if newNode == .nil | newNode == startNode then do - return .nil - end + if newNode == .nil | newNode == startNode then return .nil - if self~acceptNode(newNode) == .NodeFilter~FILTER_SKIP then do + if self~acceptNode(newNode) == .NodeFilter~FILTER_SKIP then return self~getPreviousSibling(newNode, startNode) - end return .nil end accept = self~acceptNode(newNode) - if accept == .NodeFilter~FILTER_ACCEPT then do - return newNode - end + if accept == .NodeFilter~FILTER_ACCEPT then return newNode else if accept == .NodeFilter~FILTER_SKIP then do child = self~getLastChild(newNode) - if child == .nil then do + if child == .nil then return self~getPreviousSibling(newNode, startNode) - end return child end - else do - return self~getPreviousSibling(newNode, startNode) - end + else return self~getPreviousSibling(newNode, startNode) +-- get the first child of a node, applying filtering logic ::method getFirstChild private expose entityReferenceExpansion use strict arg node - if entityReferenceExpansion & node~nodeType == .Node~ENTITY_REFERENCE_NODE then do + -- if we're on an entity reference and expansion is disabled, there are no children + if \entityReferenceExpansion & node~nodeType == .Node~ENTITY_REFERENCE_NODE then return .nil - end newNode = node~firstChild - if newNode == .nil then do - return .nil - end + if newNode == .nil then return .nil accept = self~acceptNode(newNode) - if accept == .NodeFilter~FILTER_ACCEPT then do - return newNode - end + if accept == .NodeFilter~FILTER_ACCEPT then return newNode + -- if skipping, then we drill down to that child node else if accept == .NodeFilter~FILTER_SKIP & newNode~hasChildNodes then do child = self~getFirstChild(newNode) - if child == .nil then do - return self~getNextSibling(newNode, node) - end + if child == .nil then return self~getNextSibling(newNode, node) end - else do - return self~getNextSibling(newNode, node) - end + else return self~getNextSibling(newNode, node) +-- get the last child of a node, applying filtering rules ::method getLastChild private expose entityReferenceExpansion use strict arg node - if entityReferenceExpansion & node~nodeType == .Node~ENTITY_REFERENCE_NODE then do + if \entityReferenceExpansion & node~nodeType == .Node~ENTITY_REFERENCE_NODE then return .nil - end - newNode = self~lastChild - if newNode == .nil then do - return .nil - end + newNode = nofr~lastChild + if newNode == .nil then return .nil accept = self~acceptNode(newNode) - if accept == .NodeFilter~FILTER_ACCEPT then do - return newNode - end + if accept == .NodeFilter~FILTER_ACCEPT then return newNode else if accept == .NodeFilter~FILTER_SKIP & newNode~hasChildNodes then do child = self~getLastChild(newNode) - if child == .nil then do - return self~getPreviousSibling(newNode, node) - end + if child == .nil then return self~getPreviousSibling(newNode, node) end - else do - return self~getPreviousSibling(newNode, node) - end + else return self~getPreviousSibling(newNode, node) +-- do filtering logic on a node ::method acceptNode private expose nodeFilter whatToShowFlags use strict arg node - if nodeFilter == .nil then do - if whatToShowFlags[node~nodeType] then do - return .NodeFilter~FILTER_ACCEPT - end - else do - return .NodeFilter~FILTER_SKIP - end - end - else do - if whatToShowFlags[node~nodeType] then do - return nodeFilter~accept(node) - end - else do - return .NodeFilter~FILTER_SKIP - end - end + nodeFlag = (2**(node~nodetype - 1))~d2x~x2b~right(12, 0) + -- test the flags first...if bad, this is a skip + if whatToShowFlags~bitxor(nodeflag) \= 0 then + return .NodeFilter~FILTER_SKIP + if nodeFilter \== .nil then + return nodeFilter~accept(node) + + -- passed the flag selection and no filter, this is good + return .NodeFilter~FILTER_ACCEPT + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: CoreDocument */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-10 17:03:10
|
Revision: 8025 http://oorexx.svn.sourceforge.net/oorexx/?rev=8025&view=rev Author: bigrixx Date: 2012-07-10 17:03:03 +0000 (Tue, 10 Jul 2012) Log Message: ----------- A pretty thorough cleanup pass through the DOM event handling code Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-10 00:21:17 UTC (rev 8024) +++ incubator/orxutils/xml/xmldom.cls 2012-07-10 17:03:03 UTC (rev 8025) @@ -277,6 +277,12 @@ -- called as handleEvent(event) ::method handleEvent +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: DOMEventTarget */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- interface for the DOM objects that allow attaching of event listeners ::class "DOMEventTarget" public mixinclass object ::method addEventListener abstract @@ -285,6 +291,16 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: DocumentEvent */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +-- interface for the document objects that support event creation +::class "DocumentEvent" public mixinclass object +::method createEvent abstract + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: DocumentTraversal */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -1036,39 +1052,26 @@ /* Private methods */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ + +-- find the index position for a given attribute ::method findItemPoint private expose attributes use arg item - if attributes == .nil then do - return .nil - end + if attributes == .nil then return .nil - s = attributes~supplier - do while s~available - attr = s~item - if attr == item then do - return s~index - end - end + return attributes~itemIndex(item) - return .nil - - +-- find the index position for a given attribute name ::method findNamePoint private expose attributes use arg name - if attributes == .nil then do - return .nil - end + if attributes == .nil then return .nil - s = attributes~supplier - do while s~available - attr = s~item - if attr~nodeName == name then do - return s~index - end + loop i = 1 to attributes~size + attr = attributes[i] + if attr~nodeName == name then return i end return .nil @@ -1078,28 +1081,18 @@ expose attributes use arg namespace, name - if attributes == .nil then do - return .nil - end + if attributes == .nil then return .nil - s = attributes~supplier - do while s~available - attr = s~item + loop i = 1 to attributes~size + attr = attributes[i] if namespace == .nil then do - if attr~namespaceURI == .nil & name == attr~localName then do - return s~index - end - - if attr~localName == .nil & name == attr~nodeName then do - return s~index - end + if attr~namespaceURI == .nil & name == attr~localName then + return i + if attr~localName == .nil & name == attr~nodeName then + return i end - else do - if attr~namespaceURI == namespace & attr~localName == name then do - return s~index - end - end - s~next + else if attr~namespaceURI == namespace & attr~localName == name then + return i end return .nil @@ -1113,7 +1106,7 @@ if attributes \= .nil then do loop node over attributes if node == a then return .true - if node == .b then return .false + if node == b then return .false end end return .false @@ -1153,14 +1146,11 @@ expose attributes use strict arg name - if attributes == .nil then do - return .nil - end + if attributes == .nil then return .nil do attribute over attributes - if attribute~name == name then do + if attribute~name == name then return attribute - end end return .nil @@ -1174,14 +1164,11 @@ expose attributes use strict arg namespace, name - if attributes == .nil then do - return .nil - end + if attributes == .nil then return .nil do attribute over attributes - if attribute~localname == name & attribute~namespaceURI == namespace then do + if attribute~localname == name & attribute~namespaceURI == namespace then return attribute - end end return .nil @@ -1203,9 +1190,7 @@ attributes[index] = node end else do - if attributes == .nil then do - attributes = .list~new - end + if attributes == .nil then attributes = .list~new attributes~append(node) end @@ -1236,9 +1221,7 @@ attributes[index] = node end else do - if attributes == .nil then do - attributes = .list~new - end + if attributes == .nil then attributes = .list~new attributes~append(node) end end @@ -1301,7 +1284,8 @@ expose attributes use arg source if source \= .nil then do - attributes = .list~new + -- we use a queue because it can be addressed by relative position + attributes = .queue~new do attr over source attributes~append(attr~cloneNode(.true)) end @@ -1316,13 +1300,9 @@ ::method item expose attributes use strict arg position - if attributes == .nil then do - return .nil - end - else do - return attributes~makearray[position + 1] - end + if attributes == .nil then return .nil + else return attributes[position + 1] /*----------------------------------------------------------------------------*/ /* Method: length */ @@ -1332,12 +1312,8 @@ ::method length expose attributes use strict arg - if attributes \== .nil then do - return attributes~items - end - else do - return 0; - end + if attributes \== .nil then return attributes~size + else return 0 ::attribute attributes PRIVATE @@ -1408,12 +1384,12 @@ self~ownerNode~ownerDocument~setAttrNode(attribute, previous) return previous +-- add an attribute to the list. This also has effect of adding it to the +-- owning element ::method setNamedItemNS use strict arg attribute -- replacing an attribute with itself does nothing - if attribute~isOwned then do - return attribute - end + if attribute~isOwned then return attribute attribute~ownerNode = self~ownerNode attribute~isOwned = .true @@ -1439,44 +1415,42 @@ self~ownerNode~ownerDocument~setAttrNode(attribute, previous) return previous +-- remove an item from the attribute map ::method removeNamedItem use strict arg name index = self~findNamePoint(name) - if index == .nil then do - return .nil - end + if index == .nil then return .nil return self~remove(self~attributes[index], index, .true) +-- remove an item from the attribute map ::method removeNamedItemNS use strict arg namespaceURI, name index = self~findNamePointNS(namespaceURI, name) - if index == .nil then do - return .nil - end + if index == .nil then return .nil return self~remove(self~attributes[index], index, .true) +-- remove an item node ::method removeItem use strict arg attr, addDefault index = self~findItemPoint(attr) - if index == .nil then do - return .nil - end + if index == .nil then return .nil return self~remove(attr, index, addDefault) +-- internal removal method used by the different update methods ::method remove private use strict arg attr, index, addDefault = .false ownerDocument = self~ownerNode~ownerDocument name = attr~nodeName - if attr~isId then do - self~ownerDocument~removeIdentifier(attr~value) - end + -- if this is an id attribute, make sure the document knows + -- this is going away + if attr~isId then self~ownerDocument~removeIdentifier(attr~value) attributes = self~attributes @@ -1491,9 +1465,8 @@ -- the namespace uri comes from the deleted node, -- not the default source value if the default -- does not have a local name - if newAttr~localName \== .nil then do + if newAttr~localName \== .nil then newAttr~namespaceURI = attr~namespaceURI - end newAttr~ownerNode = self~ownerNode newAttr~isOwned = .true -- mark this as a default value @@ -1502,16 +1475,13 @@ setdefault = .true -- if this is the id attribute, make sure the document knows -- about this mapping - if attr~isId then do + if attr~isId then ownerDocument~putIdentifier(newAttr~nodeValue, ownerNode) - end end end end -- if we didn't end up setting a default, remove the node - if \setDefault then do - attributes~remove(index) - end + if \setDefault then attributes~remove(index) -- detach from usage attr~ownerNode = .nil attr~isOwned = .false @@ -1522,12 +1492,13 @@ ownerDocument~removedAttrNode(attr, self~ownerNode, name) return attr +-- clone the content of an attribue map ::method cloneContent use strict arg source srcnodes = source~attributes if srcnodes \= .nil then do - self~attributes = .List~new - do node over srcnodes + self~attributes = .Queue~new + loop node over srcnodes newNode = node~cloneNode(true) newNode~ownerNode = self~ownerNode newNode~isOwned = .true @@ -2650,16 +2621,17 @@ /* Class: DocumentImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "DocumentImpl" subclass ParentNode public inherit Document DocumentTraversal +::class "DocumentImpl" subclass ParentNode public inherit Document DocumentTraversal DocumentEvent ::method init - expose iterators ranges eventListeners doctype hasMutationEvents + expose iterators ranges eventListeners doctype haveMutationEventListeners savedEventContext use arg doctype = .nil self~init:super iterators = .nil ranges = .nil eventListeners = .nil - hasMutationEvents = .false + haveMutationEventListeners = .false + savedEventContext = .nil ::method cloneNode use strict arg deep = .false @@ -2757,26 +2729,16 @@ end end -::method removedAttrNode - use strict arg attr, oldOwner, name - -::method renamedAttrNode - use strict arg oldAttr, newAttr - - +-- create an event object. Part of the DocumentEvent support ::method createEvent use strict arg type - if type~caselessEquals("Event") then do - return .DOMEvent~new - end - else if type~caselessEquals("MutationEvent") then do - return .DOMMutationEvent~new - end - else do - .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) - end + if type~caselessEquals("Event") then return .DOMEvent~new + else if type~caselessEquals("MutationEvent") then return .DOMMutationEvent~new + else .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) -::attribute hasMutationEvents +-- flag to indicate if there are any mutation event listeners in use. +-- provides an optimization for the normal case of no listeners. +::attribute haveMutationEventListeners -- set a set of event listeners for a given node ::method setEventListeners @@ -2794,13 +2756,13 @@ eventListeners~remove(node) -- if there are no more listeners, turn off even checking if eventListeners~isEmpty then - self~hasMutationEvents = .false + self~haveMutationEventListeners = .false end else do -- add this to the listener table and make sure the -- event flag is turned on eventListeners[node] = listeners - self~hasMutationEvents = .true + self~haveMutationEventListeners = .true end -- retrieve the event listeners for a target node @@ -3043,9 +3005,7 @@ ::method lookupCapture private expose captures use strict arg type - if caputures == .nil then do - captures = .directory~new - end + if captures == .nil then captures = .directory~new capture = captures[type] -- create a tracker if this is the first request for this type @@ -3056,45 +3016,55 @@ return capture +-- dispatch an event to an entire subtree ::method dispatchEventToSubtree private use strict arg node, event + + -- if this is an element type, we need to dispatch + -- the attribute nodes too if node~nodeType == .Node~ELEMENT_NODE then do - do attr over node~attributes - self~dispatchinggEventToSubtree(attr, event) + loop attr over node~attributes + self~dispatchingEventToSubtree(attr, event) end end - self~dispatchingEventToSubtree(node~firstChild(, event)) + self~dispatchingEventToSubtree(node~firstChild, event) +-- handle dispatch of an event to a subtree. This will +-- recursively hit the entire subtree ::method dispatchingEventToSubtree use strict arg node, event - if node == .nil then do - return - end + if node == .nil then return + -- dispatch the event to this node node~dispatchEvent(event) + -- if this is an element, dispatch on the attributes as well if node~nodeType == .Node~ELEMENT_NODE then do - do attr over node~attributes + loop attr over node~attributes self~dispatchingEventToSubtree(attr, event) end end + -- hit the first child, which will also propagate to the siblings self~dispatchingEventToSubtree(node~firstChild, event) + -- send down the sibling chain as well self~dispatchingEventToSubtree(node~nextSibling, event) +-- dispatch an aggregate event ::method dispatchAggregateEvents use strict arg node, enclosingAttr = .nil, oldvalue = .nil, change = 0 owner = .nil - if enclosingAttr \= .nil then do + if enclosingAttr \== .nil then do capture = self~lookupCapture(.DOMMutationEvent~DOM_ATTR_MODIFIED) - owner = enclosingAttr~ownerElement - if capture~total then do - if owner \= .nil then do + attr = enclosingAttr[1] + if capture~total > 0 then do + owner = attr~ownerElement + if owner \== .nil then do me = .DOMMutationEvent~new me.initMutationEvent(.DOMMutationEvent~DOM_ATTR_MODIFIED, .true. - - .false, enclosingAttr, oldvalue, enclosingAttr~nodeValue, - - enclosing~nodeName, change) + .false, attr, enclosingAttr[2], attr~nodeValue, - + attr~nodeName, change) owner~dispatchEvent(me) end end @@ -3118,58 +3088,72 @@ end end -::method saveEnclosingAttr - expose savedEnclosingAttr +-- For some modification events, there is an event that says "we're modifying", +-- Followed by an event that says "We modified". These are dispatched at the same +-- time following the actual modification. However, the first event requires some of +-- the pre-event state. This caches the pre-event state needed for the first event +-- so that it can be retrieved to dispatch the event. The information is just +-- cached in a simple array item. +::method saveEventContext + expose savedEventContext use strict arg node - savedEnclosingAttr = .nil + -- clear any previous state...we might not actually be saving anything here + savedEventContext = .nil + -- First make sure we've got listeners for this type of event at all capture = self~captureLookup(.DOMMutationEvent~DOM_ATTR_MODIFIED) if capture~total > 0 then do - eventAncestor = .nil - do forever - if eventAncestor == .nil then do - return - end + eventAncestor = node + -- search for a target event ancestor. We're looking for an + -- attribute node, but since the source event might be one of the + -- children of the attribute, we need to find the dispatch target. + loop forever + -- no attribute ancestor, done + if eventAncestor == .nil then return type = eventAncestor~nodeType - if type == .Node~ATTRIBUTE_NODe then do - retval = .EnclosingAttr(eventAncestor, eventAncestor~nodeValue) - savedEnclosingAttr = retval + -- found an attribute in the ancestry, this will be our target. Save + -- the current attribute node value (which may be a composite) to + -- broadcast in the event. + if type == .Node~ATTRIBUTE_NODE then do + savedEventContext = .array~of(eventAncestor, eventAncestor~nodeValue) return end - else if type == .Node~ENTITY_REFERENCE_NODE then do - eventAncestor = eventAncestor~parentNode - end - else if type == .Node~TEXT_NODE then do - eventAncestor = eventAncestor~parentNode - end - else do - return - end + -- an entity reference...move up the chain + else if type == .Node~ENTITY_REFERENCE_NODE then eventAncestor = eventAncestor~parentNode + -- text nodes also go up + else if type == .Node~TEXT_NODE then eventAncestor = eventAncestor~parentNode + -- starting point was not an ancestor of an attribute...done + else return end end +-- We're modifying character data on a node +-- this does not dispatch an event now...this will be done as part of an +-- aggregate later ::method modifyingCharacterData - expose hasMutationEvents - + expose haveMutationEventListeners use strict arg node, replace - if hasMutationEvents then do - if \replace then do - self~saveEnclosingAttr(node) - end + if haveMutationEventListeners then do + -- if we're not replacing, check if this belongs to an attribute + -- and save that context for event dispatch later + if \replace then self~saveEventContext(node) end +-- character data has been modified. ::method modifiedCharacterData - expose hasMutationEvents savedEnclosingAttr - + expose haveMutationEventListeners use strict arg node, oldValue, value, replace - if hasMutationEvents then do + -- if we have listeners, dispatch the event + if haveMutationEventListeners then self~mutationEventsModifiedCharacterData(node, oldValue, value, replace) - end +-- this dispatches multiple events for modified character data, +-- using potential cached state ::method mutationEventsModifiedCharacterData + expose savedEventContext use strict arg node, oldValue, value, replace if \replace then do @@ -3180,38 +3164,40 @@ .true, .false, .nil, oldValue, value, .nil, 0) self~dispatchEvent(node, me) end - - self~dispatchAggregateEvents(node, savedEnclosingAttr~node, oldValue) + -- now dispatch the aggregate event on the enclosing attribute + self~dispatchAggregateEvents(node, savedEventContext[1], oldValue) end -::method replaceCharacterData +-- character data replacement...handle as a modification +::method replacedCharacterData use strict arg node, oldvalue, value self~modifiedCharacterData(node, oldvalue, value, .false) +-- inserting a new node ::method insertingNode - expose hasMutationEvents - + expose haveMutationEventListeners use strict arg node, replace - if hasMutationEvents then do - if \replace then do - self~saveEnclosingAttr(node) - end - end + -- no event dispatched at this time, but save the + -- context for later + if haveMutationEventListeners & \replace then self~saveEventContext(node) + +-- inserting a node ::method insertedNode - expose hasMutationEvents ranges + expose haveMutationEventListeners ranges use strict arg node, newInternal, replace - if hasMutationEvents then do + -- if we have listeners, dispatch the event + if haveMutationEventListeners then self~mutationEventsInsertedNode(node, newInternal, replace) - end - if ranges \= .nil then do + -- handle the range-related updates + if ranges \= .nil then self~notifyRangesInsertedNode(newInternal) - end +-- process a node insertion event ::method mutationEventsInsertedNode private - expose savedEnclosingAttr + expose savedEventContext use strict arg node, newInternal, replace capture = self~lookupCapture(.DOMMutationEvent~DOM_NODE_INSERTED) @@ -3222,22 +3208,27 @@ self~dispatchEvent(newInternal, me) end + -- now see if anybody is watching at the document level capture = self~lookupCapture(.DOMMutationEvent~DOM_NODE_INSERTED_INTO_DOCUMENT) if capture~total > 0 then do - eventAncestor = .node - if savedEnclosingAttr \= .nil then do - eventAncestor = savedEnclosingAttr~node~ownerElement - end - if eventAncestor \= .nil then do + eventAncestor = node + -- if we have an active saved context, then the ancestor is the + -- element that owns the attribute of the saved context. + if savedEventContext \== .nil then + eventAncestor = savedEventContext[1]~ownerElement + if eventAncestor \== .nil then do parent = eventAncestor - do while parent \= .nil - if parent~nodeType == .Node~ATTRIBUTE_NODE then do - parent = parent~ownerDocument - end - else do - parent = parent~parentNode - end + loop while parent \== .nil + -- save the last valid parent + eventAncestor = parent + -- if we've walked back up to an attribute, the parent + -- is the owning element + if parent~nodeType == .Node~ATTRIBUTE_NODE then + parent = parent~ownerElement + -- get the parent + else parent = parent~parentNode end + -- did we eventually arrive at a document node? dispatch this if eventAncestor~nodeType == .Node~DOCUMENT_NODE then do me = .DOMMutationEvent~new me~initMutationEvent(.DOMMutationEvent~DOM_NODE_INSERTED_INTO_DOCUMENT, - @@ -3247,10 +3238,12 @@ end end - if \replace then do - self~dispatchAggregateEvents(node, savedEnclosingAttr~node, saveEnclosingAttr~oldValue) - end + -- also transmit DOMAttrModified and DOMSubtreeModified + -- (Common to most kinds of mutation) + if \replace then + self~dispatchAggregateEvents(node, savedEventContext[1], savedEventContext[2]) +-- notify any ranges of a node insertion ::method notifyRangesInsertNode expose ranges use strict arg newInternal @@ -3259,30 +3252,36 @@ range~insertedNodeFromDOM(newInternal) end +-- handle the pre-removal event processing. This may involve +-- notifying iterators and ranges of the event, allowing them +-- to update their internal state before things change ::method removingNode - expose iterators ranges hasMutationEvents + expose iterators ranges haveMutationEventListeners use strict arg node, oldChild, replace - if iterators \= .nil then do + -- have iterators? broadcast this to them + if iterators \= .nil then self~notifyIteratorsRemovingNode(oldChild) - end - if ranges \= .nil then do + -- ditto for the ranges + if ranges \= .nil then self~notifyRangesRemovingNode(oldChild) - end - if hasMutationEvents then do + -- if there are mutation event listeners, let them know too + if haveMutationEventListeners then self~mutationEventsRemovingNode(node, oldChild, replace) - end +-- notify any attached iterators that we're moving a node ::method notityIteratorsRemovingNode expose iterators use strict arg oldChild + -- just tap each one on the shoulder do iterator over iterators iterator~removeNode(oldChild) end +-- notify the rances of a removal ::method notifyRangesRemovingNode expose ranges use strict arg oldChild @@ -3291,14 +3290,17 @@ range~removeNode(oldChild) end +-- handle a node removal mutation event ::method mutationEventsRemovingNode - expose savedEnclosingAttr + expose savedEventContext use strict arg node, oldChild, replace - if \replace then do - self~saveEnclosingAttr(node) - end + -- if not a replacement operation, save the + -- context for post-update event processing + if \replace then + self~saveEventContext(node) + -- do we have capture listeners for this event type? capture = self~lookupCapture(.DOMMutationEvent~DOM_NODE_REMOVED) if capture~total > 0 then do me = .DOMMutationEvent~new @@ -3307,12 +3309,14 @@ self~dispatchEvent(oldChild, me) end + -- If within Document, the child's subtree is informed that it's + -- being removed capture~captureLookup(.DOMMutationEvent~DOM_NODE_REMOVED_FROM_DOCUMENT) - if capture~total then do + if capture~total > 0 then do eventAncestor = self - if savedEnclosingAttr \= .nil then do - eventAncestor = savedEnclosingAttr~node~ownerElement - end + if savedEventContext \== .nil then + eventAncestor = savedEventContext[1]~ownerElement + -- find the last non-null ancestor if eventAncestor \= .nil then do parent = eventAncestor~parentNode do while parent \= .nil @@ -3320,91 +3324,142 @@ parent = parent~parentNode end end + -- this must stil be part of a document for this to go out if eventAncestor~nodeType == .Node~DOCUMENT_NODE then do me = new .DOMMutationEvent~new me~initMutationEvent(.DOMMutationEvent~DOM_NODE_REMOVED_FROM_DOCUMENT, .false, .false, .nil, .nil, .nil, .nil, 0) + -- and dispatch to the removed subtree self~dispatchEventToSubtree(oldChild, me) end end +-- handle node removal notification. This is the post-update +-- event broadcast ::method removedNode - expose hasMutationEvents savedEnclosingAttr + expose haveMutationEventListeners savedEventContext use strict arg node, replace - if hasMutationEvents then do + if haveMutationEventListeners then do if \replace then do - self~dispatchAggregateEvents(node, savedEnclosingAttr~node, savedEnclosingAttr~oldValue) + self~dispatchAggregateEvents(node, savedEventContext~node, savedEventContext~oldValue) end end +-- broadcast intention of node replacement to the appropriate listeners ::method replacingNode - expose hasMutationEvents + expose haveMutationEventListeners use strict arg node - if hasMutationEvents then do - self~saveEnclosingAttr(node) - end + -- if we have events to broadcast later, save the context of the + -- replacement + if haveMutationEventListeners then + self~saveEventContext(node) +-- broadcast an impending data replacement ::method replacingData - expose hasMutationEvents + expose haveMutationEventListeners use strict arg node - if hasMutationEvents then do - self~saveEnclosingAttr(node) - end + -- if we have events to broadcast later, save the context of the + -- replacement + if haveMutationEventListeners then + self~saveEventContext(node) + +-- broadcast a node replacement ::method replacedNode - expose hasMutationEvents savedEnclosingAttr + expose haveMutationEventListeners savedEventContext use strict arg node - if hasMutationEvents then do - self~dispatchAggregateEvents(node, savedEnclosingAttr~node, saveEnclosingAttr~oldValue) - end + -- we've replaced a node...broadcast the update to the node listener and listeners on + -- the effected subtree + if haveMutationEventListeners then + self~dispatchAggregateEvents(node, savedEventContext[1], savedEventContext[2]) +-- handle attribute value notification ::method modifiedAttrValue - expose hasMutationEvents + expose haveMutationEventListeners use strict arg attr, oldValue - if hasMutationEvents then do + -- broadcast to all effected nodes + if haveMutationEventListeners then self~dispatchAggregateEvents(attr, attr, oldvalue, .DOMMutationEvent~MODIFICATION) - end +-- handle an attribute set event ::method setAttrNode - expose hasMutationEvents + expose haveMutationEventListeners use strict arg attr, previous - if hasMutationEvents then do - if previous == .nil then do + if haveMutationEventListeners then do + -- new node event + if previous == .nil then self~dispatchAggregateEvents(attr~ownerNode, attr, .nil, .DOMMutationEvent~ADDITION) - end - else do - self~dispatchAggregateEvents(attr~ownerNode, attr, previous~nodeValue, .DOMMutationEvent~MODIFICATION) - end + -- replacing an existing node, this is a modification + else self~dispatchAggregateEvents(attr~ownerNode, attr, previous~nodeValue, .DOMMutationEvent~MODIFICATION) end -::method removeAttrNode - expose hasMutationEvents +-- handle notification of attribute node removal +::method removedAttrNode + expose haveMutationEventListeners use strict arg attr, oldOwner, name - if hasMutationEvents then do + if haveMutationEventListeners then self~mutationEventRemovedAttrNode(attr, oldOwner, name) - end -::method mutationEventsRemovedAttrNode - use strict arg attr, oldOwner, name +-- real processing of attribute node removal +::method mutationEventRemovedAttrNode + use strict arg attr, oldAttr, name capture = self~lookupCapture(.DOMMutationEvent~DOM_ATTR_MODIFIED) if capture~total > 0 then do me = .DOMMutationEvent~new me~initMutationEvent(.DOMMutationEvent~DOM_ATTR_MODIFIED, .true, .false, attr, - attr~nodeValue, .nil, name, .DOMMutationEvent~REMOVAL) - self~dispatchEvent(oldOwner, me) + attr~nodeValue, .nil, name, .DOMMutationEvent~MODIFICATION) + self~dispatchEvent(oldAttr, me) end + -- we might need to dispatch events to the subtree as well self~dispatchAggregateEvents(oldOwner) +-- handle notification of attribute node rename +::method renamedAttrNode + use strict arg attr, oldName + + if haveMutationEventListeners then + self~mutationEventRenamedAttrNode(newAttr, attr, oldName) + +-- real processing of attribute node rename +::method mutationEventRenameAttrNode + use strict arg attr, oldName + + capture = self~lookupCapture(.DOMMutationEvent~DOM_ATTR_MODIFIED) + if capture~total > 0 then do + me = .DOMMutationEvent~new + me~initMutationEvent(.DOMMutationEvent~DOM_ATTR_MODIFIED, .true, .false, attr, + attr~nodeName, .nil, oldName, .DOMMutationEvent~MODIFICATION) + self~dispatchEvent(attr, me) + end + +-- handle notification of element renames ::method renamedElement + -- old node and new node should be the same + use strict arg element, oldName + if haveMutationEventListeners then + self~mutationEventRenamedElementNode(element, oldName) + +-- real processing of element node rename +::method mutationEventRenameElementNode + use strict arg element, oldName + + capture = self~lookupCapture(.DOMMutationEvent~DOM_ELEMENT_MODIFIED) + if capture~total > 0 then do + me = .DOMMutationEvent~new + me~initMutationEvent(.DOMMutationEvent~DOM_ELEMENT_MODIFIED, .true, .false, element, + element~nodeName, .nil, oldName, .DOMMutationEvent~MODIFICATION) + self~dispatchEvent(element, me) + end + ::class "EventListenerDescriptor" public ::method init expose type useCapture listener @@ -3656,7 +3711,7 @@ ::attribute value SET use strict arg newValue -- we might need to send mutation events, so get the old value - if self~ownerDocument~hasMutationEvents then + if self~ownerDocument~haveMutationEventListeners then -- get the old value (normalized) oldValue = self~textcontent:super @@ -3664,7 +3719,7 @@ forward message("TEXTCONTENT=") class(super) continue self~specified = .true - if self~ownerDocument~hasMutationEvents then + if self~ownerDocument~haveMutationEventListeners then self~ownerDocument~modifiedAttrValue(self, oldvalue) else self~changed @@ -5176,6 +5231,7 @@ ::constant DOM_NODE_INSERTED_INTO_DOCUMENT "DOMNodeInsertedIntoDocument" ::constant DOM_ATTR_MODIFIED "DOMAttrModified" ::constant DOM_CHARACTER_DATA_MODIFIED "DOMCharacterDataModified" +::constant DOM_ELEMENT_MODIFIED "DOMElementModified" ::method init @@ -7289,11 +7345,13 @@ newNode = node if node~nodeType == .Node~ELEMENT_NODE then do + oldName = node~nodeName node~rename(namespaceURI, name) self~callUserDataHandlers(node, .nil, .UserDataHandler~NODE_RENAMED) - self~renamedElement(node, node) + self~renamedElement(node, oldName) end else if node~nodeType == .Node~ATTRIBUTE_NODE then do + oldName = node~nodeName -- detach the attr from its owning element owner = node~ownerElement if owner \= .nil then @@ -7304,7 +7362,7 @@ owner~setAttributeNodeNS(node) self~callUserDataHandlers(node, .nil, UserDataHandler~NODE_RENAMED) -- fire AttributeNameChanged event - self~renamedAttrNode(node, node) + self~renamedAttrNode(node, nodeName) end else .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-11 00:30:39
|
Revision: 8033 http://oorexx.svn.sourceforge.net/oorexx/?rev=8033&view=rev Author: bigrixx Date: 2012-07-11 00:30:28 +0000 (Wed, 11 Jul 2012) Log Message: ----------- more cleanup and addition of ElementTraversal interface Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-10 22:36:38 UTC (rev 8032) +++ incubator/orxutils/xml/xmldom.cls 2012-07-11 00:30:28 UTC (rev 8033) @@ -42,6 +42,8 @@ -- initial tables .XPathToken~setup +::options trace c + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Section: Abstract DOM interface class definitions */ @@ -312,6 +314,20 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: ElementTraversal */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +-- interface for supporting element traversal methods +::class "ElementTraversal" mixinclass object +::method firstElementChild abstract +::method lastElementChild abstract +::method previousElementSibling abstract +::method nextElementSibling abstract +::method childElementCount abstract + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: NodeIterator */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -401,10 +417,56 @@ -- return .true return flagValues~bitand(testFlags) \= 0 +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: DocumentRange */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +::class "DocumentRange" public mixinclass Object +::method createRange abstract /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: Range */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "Range" public mixinclass Object +::constant START_TO_START 0 +::constant START_TO_END 1 +::constant END_TO_END 2 +::constant END_TO_START 3 + +::method startContainer abstract +::method startOffset abstract +::method endContainer abstract +::method endOffset abstract +::method collapsed abstract +::method commonAncestorContainer abstract + +::method setStart abstract +::method setEnd abstract +::method setStartBefore abstract +::method setStartAfter abstract +::method setEndBefore abstract +::method setEndAfter abstract +::method collapse abstract +::method selectNode abstract +::method selectNodeContents abstract +::method compareBoundaryPoints abstract +::method deleteContents abstract +::method extractContents abstract +::method cloneContents abstract +::method insertNode abstract +::method surroundContents abstract +::method cloneRange abstract +::method toString abstract +::method detach abstract + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Section: Concrete implementation of the DOM classes */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -1619,6 +1681,8 @@ ::attribute localName GET use strict arg return self~nodeName + +-- base URI is not supported yet ::attribute baseURI GET use strict arg return .nil @@ -2621,7 +2685,7 @@ /* Class: DocumentImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "DocumentImpl" subclass ParentNode public inherit Document DocumentTraversal DocumentEvent +::class "DocumentImpl" subclass ParentNode public inherit Document DocumentTraversal DocumentEvent DocumentRange ::method init expose iterators ranges eventListeners doctype haveMutationEventListeners savedEventContext use arg doctype = .nil @@ -2633,13 +2697,18 @@ haveMutationEventListeners = .false savedEventContext = .nil +-- clone a document node ::method cloneNode use strict arg deep = .false + -- create an instance of the same class (we might be subclassed) + -- and go through the cloning logic newDoc = self~class~new self~cloneDocument(newDoc, deep) return newDoc +-- retrieve the DOM implementation this is associated with. This +-- always returns the ooRexxDOM ::method implementation -- this is a singleton return .ooRexxDOM~implementation @@ -2671,50 +2740,58 @@ iterators~removeItem(iterator) + +-- create a range instance associated with this document ::method createRange expose ranges - if ranges == .nil then do - ranges = .list~new - end + use strict arg - range = .range~new(self) + -- if this is the first range, then create a list to track these + if ranges == .nil then ranges = .list~new + + -- create an instance and add it to the tracking list + range = .rangeImpl~new(self) ranges~append(range) return range +-- remove a range from the document ::method removeRange expose ranges use strict arg range - if range == .nil | ranges == .nil then do - return - end + + if range == .nil | ranges == .nil then return ranges~removeItem(range) +-- handle a replacedText event. This will broadcast to all of the ranges ::method replacedText expose ranges use strict arg node if ranges \= .nil then do - do range over ranges + loop range over ranges range~receiveReplacedText(node) end end + +-- handle a deletedText event. This will broadcast to all of the ranges ::method deletedText expose ranges use strict arg node, offset, count if ranges \= .nil then do - do range over ranges + loop range over ranges range~receiveDeletedText(node, offset, count) end end +-- handle a insertedText event. This will broadcast to all of the ranges ::method insertedText expose ranges use strict arg node, offset, count if ranges \= .nil then do - do range over ranges + loop range over ranges range~receiveInsertedText(node, offset, count) end end @@ -2724,7 +2801,7 @@ use strict arg node, newNode, offset if ranges \= .nil then do - do range over ranges + loop range over ranges range~receiveSplitData(node, newNode, offset) end end @@ -2808,9 +2885,8 @@ do le over nodeListeners if le~equals(type, listener, useCapture) then do nodeListeners~removeItem(le) - if nodeListeners~isEmpty then do + if nodeListeners~isEmpty then self~setEventListeners(node, .nil) - end -- remove this from the capture tables as well capture = self~lookupCapture(eventName) capture~removeListener(useCapture) @@ -2895,17 +2971,7 @@ * on the event which triggered them. Please be aware that this may * result in events arriving at listeners "out of order" relative * to the actual sequence of requests. - * <p> - * Note that our implementation resets the event's stop/prevent flags - * when dispatch begins. - * I believe the DOM's intent is that event objects be redispatchable, - * though it isn't stated in those terms. - * @param node node to dispatch to - * @param event the event object to be dispatched to - * registered EventListeners - * @return true if the event's <code>preventDefault()</code> - * method was invoked by an EventListener; otherwise false. -*/ + */ ::method dispatchEvent private use strict arg node, event @@ -3460,17 +3526,20 @@ self~dispatchEvent(element, me) end -::class "EventListenerDescriptor" public +-- internal class for tracking event listeners +::class "EventListenerDescriptor" ::method init expose type useCapture listener use strict arg type, listener, useCapture +-- test if an event listener matches a given search criteria ::method equals expose type useCapture listener use strict arg eventType, eventlistener, phase return phase == useCapture & listener == eventListener & eventType == type +-- tests if a handler should handle a given event phase ::method handlesEvent expose type useCapture @@ -3478,7 +3547,7 @@ return phase == useCapture & type == eventType --- invoke an event handler with +-- invoke an event handler with syntax error handling ::method invoke expose listener use strict arg event @@ -3496,10 +3565,14 @@ ::method init expose captures total bubble total +-- the number of capture phase listeners we have for this event ::attribute captures GET +-- the total number of listeners we have for this event type ::attribute total GET +-- the total number of bubble phase listeners we have for this event type ::attribute bubbles GET +-- add another listener for a given event type ::method addListener expose captures total bubbles use arg useCapture @@ -3509,6 +3582,7 @@ if useCapture then captures += 1 else bubbles += 1 +-- remove a listener from the tracking for this event ::method removeListener expose captures total bubbles use arg useCapture @@ -3520,7 +3594,7 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: Attr */ +/* Class: AttrImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -3535,9 +3609,8 @@ use strict arg ownerDoc, nodeName, namespaceURI = .nil, explicitLocalName = .nil self~init:super(ownerDoc) self~setName(nodeName) - if explicitLocalName \= .nil then do + if explicitLocalName \= .nil then localName = explicitLocalName - end self~specified = .false -- process a name change for this attribute @@ -3545,27 +3618,23 @@ expose namespaceURI localName prefix use arg qname -- null string is the same as not there - if namspaceURI == "" then do + if namspaceURI == "" then namespaceURI = .nil - end colon1 = qname~pos(":") colon2 = qname~lastPos(":") -- no prefix - if colon1 == 0 then do + if colon1 == 0 then -- local name and qualified name are the same localName = qname - end - else do - parse var qname prefix =(colon1) =(colon2 + 1) localName - end + else parse var qname prefix =(colon1) =(colon2 + 1) localName -- support for the Document renameNode method ::method rename use strict arg uri, name = .nil - if name == .nil then do + + if name == .nil then self~nodeName = uri - end else do self~nodeName = name self~namespaceURI = uri @@ -3578,26 +3647,21 @@ ::attribute prefix GET expose nodeName index = nodeName~pos(":") - if index > 0 then do + if index > 0 then return nodeName~substr(1, index - 1) - end - else do - return .nil - end + else return .nil ::attribute prefix SET expose nodeName localName use strict arg prefix -- we're either adding or replacing the prefix - if prefix \= "" then do + if prefix \= "" then nodeName = prefix":"localName - end -- or removing it entirely - else do - nodeName = localName - end + else nodeName = localName +-- the localname part of the qualified name ::attribute localName GET -- resolve the prefix that a node is using for a given namespace URI @@ -3635,64 +3699,65 @@ return ownerNode~isDefaultNamespace(uri) return .false +-- indicates that this attribute has been marked as an id attribute ::attribute isId +-- clone an attribute node ::method cloneNode expose value use strict arg deep = .false + -- do the node cloning first newNode = self~cloneNode:super(deep) - + -- flip the specified flag newNode~specified = .true return newNode +-- override to return the attribute node type ::attribute nodeType GET use strict arg return .Node~ATTRIBUTE_NODE +-- node name attribute ::attribute nodeName +-- remap nodevalue setter/getter to the value method ::attribute nodeValue SET forward message("VALUE=") ::attribute nodeValue GET forward message("VALUE") +-- get the type name...this is the type information +-- from a schema, which is not yet implemented ::attribute typeName GET expose type use strict arg if type \= .nil then do - if type~isA(.String) then do - return type - end - else do - return type~typeName - end + if type~isA(.String) then return type + else return type~typeName end - else do - return .nil - end + else return .nil +-- return the type definition namespace. Not yet really +-- implemented since the parser doesn't have type support. ::attribute typeNamespace GET expose type use strict arg if type \= .nil then do - if \type~isA(.String) then do - return type~namespace - end - else do - return "http://www.w3.org/TR/REC-xml"; - end + if \type~isA(.String) then return type~namespace + else return "http://www.w3.org/TR/REC-xml"; end return .nil +-- determine if an attribute is derived from a given type ::method isDerivedFrom expose type use strict arg typeNamespace, typeName, derivationMethod - if type \= .nil, \type~isA(.String) then do + if type \= .nil, \type~isA(.String) then return type~isDOMDerivedFrom(typeNamespace, typeName, derivationMethod) - end return .false + -- set/retrieve type directly ::attribute type @@ -3723,10 +3788,10 @@ self~ownerDocument~modifiedAttrValue(self, oldvalue) else self~changed - if self~isId & self~ownerElement \== .nil then do + if self~isId & self~ownerElement \== .nil then self~ownerDocument~putIdentifier(newvalue, ownerElement) - end + -- set the value of the attribute. This adds a text node to the attribute -- node ::attribute value GET @@ -3740,14 +3805,13 @@ ::method buildTextContent private use arg buffer child = self~firstChild - do while child \= .nil + loop while child \= .nil if child~nodeType == .Node~ENTITY_REFERENCE_NODE then data = child~entryRefValue else if self~hasTextContent(child) then data = child~nodeValue - if data \== .nil then do + if data \== .nil then buffer~append(data) - end child = child~nextSibling end @@ -3757,16 +3821,15 @@ ::attribute textContent SET forward message("VALUE=") +-- get the element parent for this attribute ::attribute element GET use strict arg - if self~isOwned then do + if self~isOwned then return self~ownerNode - end - else do - return .nil - end + else return .nil +-- same as element ::attribute ownerElement GET forward message("ELEMENT") @@ -3779,7 +3842,7 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "ElementImpl" subclass ParentNode public inherit Element NodeList +::class "ElementImpl" subclass ParentNode public inherit Element NodeList ElementTraversal ::method init expose nodeName attributes namespaceURI localName type attributes = .nil @@ -3814,22 +3877,17 @@ expose namespaceURI localName use arg qname -- null string is the same as not there - if namespaceURI == "" then do - namespaceURI = .nil - end + if namespaceURI == "" then namespaceURI = .nil colon1 = qname~pos(":") colon2 = qname~lastPos(":") -- no prefix - if colon1 == 0 then do + if colon1 == 0 then -- local name and qualified name are the same localName = qname - end - else do - parse var qname prefix =(colon1) =(colon2 + 1) localName - -- TODO: validate the name information with the ownerdoc - end + else parse var qname prefix =(colon1) =(colon2 + 1) localName + -- support for the Document renameNode method ::method rename expose nodeName namespaceURI @@ -3850,99 +3908,87 @@ ::attribute prefix GET expose nodeName index = nodeName~pos(":") - if index > 0 then do - return nodeName~substr(1, index - 1) - end - else do - return .nil - end + if index > 0 then return nodeName~substr(1, index - 1) + else return .nil +-- set the prefix for the element name ::attribute prefix SET expose nodeName localName use strict arg prefix -- we're either adding or replacing the prefix - if prefix \= "" then do + if prefix \= "" then nodeName = prefix":"localName - end -- or removing it entirely - else do - nodeName = localName - end + else nodeName = localName +-- retrieve the localName ::attribute localName GET +-- standard nodetype override ::attribute nodeType GET + use strict arg return .node~ELEMENT_NODE +-- the node name attribue ::attribute nodeName GET +-- get the argument map holding the attributes ::attribute attributes GET expose attributes use strict arg - if attributes == .nil then do - attributes = .AttributeMap~new(self, .nil) - end - + if attributes == .nil then attributes = .AttributeMap~new(self, .nil) return attributes +-- set a new attribute set ::attribute attributes SET private +-- clone an element node ::method cloneNode expose attributes use strict arg deep = .false newNode = self~cloneNode(deep) -- the attributes are always copied regardless of the deep flag - if attributes \= .nil then do + if attributes \= .nil then newNode~attributes = attributes~cloneMap(newNode) - end - return newNode +-- get the base URI for this element...not supported yet ::attribute baseURI GET use strict arg return .nil +-- set the element owner document ::attribute ownerDocument SET private expose attributes use strict arg doc forward class(super) continue -- also set this for all of the attributes - if attributes \= .nil then do - attributes~ownerDocument = doc - end + if attributes \= .nil then attributes~ownerDocument = doc -- retrieve the value of a named attribute ::method getAttribute expose attributes use strict arg name - if attributes == .nil then do - return "" - end + if attributes == .nil then return "" attr = attributes~getNamedItem(name) - if attr == .nil then do - return "" - end - else do - return attr~value - end + if attr == .nil then return "" + else return attr~value -- get the node associated with a specific named attribute ::method getAttributeNode expose attributes use strict arg name - if attributes == .nil then do - return .nil - end - + if attributes == .nil then return .nil return attributes~getNamedItem(name) +-- return a list of all elements by tag name ::method getElementsByTagName use strict arg tagname -- this version does a lazy search @@ -3953,24 +3999,24 @@ expose nodeName return nodeName +-- remove an attribute from the element ::method removeAttribute expose attributes use strict arg name - if attributes \= .nil then do + if attributes \= .nil then return attributes~removeNamedItem(name) - end return .nil +-- remove an attribute node from an element ::method removeAttributeNode expose attributes use strict arg oldAttr - if attrbutes \= .nil then do - return attributes~removeItem(oldAttr, .true) - end + if attrbutes \= .nil then return attributes~removeItem(oldAttr, .true) return .nil +-- set a new attribute value on an element ::method setAttribute use strict arg name, value @@ -3984,47 +4030,36 @@ newAttr~value = value attributes~setNamedItem(newAttr) end - else do - newAttr~value = value - end + else newAttr~value = value return newAttr +-- set an attribute on an element by node ::method setAttributeNode use strict arg newAttr -- get the attribute map. This also creates it if -- we don't have one yet attributes = self~attributes - return attributes~setNamedItem(newAttr) - +-- set an attribute by localname/namespace pair ::method getAttributeNS expose attributes use strict arg namespaceURI, localName - if attributes == .nil then do - return "" - end + if attributes == .nil then return "" attr = attributes~getNamedItemNS(namespaceURI, localName) - if attr == .nil then do - return "" - end - else do - return attr~value - end + if attr == .nil then return "" + else return attr~value - -- set an attribute using a namespace URI and a qualified name ::method setAttributeNS expose attributes use strict arg namespaceURI, qualifiedName, value index = qualifiedName~pos(":") - if pos > 0 then do - parse var qualifiedName prefix ":" localName - end + if pos > 0 then parse var qualifiedName prefix ":" localName else do prefix = .nil localName = qualifiedName @@ -4046,53 +4081,50 @@ end return newAttr +-- remove an attribute by specified localname/namespace pair ::method removeAttributeNS expose attributes use strict arg namespaceURI, localName - if attributes == .nil then do - return .nil - end - + if attributes == .nil then return .nil return attributes~removeNamedItemNS(namespaceURI, localName) + +-- retrieve an attribute node by specified localname/namespace pair ::method getAttributeNodeNS expose attributes use strict arg namespaceURI, localName - if attributes == .nil then do - return .nil - end - + if attributes == .nil then return .nil return attributes~getNamedItemNS(namespaceURI, localName) +-- set an attribute node by specified localname/namespace pair ::method setAttributeNodeNS use strict arg newAttr -- get the attribute map. This also creates it if -- we don't have one yet attributes = self~attributes - return attributes~setNamedItemNS(newAttr) +-- test if an element has any attributes ::method hasAttributes expose attributes - if attributes == .nil then do - return .false - end - + if attributes == .nil then return .false return attributes~length > 0 +-- test if an element has a given attribute ::method hasAttribute use strict arg name return self~getAttributeNode(name) \= .nil +-- test if an element has a given attribute using a namespace qualified name ::method hasAttributeNS use strict arg namespaceURI, localName - return self~getAttributeNodeNS(namespaceURI, localName) \= .nil +-- get all elements using a namespace qualified name ::method getElementsByTagNameNS use strict arg namespaceURI, localName @@ -4133,179 +4165,130 @@ ::attribute typeName GET expose type use strict arg - if type \= .nil then do - return type~typeName - end - else do - return .nil - end + if type \= .nil then return type~typeName + else return .nil +-- retrieve the type namespace ::attribute typeNamespace GET expose type use strict arg - if type \= .nil then do - return type~namespace - end - else do - return .nil - end + if type \= .nil then return type~namespace + else return .nil +-- test if a node is derived from a given type ::method isDerivedFrom expose type use strict arg typeNamespace, typeName, derivationMethod - if type \= .nil then do + if type \= .nil then return type~isDOMDerivedFrom(typeNamespace, typeName, derivationMethod) - end - else do - return .false - end + else return .false -- set/retrieve type directly ::attribute type +-- retrieve the schema information ::attribute schemaTypeInfo GET use strict arg return self -- ElementTraversal methods +-- return the count of child elements ::attribute childElementCount GET use strict arg count = 0 child = self~firstElementChild - do while child \= .nil + loop while child \= .nil count += 1 child = child~nextElementSibling end return count +-- get the first element child of this node (skipping over non-element children) ::attribute firstElementChild GET use strict arg node = self~firstChild - do while node \= .nil - if node~nodeType == .Node~ELEMENT_NODE then do - return node - end + loop while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then return node else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do - e = self~getFirstChildElement(node) - if e \= .nil then do - return e - end + e = self~getFirstElementChild(node) + if e \= .nil then return e end node = node~nextSibling end return .nil +-- get the last elemet child of this element ::attribute lastElementChild GET use strict arg node = self~lastChild - do while node \= .nil - if node~nodeType == .Node~ELEMENT_NODE then do - return node - end + loop while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then return node else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do - e = self~getFirstChildElement(node) - if e \= .nil then do - return e - end + e = self~getLastChildElement(node) + if e \= .nil then return e end node = node~previousSibling end return .nil +-- get the next element sibling of this node ::attribute nextElementSibling GET use strict arg node = self~nextLogicalSibling(self) - do while node \= .nil - if node~nodeType == .Node~ELEMENT_NODE then do - return node - end + loop while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then return node else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do - e = self~getFirstChildElement(node) - if e \= .nil then do - return e - end + e = self~getFirstElementChild(node) + if e \= .nil then return e end node = node~nextLogicalSibling(node) end return .nil +-- get the previous element sibling ::attribute previousElementSibling GET use strict arg node = self~previousLogicalSibling(self) - do while node \= .nil - if node~nodeType == .Node~ELEMENT_NODE then do - return node - end + loop while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then return node else if node~nodeType == .Node~ENTITY_REFERENCE_NODE then do - e = self~getFirstChildElement(node) - if e \= .nil then do - return e - end + e = self~getLastElementChild(node) + if e \= .nil then return e end node = node~previousLogicalSibling(node) end return .nil +-- get the first element child of this node ::method getFirstElementChild private use strict arg node top = node - do while node \= .nil - if node~nodeType == .Node~ELEMENT_NODE then do - return node - end + loop while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then return node next = node~firstChild - do while next \= .nil - if node == top then do - leave; - end + loop while next \= .nil + if node == top then leave next = node~nextSibling if next \= .nil then do node = node~parentNode - if node == .nil | node == top then do - return .nil - end + if node == .nil | node == top then return .nil end end node = next end return .nil -::method getLastElementChild private - use strict arg node - - top = node - - do while node \= .nil - if node~nodeType == .Node~ELEMENT_NODE then do - return node - end - next = node~lastChild - do while next \= .nil - if node == top then do - leave; - end - next = node~previousSibling - if next \= .nil then do - node = node~parentNode - if node == .nil | node == top then do - return .nil - end - end - end - node = next - end - return .nil - +-- get the next logical sibling of this node ::method nextLogicalSibling private use arg node @@ -4313,17 +4296,16 @@ if next == .nil then do parent = node~parentNode - do while parent \= .nil, parent~nodeType == .Node~ENTITY_REFERENCE_NODE + loop while parent \= .nil, parent~nodeType == .Node~ENTITY_REFERENCE_NODE next = parent~nextSibling - if next \= .nil then do - leave - end + if next \= .nil then leave parent = parent~parentNode end end return next +-- get the previous logical sibling ::method previousLogicalSibling private use arg node @@ -4333,15 +4315,34 @@ parent = node~parentNode do while parent \= .nil, parent~nodeType == .Node~ENTITY_REFERENCE_NODE previous = parent~previousSibling - if previous \= .nil then do - leave - end + if previous \= .nil then leave parent = parent~parentNode end end return previous +-- Returns the first element node found from a +-- non-recursive reverse order traversal of the given node. +::method getLastElementChild private + use strict arg node + + top = node + loop while node \= .nil + if node~nodeType == .Node~ELEMENT_NODE then return node + next = node~lastChild + loop while next \= .nil + if node == top then leave + next = node~previousSibling + if next \= .nil then do + node = node~parentNode + if node == .nil | node == top then return .nil + end + end + node = next + end + return .nil + -- resolve the prefix that a node is using for a given namespace URI ::method lookupPrefix use strict arg uri @@ -4475,61 +4476,70 @@ use strict arg ownerDocument, data self~init:super(ownerDocument) +-- character data nodes do not have children ::attribute childNodes GET use strict arg -- always returns an empty node list return .NodeListImpl~new +-- retrieve the nodevalue, which is the same as the data ::attribute nodeValue GET expose data use strict arg return data +-- set the nodeValue ::attribute nodeValue SET expose data use strict arg value, replace = .false oldValue = data + -- announce that we're modifying self~ownerDocument~modifyingCharacterData(self, replace) data = value - + -- and say we're done self~ownerDocument~modifiedCharacterData(self, oldValue, value, replace) +-- data is mapped to the node vale ::attribute data GET forward message("NODEVALUE") ::attribute data SET forward message("NODEVALUE=") + +-- retrieve the data length ::attribute length GET expose data use strict arg return data~length +-- append a string to the node data ::method appendData expose data use strict arg newData - if newData == .nil then do - return - end + if newData == .nil then return + + -- set the node value, which also handles events self~nodeValue = data||newData +-- delete data from the node ::method deleteData expose data use strict arg offset, count, replace = .false tailLength = max(data~length - count - offset, 0) - if offset >= data~length then do - newData = data - end - else do - newData = data~delstr(offset + 1, count) - end + if offset >= data~length then newData = data + else newData = data~delstr(offset + 1, count) -- set the node value to the adjusted version + -- we do this directly since we don't want to + -- raise set events data = newData + -- indicate we deleted self~ownerDocument~deletedText(self, offset, count) +-- insert data into the node ::method insertData expose data use strict arg offset, newData, replace = .false @@ -4538,8 +4548,9 @@ -- the Rexx insert function inserts after the given offset, not -- before. This actually works to our advantage. newValue = data~insert(newData, offset) + -- set directly to avoid set events data = newValue - + -- send the insertion event self~ownerDocument~insertedText(self, offset, newData~length) ::method replaceData @@ -5121,7 +5132,9 @@ ::constant NAMESPACE_ERR 14 ::constant INVALID_ACCESS_ERR 15 ::constant VALIDATION_ERR 16 -::constant TYPE_MISMATCH_ERR 16 +::constant TYPE_MISMATCH_ERR 17 +::constant BAD_BOUNDARYPOINTS_ERR 18 +::constant INVALID_NODE_TYPE_ERR 19 -- instance item for DOM errors. This is attached to the condition information ::method init @@ -5154,6 +5167,8 @@ messageTable[.DomException~VALIDATION_ERR] = "A call to a method such as insertBefore or removeChild would make the Node invalid with respect to document grammar." messageTable[.DomException~WRONG_DOCUMENT_ERR] = "A node is used in a different document than the one that created it." messageTable[.DomException~TYPE_MISMATCH_ERR] = "The value type for this parameter name is incompatible with the expected value type." + messageTable[.DomException~BAD_BOUNDARYPOINTS_ERR] = "The boundary-points of a Range do not meet specific requirements." + messageTable[.DomException~INVALID_NODE_TYPE_ERR] = "The container of a boundary-point of a Range is being set to either a node of an invalid type or a node with an ancestor of an invalid type." -- raise an error using the DOMException error numbers ::method raiseError class @@ -5446,10 +5461,11 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: Range */ +/* Class: RangeImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "Range" public + +::class "RangeImpl" public inherit Range ::constant START_TO_START 0 ::constant START_TO_END 1 ::constant END_TO_END 2 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-11 20:04:03
|
Revision: 8036 http://oorexx.svn.sourceforge.net/oorexx/?rev=8036&view=rev Author: bigrixx Date: 2012-07-11 20:03:56 +0000 (Wed, 11 Jul 2012) Log Message: ----------- a lot of work on Range interface Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-11 01:12:02 UTC (rev 8035) +++ incubator/orxutils/xml/xmldom.cls 2012-07-11 20:03:56 UTC (rev 8036) @@ -2127,6 +2127,21 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +-- retrieve the nodes complete ancestor chain +::attribute ancestors get + use strict arg + + -- NB: We include the target node itself in this list...if you wish to exclude that, + -- start the request one level up + ancestors = .array~new + node = self + loop while node \= .nil + ancestors~append(node) + node = node~parentNode + end + + return ancestors + ::attribute ctr class private ::attribute id private @@ -2750,7 +2765,7 @@ if ranges == .nil then ranges = .list~new -- create an instance and add it to the tracking list - range = .rangeImpl~new(self) + range = .RangeImpl~new(self) ranges~append(range) return range @@ -5468,137 +5483,104 @@ ::attribute startOffset GET ::attribute endContainer GET ::attribute endOffset GET + +-- test if a range has been collapsed. A collapsed range +-- starts and ends in the same container and has the same offset ::attribute collapsed GET expose startContainer endContainer startOffset endOffset use strict arg return startContainer == endContainer & startOffset = endOffset +-- locate the common ancestor of both the start and end containers ::attribute commonAncestorContainer GET expose startContainer - startV = .array~new - node = startContainer - do while node \= .nil - startV~append(node) - node = node~parentNode - end - endV = .array~new + -- build a chain of the start containers ancestor chain + startAncestors = startContainer~ancestors + endAncestors = endContainer~ancestors - node = endContainer - do while node \= .nil - endV~append(node) - node = node~parentNode - end - -- this will give all of the common elements, -- retaining the order. The last one is the -- element we want - common = startV~intersection(endV) + common = startAncestors~intersection(endV) + -- not really good if they have no common ancestor + if common~isEmpty then return .nil + -- the last item is the one we want return common[common~last] +-- set the range start as a node and offset ::method setStart - expose startContainer startOffset endContainer endOffset + expose startContainer startOffset use strict arg refNode, offset + -- validate this is a valid starting point and set the start item self~checkIndex(refNode, offset) startContainer = refNode startOffset = offset - if self~commonAncestorContainer == .nil | - - (startContainer == endContainer & endOffset < startOffset) then do - self~collapse(.true) - end + self~checkCollapse -- this new range may require collapsing +-- set the end position ::method setEnd - expose startContainer startOffset endContainer endOffset + expose endContainer endOffset use strict arg refNode, offset + -- validate this is a valid ending point and set the end items self~checkIndex(refNode, offset) endContainer = refNode endOffset = offset - if self~commonAncestorContainer == .nil | - - (startContainer == endContainer & endOffset < startOffset) then do - self~collapse(.false) - end + self~checkCollapse -- this new range may require collapsing - +-- set the start position as being before a target node ::method setStartBefore - expose startContainer startOffset endContainer endOffset + expose startContainer startOffset use strict arg refNode startContainer = refNode~parentNode - i = 0 - node = refNode - do while node \= .nil - i += 1 - node = node~previousSibling - end + -- the starting offset is one less than the node offset + startOffset = self~nodeOffset(startContainer) - 1 - startOffset = i - 1 + self~checkCollapse -- this new range may require collapsing - -- now collapse this, if necessary - if self~commonAncestorContainer == .nil | - - (startContainer == endContainer & endOffset < startOffset) then do - self~collapse(.true) - end - - +-- set the start position to immediately after a given node ::method setStartAfter expose startContainer startOffset endContainer endOffset use strict arg refNode startContainer = refNode~parentNode - i = 0 - node = refNode - do while node \= .nil - i += 1 - node = node~previousSibling - end + -- the starting offset is the node offset + startOffset = self~nodeOffset(startContainer) - startOffset = i + self~checkCollapse -- this new range may require collapsing - -- now collapse this, if necessary - if self~commonAncestorContainer == .nil | - - (startContainer == endContainer & endOffset < startOffset) then do - self~collapse(.true) - end - - +-- set the end position after a given node ::method setEndAfter - expose startContainer startOffset endContainer endOffset + expose endContainer endOffset use strict arg refNode - endContainer = refNode~parentNode - i = 0 - node = refNode - do while node \= .nil - i += 1 - node = node~previousSibling - end + -- the starting offset is the node offset + startOffset = self~nodeOffset(startContainer) - endOffset = i + self~checkCollapse -- this new range may require collapsing - -- now collapse this, if necessary - if self~commonAncestorContainer == .nil | - - (startContainer == endContainer & endOffset < startOffset) then do - self~collapse(.false) - end - - +-- collapse a range ::method collapse expose startContainer startOffset endContainer endOffset use strict arg toStart + -- collapsing to the start? The end becomes same as the start if toStart then do endContainer = startContainer endOffset = startOffset end + -- collapsing to the end...the start becomes the end else do startContainer = endContainer startOffset = endOffset end +-- select a node. This node is both the start and end of the range. ::method selectNode expose startContainer startOffset endContainer endOffset use strict arg refnode @@ -5607,16 +5589,12 @@ if parent == .nil then do startContainer = parent endContainer = parent - i = 0 - node = refNode - do while node \= .nil - node = previousSibling - i += 1 - end - startOffet = i - 1 - endOffset = i + ennOffset = self~nodeOffset(refnode) + startOffset = endOffset - 1 end +-- select the contents of a node. The start and end containers are +-- the selected nodes, and the offsets cover all of the children ::method selectNodeContents expose startContainer startOffset endContainer endOffset use strict arg refnode @@ -5624,36 +5602,37 @@ startContainer = refNode startOffset = 0 endContainer = refNode - endOffset = 0 - first = refNode~firstChild - do while first \= .nil - endOffset += 1 - first = first~nextSibling - end + endOffset = self~nodeOffset(refNode~lastChild) +-- compare some boundary points between this range and +-- another range ::method compareBoundaryPoints expose startContainer startOffset endContainer endOffset use strict arg how, sourceRange select + -- comparing the start points when how == .Range~START_TO_START then do endPointA = sourceRange~startContainer endPointB = startContainer offsetA = sourceRange~startOffset offsetB = startOffset end + -- comparing the other start to our end when how == .Range~START_TO_END then do endPointA = sourceRange~startContainer endPointB = endContainer offsetA = sourceRange~startOffset offsetB = endOffset end + -- comparing the other end to our start when how == .Range~END_TO_START then do endPointA = sourceRange~endContainer endPointB = startContainer offsetA = sourceRange~endOffset offsetB = startOffset end + -- comparing the two end points when how == .Range~END_TO_END then do endPointA = sourceRange~endContainer endPointB = endContainer @@ -5678,14 +5657,10 @@ -- case 2: Child C of container A is ancestor of B current = endPointB parent = current~parentNode - do while parent \= .nil + loop while parent \= .nil if parent == endPointA then do - if offsetA <= self~indexOf(current, endPointA) then do - return 1 - end - else do - return -1 - end + if offsetA <= self~indexOf(current, endPointA) then return 1 + else return -1 end current = parent parent = parent~parentNode @@ -5694,168 +5669,173 @@ -- case 3: Child C of container B is ancestor of A current = endPointA parent = current~parentNode - do while parent \= .nil + loop while parent \= .nil if parent == endPointB then do - if self~indexOf(current, endPointB) < offsetB then do - return 1 - end - else do - return -1 - end + if self~indexOf(current, endPointB) < offsetB then return 1 + else return -1 end current = parent parent = parent~parentNode end -- case 4: preorder traversal of context tree. - depthDiff = 0 - node = endPointA - do while node \= .nil - depthDiff += 1 - node = node~parentNode - end + depthA = self~depthOf(endPointA) + depthB = self~depthOf(endPointB) - node = endPointB - do while node \= .nil - depthDiff -= 1 - node = node~parentNode - end + depthDiff = depthA - depthB - do while depthDiff > 0 + -- if A is deeper, back up + loop while depthDiff > 0 endPointA = endPointA~parentNode depthDiff -= 1 end - do while depthDiff < 0 + -- or possible B is deeper + loop while depthDiff < 0 endPointB = endPointB~parentNode depthDiff += 1 end + -- we should be at equal depths now, so keep going up + -- until these merge parentA = endPointA~parentNode parentB = endPointB~parentNode - do while parentA \= parentB + loop while parentA \= parentB endPointA = parentA endPointB = parentB parentA = parentA~parentNode parentB = parentB~parentNode end + -- now see if B follows A. node = endPointA~nextSibling - do while node \= .nil - if node == endPointB then do - return 1 - end + loop while node \= .nil + if node == endPointB then return 1 node = node~nextSibling end - + -- B must precede A return -1 +-- delete all of the range contents. ::method deleteContents use strict arg self~traverseContents(self~DELETE_CONTENTS) +-- extract the contents and return ::method extractContents use strict arg return self~traverseContents(self~EXTRACT_CONTENTS) +-- clone the contents in the range ::method cloneContents use strict arg return self~traverseContents(self~CLONE_CONTENTS) +-- insert a node into the range ::method insertNode expose startContainer startOffset endContainer endOffset insertedFromRange use strict arg newNode - if newNode == .nil then do - return - end + if newNode == .nil then return + type = newNode~nodeType currentChildren = 0 + -- when we do inserts, our listeners will get called back to inform us of this. + -- this flag lets the listener know that we're the source of this callback. insertedFromRange = .true + -- if the start container is a text node. then the range + -- refers to the text within the node. This is a string insertion if startContainer == .Node~TEXT_NODE then do parent = startContainer~parentNode currentChildren = parent~childNodes~length - cloneCurrent = startContainer~cloneNode(.false) - cloneCurrent~nodeValue = cloneCurrent~nodeValue~substr(startOffset + 1) - startContainer~nodeValue = startContainer~nodeValue(1, startOffset) - next = startContainer~nextSibling - if next \= .nil then do - if parent \= .nil then do - parent~insertBefore(newNode, next) - paretn~insertBefore(cloneNode, next) - end - end - else do - if parent \= .nil then do - parent~appendChild(newNode) - parent~appendChild(cloneCurrent) - end - end - -- update the ranges + -- this will split the text into two nodes, making the + -- second node the next sibling of this one. We insert the + -- new node between these two. + splitNode = startContainer~splitText(startOffset) + -- insert this between the container and the split node + parent~insertBefore(newNode, splitNode) + -- update the ranges. If the range was inside the + -- same text node, then the end container is the node + -- that was split off and the offset is adjusted for the + -- amount that stayed with the original node if endContainer == startContainer then do - endContainer = cloneCurrent + endContainer = splitNode endOffset -= startOffset end - else if endContainer == parent then do + -- if the end was the parent node, then adjust by the number of + -- children added. + else if endContainer == parent then endOffset += parent~childNodes~length - currentChildren - end - + -- broadcast a data split self~signalSplitdata(startContainer, cloneCurrent, startOffset) end else do - if endContainer == startContainer then do + -- not a text node, so we're inserting between nodes + -- in the same container, so the offsets refer to the container + children. Remember how many there are + if endContainer == startContainer then currentChildren = endContainer~childNodes~length - end current = startContainer~firstChild - do i = 1 to startOffset while current \= .nil + -- skip forward to the target starting offset + loop for startOffset while current \= .nil current = current~nextSibling end - if current \= .nil then do + + -- the offset might be at the end, so we may have to append + if current \= .nil then startContainer~insertBefore(newNode, current) - end - else do + else startContainer~appendChild(newNode) - end - if endContainer = startContainer & endOffset \= 0 then do - endOffset += endContainer~childNodes~length - currentNodes - end + -- if start and end are the same, then adjust the end offset by the + -- amount inserted. + if endContainer = startContainer & endOffset \== 0 then + endOffset += endContainer~childNodes~length - currentChildren end + -- as you were... insertedFromRange = .false +-- surround the contents of a range with a node. This basically +-- makes the entire range a child of the provided node ::method surroundContents expose startContainer startOffset endContainer endOffset use strict arg newParent - if newParent == .nil then do - return - end + if newParent == .nil then return type = newParent~nodeType realStart = startContainer realEnd = endContainer - if startContainer~nodeType == .Node~TEXT_NODE then do + -- text nodes for start and end change things because the + -- offsets refer to positions inside the text content + if startContainer~nodeType == .Node~TEXT_NODE then realStart = startContainer~parentNode - end - if endContainer~nodeType == .Node~TEXT_NODE then do + if endContainer~nodeType == .Node~TEXT_NODE then realEnd = endContainer~parentNode - end + -- get the contents of the range as a document fragment frag = self~extractContents() + -- insert the new node into the range self~insertNode(newParent) + -- append the node to the parent newParent~appendChild(frag) + -- the range now is the new parent self~selectNode(newParent) +-- clone the range, returning a new range covering the same positions ::method cloneRange expose document startContainer startOffset endContainer endOffset + -- get a new range from the document and set the same start/end values range = document~createRange range~setStart(startContainer, startOffset) range~setEnd(endContainer, endOffset) return range +-- return the string value of the range. This is created by extracting the TEXT and CDATA +-- and concatenating them together into a single string ::method string expose startContainer startOffset endContainer endOffset @@ -5863,58 +5843,59 @@ stopNode = endContainer buffer = .mutablebuffer~new + + -- if the start is a text node or cdata node, then the start offset is inside the character data if startContainer~nodeType == .Node~TEXT_NODE | startContainer~nodeType == .Node~CDATA_SECTION_NODE then do - if startContainer == endContainter then do + -- if the start and end are the same, we can just return the substring directly + if startContainer == endContainer then return startContainer~nodeValue~substr(startOffset + 1, endOffset - startOffset) - end - buffer~append(startContainer~nodeValue~substr(startOffset + 1)) + -- append the covered section + buffer~append(startContaine~substringData(startOffset)) end else do + -- step forward to the target offset node = node~firstChild if startOffset > 0 then do - counter = 0 - do while counter < startOffset, node \= .nil + loop for startOffset while node \= .nil node = node~nextSibling - counter += 1 end end - if nod == .nil then do + -- if we reached the end, then we need to step to the next logical node + if node == .nil then node = self~nextNode(startContainer, .false) - end end - + -- if the end it not a text type, then we need to do the same thing if endContainer~nodeType \= .Node~TEXT_NODE & endContainer~nodeType \= .Node~CDATA_SECTION_NODE then do - counter = endOffset stopNode = endContainer~firstChild - do while counter > 0, stopNode \= .nil - counter -= 1 + loop for endOffset while stopNode \= .nil stopNode = stopNode~nextSibling end - if stopNode == .nil then do + if stopNode == .nil then stopNode = self~nextNode(endContainer, .false) - end end - do while node \= stopNode, node \= .nil - if node~nodeType == .Node~TEXT_NODE | node~nodeType == .Node~CDATA_SECTION_NODE then do + -- step throug everything appending the contents of the text nodes + loop while node \= stopNode, node \= .nil + if node~nodeType == .Node~TEXT_NODE | node~nodeType == .Node~CDATA_SECTION_NODE then buffer~append(node~nodeValue) - end node = self~nextNode(node, .true) end - if endContainer~nodeType == .Node~TEXT_NODE | endContainer~nodeType == .Node~CDATA_SECTION_NODE then do - buffer~append(endContainer~nodeValue~substr(1, endOffset)) - end + -- and finally, check for an end target of a text node and append just the subpiece of it + if endContainer~nodeType == .Node~TEXT_NODE | endContainer~nodeType == .Node~CDATA_SECTION_NODE then + buffer~append(endContainer~substringData(1, endOffset)) return buffer~string +-- detach a range from a document ::method detach expose document use strict arg document~removeRange(self) document = .nil +-- broadcast a data splitting event to any other ranges ::method signalSplitData expose splitNode document use strict arg node, newNode, offset @@ -5923,14 +5904,16 @@ document~splitData(node, newNode, offset) splitNode = .nil +-- receive a split data notification from the document ::method receiveSplitData expose startContainer startOffset endContainer endOffset splitNode use strict arg node, newNode, offset - if node == .nil | newNode == .nil | splitNode == node then do - return - end + -- this could be one from us + if node == .nil | newNode == .nil | splitNode == node then return + -- a split to a text node that is our start container? If the split offset + -- is before our start, we need to adjust the offset if node == startContainer & startContainer~nodeType == .Node~TEXT_NODE then do if startOffset > offset then do startOffset = startOffset - offset @@ -5938,6 +5921,7 @@ end end + -- a similar check for the end if node == endContainer & endContainer~nodeType == .Node~TEXT_NODE then do if endtOffset > offset then do endOffset = endOffset - offset @@ -5945,6 +5929,7 @@ end end +-- broadcast a data deletiong event ::method deleteData expose deleteNode use strict arg node, offset, count @@ -5953,31 +5938,27 @@ node~deleteData(offset, count) deleteNode = .nil +-- and handle a text deletion event ::method receiveDeletedText expose startContainer startOffset endContainer endOffset deleteNode use strict arg node, offset, count - if node == .nil | deleteNode == node then do - return - end + -- nothing to do if this came from us + if node == .nil | deleteNode == node then return + -- if deleted from our start container, we need to adjust our starting offset if node == startContainer then do - if startOffset > offset + count then do + if startOffset > offset + count then startOffset = offset + (startOffset - (offset + count)) - end - else if startOffset > offset then do - startOffset = offset - end + else if startOffset > offset then startOffset = offset end if node == endContainer then do - if endOffset > offset + count then do + if endOffset > offset + count then endOffset = offset + (endOffset - (offset + count)) - end - else if endOffset > offset then do - endOffset = offset - end + else if endOffset > offset then endOffset = offset end +-- broadcast a data insertion ::method insertData expose insertNode use strict arg node, index, insert @@ -5986,66 +5967,59 @@ node~insertData(index, insert) insertNode = .nil +-- handle a data insertion notification from the document ::method receiveInsertedText expose startContainer startOffset endContainer endOffset insertNode use strict arg node, index, len - if node == .nil | deleteNode == node then do - return - end + -- ignore if we triggered this + if node == .nil | deleteNode == node then return - if node == startContainer then do - if index < startContainer then do - startOffset += len - end - end - if node == endContainer then do - if index < endOffset then do - endOffset += len - end - end + -- adjust the start or end offset if the insertion occurred + -- in our end points + if node == startContainer then + if index < startContainer then startOffset += len + if node == endContainer then + if index < endOffset then endOffset += len + +-- handle a text replacement event ::method receiveReplacedText expose startContainer startOffset endContainer endOffset use strict arg node - if node == .nil then do - return - end + if node == .nil then return - if node == startContainer then do - startOffset = 0 - end + -- if the replacement occurred in our nodes, then the offsets + -- go to zero. + if node == startContainer then startOffset = 0 + if node == endContainer then endOffset = 0 - if node == endContainer then do - endOffset = 0 - end - +-- an insertion coming from the DOM ... we might have been the ones to trigger this. ::method insertedNodeFromDOM expose startContainer startOffset endContainer endOffset insertNode insertedFromRange use strict arg node - if node == .nil | insertNode == node | insertedFromRange then do - return - end + -- this was our update, ignore it + if node == .nil | insertNode == node | insertedFromRange then return parent = node~parentNode + -- is this node one of our children? Find out its index and see + -- if this requires a range adjustment if parent == startContainer then do index = self~indexOf(node, startContainer) - if index < startOffset then do - startOffset += 1 - end + if index < startOffset then startOffset += 1 end + -- ditto for the end container if parent == endContainer then do index = self~indexOf(node, endContainer) - if index < endOffset then do - endOffset += 1 - end + if index < endOffset then endOffset += 1 end +-- handle a child removal for this range. ::method removeChild private expose removeChild use strict arg parent, child @@ -6054,30 +6028,27 @@ removeChild = .nil return old - +-- handle a node removal for the range ::method removeNode expose startContainer startOffset endContainer endOffset removeChild use strict arg node - if node == .nil | removeChild == node then do - return - end + -- This is a removal we already know about, so ignore + if node == .nil | removeChild == node then return + -- this may change the offsets, so check this out parent = node~parentNode if parent == startContainer then do index = self~indexOf(node, startContainer) - if index < startOffset then do - startOffset -= 1 - end + if index < startOffset then startOffset -= 1 end if parent == endContainer then do index = self~indexOf(node, endContainer) - if index < endOffset then do - endOffset-- - end + if index < endOffset then endOffset -= 1 end + -- there may be ancestor issues involved here if parent \= startContainer | parent \= endContainer then do if self~isAncestorOf(node, startContainer) then do startContainer = parent @@ -6091,31 +6062,29 @@ -- utility functions + +-- traverse the range contents, applying the appropriate operation ::method traverseContents private expose startContainer startOffset endContainer endOffset use strict arg now - if startContainer == .nil | endContainer = .nil then do - return .nil - end + -- not valid bounds always returns null + if startContainer == .nil | endContainer = .nil then return .nil -- Case 1: same container - if startContainer == endContainer then do - return self~traverseSameContainer(how) - end + if startContainer == endContainer then return self~traverseSameContainer(how) - -- Case 2: Child C if start container is ancestor of end container. + -- Case 2: Child C of start container is ancestor of end container. -- this can be quickly tested by walking the parent chain of the end -- container endContainerDepth = 0 node = endContainer parent = node~parentNode - do while parent \= .nil - if p == startContainer then do + loop while parent \= .nil + if parent == startContainer then return self~traverseCommonStartContainer(node, how) - end node = parent - parent = p~parentNode + parent = parent~parentNode endContainerDepth += 1 end @@ -6124,12 +6093,11 @@ endContainerDepth = 0 node = startContainer parent = node~parentNode - do while parent \= .nil - if p == endContainer then do + loop while parent \= .nil + if parent == endContainer then return self~traverseCommonEndContainer(node, how) - end node = parent - parent = p~parentNode + parent = parent~parentNode endContainerDepth += 1 end @@ -6139,14 +6107,15 @@ depthDiff = startContainerDept - endContainerDepth startNode = startContainer - do while depthDiff > 0 + -- adjust these to be at the same depth + loop while depthDiff > 0 startNode = startNode~parentNode depthDiff -= 1 end endNode = endContainer - do while depthDiff < 0 + loop while depthDiff < 0 endNode = endNode~parentNode depthDiff += 1 end @@ -6154,50 +6123,51 @@ sp = startNode~parentNode ep = endNode~parentNode - do while sp \= ep + loop while sp \= ep startNode = sp endNode = sp sp = sp~parentNode ep = ep~parentNode end + return self~traverseCommonAncestors(startNode, endNode, how) +-- perform a traversal on the same container level ::method traverseSameContainer private expose document startContainer startOffset endContainer endOffset use strict arg how fragment = .nil - if how == self~DELETE_CONTENTS then do + -- if we're deleting the contents, then we need to create a document fragment + -- to receive the deleted nodes + if how \= self~DELETE_CONTENTS then fragment = document~createDocumentFragment - end - nodeType = startContainer~nodeType + -- if the starting node is any of the text type nodes, then we need to split the node + -- and take the trailing section if nodeType == .Node~TEXT_NODe | nodeType == .Node~CDATA_SECTION_NODE | nodeType == .Node~COMMENT_NODE | nodeType == .Node~PROCESSING_INSTRUCTION_NODE then do + -- get the portion of the text from the start offset test = startContainer~nodeValue sub = s~substr(startOffset + 1, endOffset - startOffset) + -- if not cloning, then we need to delete the data and + -- collapse everything if how \= self~CLONE_CONTENTS then do startContainer~deleteData(startOffset, endOffset - startOffset) self~collapse(.true) end - if how == self~DELETE_CONTENTS then do - return .nil - end - if nodeType == .Node~TEXT_NODE then do - fragment~appendChild(document~createTestNode(sub)) - end - else if nodeType == .Node~CDATA_SECTION_NODE then do - fragment~appendChild(document~createCDATASection(sub)) - end - else if nodeType == .Node~COMMENT_NODE then do - fragment~appendChild(document~createComment(sub)) - end - else do -- .Node~PROCESSING_INSTRUCTION_NODE - fragment~appendChild(document~createProcessingInstruction(startContainer~nodeName, sub)) - end + -- no document fragment to return for a deletion + if how == self~DELETE_CONTENTS then return .nil + + -- create the appropriate node type and attach to the fragment + if nodeType == .Node~TEXT_NODE then fragment~appendChild(document~createTextNode(sub)) + else if nodeType == .Node~CDATA_SECTION_NODE then fragment~appendChild(document~createCDATASection(sub)) + else if nodeType == .Node~COMMENT_NODE then fragment~appendChild(document~createComment(sub)) + else fragment~appendChild(document~createProcessingInstruction(startContainer~nodeName, sub)) + return fragment end @@ -6205,40 +6175,40 @@ node = self~getSelectedNode(startContainer, startOffset) count = endOffset - startOffset - do count + loop count sibling = node~nextSibling xferNode = self~traverseFullySelected(node, how) - if fragment \= .nil then do - fragment~appendChild(xferNode) - end + -- if we're accumulating, add to the fragment + if fragment \= .nil then fragment~appendChild(xferNode) node = sibling end - if now \= self~CLONE_CONTENTS then do + -- if not just copying, collapse the existing range + if how \= self~CLONE_CONTENTS then self~collapse(.true) - end - + -- return the fragment with the extracted nodes return fragment + +-- traverse over a range using a common start container ::method traverseCommonStartContainer private expose document startContainer startOffset endContainer endOffset use strict arg endAncestor, how fragment = .nil - - if how == self~DELETE_CONTENTS then do + -- if not deleting, create a document fragment to accumulate + if how \= self~DELETE_CONTENTS then fragment = document~createDocumentFragment - end + -- traverse the boundary at the endAncestor side node = self~traverseRightBoundary(endAncestor, how) - if fragment \= .nil then do - fragment~appendChild(node) - end + if fragment \= .nil then fragment~appendChild(node) endIndex = self~indexOf(endAncestor, startContainer) count = endIndex - startOffset if count <= 0 then do + -- if not cloning, we're removing these nodes, so collapse things if how \= self~CLONE_CONTENTS then do self~setEndBefore(endAncestor) self~collapse(.false) @@ -6246,70 +6216,66 @@ return fragment end + -- run through the sibling list getting the rest of the children node = endAncestor~previousSibling - do count + loop count sibling = node~previousSibling xferNode = self~traverseFullySelected(node, how) - if fragment \= .nil then do + if fragment \= .nil then fragment~insertBefore(xferNode, fragment~firstChild) - end node = sibling end - + -- again, collapse if this was not a cloning operation if how \= self~CLONE_CONTENTS then do self~setEndBefore(endAncestor) self~collapse(.false) end return fragment +-- traverse where there is a common end container ::method traverseCommonEndContainer private expose document startContainer endContainer use strict arg startAncestor, how + -- get an accumulator fragment if needed fragment = .nil - - if how == self~DELETE_CONTENTS then do + if how == self~DELETE_CONTENTS then fragment = document~createDocumentFragment - end + -- do the left boundary of the range and add if needed node = self~traverseLeftBoundary(endAncestor, how) - if fragment \= .nil then do - fragment~appendChild(node) - end + if fragment \= .nil then fragment~appendChild(node) + -- get the rest of the siblings startIndex = self~indexOf(startAncestor, endContainer) + 1 count = endOffset - startIndex node = startAncestor~nextSibling - do count + loop count sibling = node~nextSibling xferNode = self~traverseFullySelected(node, how) - if fragment \= .nil then do - fragment~appendChild(xferNode) - end + if fragment \= .nil then fragment~appendChild(xferNode) node = sibling end + -- collapse if needed if how \= self~CLONE_CONTENTS then do self~setStartAfter(startAncestor) self~collapse(.true) end return fragment +-- traverse a range where there are common ancestors ::method traverseCommonAncestors private expose document startContainer endContainer use strict arg startAncestor, endAncestor, how fragment = .nil - - if how == self~DELETE_CONTENTS then do + if how == self~DELETE_CONTENTS then fragment = document~createDocumentFragment - end node = self~traverseLeftBoundary(endAncestor, how) - if fragment \= .nil then do - fragment~appendChild(node) - end + if fragment \= .nil then fragment~appendChild(node) commonParent = startAncestor~parentNode startOffset = self~indexOf(startAncestor, commonParent) + 1 @@ -6318,19 +6284,15 @@ count = endOffset - startOffset sibling = startAncestor~nextSibling - do count + loop count nextSibling = sibling~nextSibling node = self~traverseFullySelected(sibling, now) - if fragment \= .nil then do - fragment~appendChild(node) - end + if fragment \= .nil then fragment~appendChild(node) sibling = nextSibling end node = self~traverseRightBoundary(endAncestor, how) - if fragment \= .nil then do - fragment~appendChild(node) - end + if fragment \= .nil then fragment~appendChild(node) if how \= self~CLONE_CONTENTS then do self~setStartAfter(startAncestor) @@ -6338,6 +6300,7 @@ end return fragment +-- traverse the right boundary of the range ::method traverseRightBoundary private expose document startContainer startOffset endContainer endOffset use strict arg root, how @@ -6345,88 +6308,88 @@ next = self~getSelectedNode(endContainer, endOffset - 1) isFullySelected = next \= endContainer - if next == root then do + if next == root then return self~traverseNode(next, isFullySelected, .false, now) - end parent = next~parentNode clonedParent = self~traverseNode(parent, .false, .false, how) - do while parent \= .nil - do while next \= .nil + loop while parent \= .nil + loop while next \= .nil prevSibling = next~previousSibling clonedChild = self~traverseNode(next, isFullySelected, .false, how) - if how \= self~DELETE_CONTENTS then do + if how \= self~DELETE_CONTENTS then clonedParent~insertBefore(clonedChild, clonedParent~firstChild) - end isFullySelected = .true next = prevSibling end - if parent == root then do - return clonedParent - end + if parent == root then return clonedParent next = parent~previousSibling parent = parent~parentNode node clonedGrandParent = self~traverseNode(parent, .false, .false, how) - if how \= self~DELETE_CONTENTS then do + if how \= self~DELETE_CONTENTS then clonedGrandParent~appendChild(clonedParent) - end clonedParent = clonedGrandParent end return .nil +-- traverse a single node ::method traverseNode private use strict arg node, isFullySelected, isLeft, how - if isFullySelected then do - return self~traverseFullySelected(node, how) - end + if isFullySelected then return self~traverseFullySelected(node, how) nodeType = node~nodeType + -- character data nodes get special handling if nodeType == .Node~TEXT_NODE | nodeType == .Node~CDATA_SECTION_NODE | - - nodeType == .Node~COMMENT_NODE | nodeType == .Node~PROCESSING_INSTRUCTION_NODE then do + nodeType == .Node~COMMENT_NODE | nodeType == .Node~PROCESSING_INSTRUCTION_NODE then return self~traverseCharacterDataNode(node, isLeft, how) - end - + -- handle the partial selection return self~traversePartiallySelected(node, how) +-- traverse a single node that is fully selected within the range ::method traverseFullySelected private use strict arg node, how select - when how == self~CLONE_CONTENTS then do + -- if cloning, do a deep copy of the node + when how == self~CLONE_CONTENTS then return node~cloneNode(.true) - end - when how == self~EXTRACT_CONTENTS then do + -- if we're extracting, just return the node as is + when how == self~EXTRACT_CONTENTS then return node - end + -- if deleting, remove the node and return .nil when how == self~DELETE_CONTENTS then do node~parentNode~removeChild(node) return .nil end end +-- handling a partially selected node ::method traversePartiallySelected use strict arg node, how select - when how == self~CLONE_CONTENTS then do + -- if cloning, this is just a shallow copy + when how == self~CLONE_CONTENTS then return node~cloneNode(.false) - end - when how == self~EXTRACT_CONTENTS then do + -- extraction is a shallow copy + when how == self~EXTRACT_CONTENTS then return node~cloneNode(.false) - end - when how == self~DELETE_CONTENTS then do + -- deleting returns .nil + when how == self~DELETE_CONTENTS then return .nil - end end +-- traverse a character node ::method traverseCharacterDataNode private use strict arg node, isLeft, how textValue = node~nodeValue + -- extract the section depending on direction (e.g., whether this + -- is a start or end node) if isLeft then do offset = self~startOffset newNodeValue = textValue~substr(offset + 1) @@ -6438,167 +6401,189 @@ oldNodeValue = textValue~substr(offset + 1) end - if how \= self~CLONE_CONTENTS then do - node~nodeValue = oldNodeValue - end - if how == self~DELETE_CONTENTS then do - return .nil - end - + -- if not cloning, then update the existing node + if how \= self~CLONE_CONTENTS then node~nodeValue = oldNodeValue + -- if deleting, we're done + if how == self~DELETE_CONTENTS then return .nil + -- clone the node and return the extracted bit newNode = node~cloneNode(.false) newNode~nodeValue = newNodeValue return newNode +-- check an index value for validity ::method checkIndex private use strict arg refNode, offset - if offset < 0 then do - .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) - end + if offset < 0 then .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) type= refNode~nodeType + -- if on a text node, this must lie within the length of the character data if nodeType == .Node~TEXT_NODE | nodeType == .Node~CDATA_SECTION_NODE | - nodeType == .Node~COMMENT_NODE | nodeType == .Node~PROCESSING_INSTRUCTION_NODE then do - if offset > refNode~nodeValue~length then do + if offset > refNode~nodeValue~length then .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) - end end - else do - if offset > refNode~childNodes~length then do + -- must lie with the range of children for the node + else if offset > refNode~childNodes~length then .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) - end + +-- check the start and end positions and determine if the range +-- needs to be collapsed +::method checkCollapse private + + -- if there is no common ancestor or the end precedes the start, then + -- this is a collapsed container + if self~commonAncestorContainer == .nil | - + (startContainer == endContainer & endOffset < startOffset) then self~collapse(.true) + +-- determine the relative offset of a node +::method nodeOffset private + use strict arg node + -- count the offset of the reference node relative to its siblings + loop i = 0 while node \= .nil + node = node~previousSibling end + -- the offset is one less than that + return i - 1 +-- get the root container of the node ::method getRootContainer private use strict arg node - do while node \= .nil + loop while node \= .nil node = node~parentNode end return node +-- test if a node is a legal container for a range ::method isLegalContainer private use strict arg node - if node == .nil then do - return .false - end - do while node \= .nil + if node == .nil then return .false + + -- check the entire ancestor chain for a non-allowed node type + loop while node \= .nil nodeType = node~nodeType - if nodeType == .Node~ENTITY_NODE | nodeType == .Node~NOTATION_NODE | nodeType == .Node~DOCUMENT_TYPE_NODE then do + -- these are invalid node types + if nodeType == .Node~ENTITY_NODE | nodeType == .Node~NOTATION_NODE | nodeType == .Node~DOCUMENT_TYPE_NODE then return .false - end node = node~parentNode end return .true +-- check if a node has a legal root container ::method hasLegalRootContainer private use strict arg node - if node == .nil then do - return .false - end + if node == .nil then return .false + rootContainer = self~getRootContainer(node) - nodeType = node~nodeType - if nodeType == .Node~ATTRIBUTE_NODE | nodeType == .Node~DOCUMENT_NODE | nodeType == .Node~DOCUMENT_FRAGMENT_NODE then do + nodeType = rootContainer~nodeType + -- attributes, documents, and document fragments are the only valid roots. + if nodeType == .Node~ATTRIBUTE_NODE | nodeType == .Node~DOCUMENT_NODE | nodeType == .Node~DOCUMENT_FRAGMENT_NODE then return .true - end return .false +-- check if we have a legal contained node for a start or end point ::method isLegalContainedNode private use strict arg node - if node == .nil then do - return .false - end + if node == .nil then return .false + + -- candidate nodes must be legal document tree nodes if nodeType == .Node~ATTRIBUTE_NODE | nodeType == .Node~DOCUMENT_NODE | nodeType == .Node~DOCUMENT_FRAGMENT_NODE | - - nodeType == .Node~ENTITY_NODE | nodeType == .Node~NOTATION_NODE then do + nodeType == .Node~ENTITY_NODE | nodeType == .Node~NOTATION_NODE then return .false - end return .true +-- traverse to the next logical node ::method nextNode private expose document use strict arg node, visitChildren - if node == .nil then do - return .nil - end + if node == .nil then return .nil + + -- if children are an option, then go to the first child if there is one if visitChildren then do - result = node~firstChild - if result \= .nil then do - return result - end + next = node~firstChild + if next \= .nil then return result end - result = node~nextSibling - if result \= .nil then do - return result - end + -- no children or skipping intentionally + -- try for a sibling + next = node~nextSibling + if next \== .nil then return result + + -- go up the parent hierarchy looking for a sibling to a direct + -- ancestor node parent = node~parentNode - do while parent \= .nil, parent \= document + loop while parent \= .nil, parent \= document result = parent~nextSibling - if result \= .nil then do - return result - end - else do - parent = parent~parentNode - end + if next \== .nil then return result + else parent = parent~parentNode end - + -- nothing found return .nil +-- test if a node is an ancestor of another node ::method isAncestorOf private use strict arg a, b + node = b - do while node \= .nil - if node == a then do - return .true - end + loop while node \= .nil + if node == a then return .true node = node~parentNode end return .false +-- determine the tree depth of a node +::method depthOf private + use strict arg node + + loop depthDiff = 0 while node \= .nil + node = node~parentNode + end + + return depthDiff + +-- find the index offset of a child node ::method indexOf private use strict arg child, parent - if child~parentNode \= parent then do - return -1 - end + if child~parentNode \== parent then return -1 + node = parent~firstChild - do i = 0 while node \= child + loop i = 0 while node \= child node = node~nextSibling end + return i - +-- get a selected node ::method getSelectedNode private use strict arg container, offset - if container~nodeType == .Node~TEXT_NODE then do - return container - end + -- if this is a text node, just return it directly. The offset + -- is within the text of the node + if container~nodeType == .Node~TEXT_NODE then return container - if offset < 0 then do - return container - end + -- a negative offset means return the container + if offset < 0 then return container + -- skip ahead to the indicated child child = container~firstChild - - do i = 1 to offset while child \= .nil + do offset while child \= .nil child = child~nextSibling end - if child \= null then do - return child - end - + if child \== .nil then return child + -- can't get the child, return the container return container This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-11 21:38:36
|
Revision: 8037 http://oorexx.svn.sourceforge.net/oorexx/?rev=8037&view=rev Author: bigrixx Date: 2012-07-11 21:38:29 +0000 (Wed, 11 Jul 2012) Log Message: ----------- add a couple of classes from DOM 3 spec and a bit more cleanup Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-11 20:03:56 UTC (rev 8036) +++ incubator/orxutils/xml/xmldom.cls 2012-07-11 21:38:29 UTC (rev 8037) @@ -79,6 +79,113 @@ ::method items forward message("LENGTH") +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: DOMStringList */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "DOMStringList" +-- initialize a string list from an array of strings +::method init + expose array + -- default is to create an empty list + use strict arg array = (.array~new) + +-- retrieve an item from the list using a 0-based index +::method item + expose array + use strict arg index + if index > 0 then return array[index] + -- defined as returning .nil for anything out of range + return .nil + +-- get the count of items in the array +::attribute length get + expose array + return array~items + +-- returns true if this list contains the given string +::method contains + expose array + use strict arg target + return array~hasItem(target) + +-- some compatibility methods to make nodelist feel like a Rexx collection +::method makearray + expose array + return array~copy -- return a copy of our array so this stays immutable + +::method "[]" + forward message("ITEM") +::method items + forward message("LENGTH") + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: NameList */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "NameList" +-- initialize an empty NameList +::method init + expose names namespaces + + +-- retrieve the indexed name item from the list (0-based index) +::method getName + expose names + use strict arg index + if index > 0 then return names[index] + -- defined as returning .nil for anything out of range + return .nil + + +-- retrieve the indexed name item from the list (0-based index) +::method getNamespaceURI + expose namespaces + use strict arg index + if index > 0 then return namespace[index] + -- defined as returning .nil for anything out of range + return .nil + +-- get the count of items in the list +::attribute length get + expose names + return names~items + +-- returns true if this list contains the given string +::method contains + expose names + use strict arg target + return names~hasItem(target) + +-- returns true if this list contains the given string +::method containsNS + expose names namespaces + use strict arg namespaceURI, name + + loop i = 1 to names~items + if names[i] == name & namespaces[i] == namespaceURI then return .true + end + return .false + +-- internal method for adding items to this list +::method addName + expose names namespaces + use strict arg namespaceURI, name + + names~append(name) + namespaces~append(namespaceURI) + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Node */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + + -- DOM Node interface class ::class "Node" public mixinclass Object -- various type definitions @@ -96,6 +203,14 @@ ::constant DOCUMENT_FRAGMENT_NODE 11 ::constant NOTATION_NODE 12 +-- DocumentPosition indicators +::constant DOCUMENT_POSITION_DISCONNECTED 1 +::constant DOCUMENT_POSITION_PRECEDING 2 +::constant DOCUMENT_POSITION_FOLLOWING 4 +::constant DOCUMENT_POSITION_CONTAINS 8 +::constant DOCUMENT_POSITION_IS_CONTAINED 16 +::constant DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC 32 + ::method nodeName abstract ::method nodeValue abstract ::method "nodeValue=" abstract @@ -126,6 +241,12 @@ ::method textContent abstract ::method isDefaultNamespace +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Attr */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- an abstract attribute interface definition ::class "Attr" mixinclass Node public ::method name abstract @@ -135,6 +256,12 @@ ::method "value=" abstract ::method isId abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: CharacterData */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- an abstract characterdata interface definition ::class "CharacterData" mixinclass Node public ::method appendData abstract @@ -146,20 +273,44 @@ ::method replaceData abstract ::method substringData abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Text */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract text definition ::class "Text" mixinclass CharacterData public ::method splitText abstract ::method wholeText abstract ::method replaceWholeText abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: CDATASection */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract CDATA section definition ::class "CDATASection" mixinclass Text public -- no additional methods defined on this interface +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Comment */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract Comment definition ::class "Comment" mixinclass CharacterData public -- no additional methods defined on this interface +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Document */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract document interface ::class "Document" mixinclass Node public ::method createAttribute abstract @@ -183,10 +334,22 @@ ::method adoptNode abstract ::method "encoding=" abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: DocumentFragment */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract documentfragment definition ::class "DocumentFragment" mixinclass Node public -- no additional methods defined on this interface +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: DocumentType */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract documenttype definition ::class "DocumentType" mixinclass Node public ::method entities abstract @@ -196,12 +359,24 @@ ::method publicID abstract ::method systemID abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: DOMImplementation */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract DOMImplementation definiton ::class "DOMImplementation" mixinclass Object public ::method createDocument abstract ::method createDocumentType abstract ::method hasFeature abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Element */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract Element definition ::class "Element" mixinclass Node public ::method getAttribute abstract @@ -225,6 +400,12 @@ ::method setIdAttributeNS abstract ::method setIdAttributeNode abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Entity */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract Entity definition ::class "Entity" mixinclass Node public ::method xmlEncoding abstract @@ -234,11 +415,23 @@ ::method xmlVersion abstract ::method inpugEncoding +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: EntityReference */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract entityreference definition ::class "EntityReference" mixinclass Node public -- no additional methods defined on this interface --- abstract NameNodeMap definition +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: NamedNodeMap */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +-- abstract NamedNodeMap definition ::class "NamedNodeMap" mixinclass Object public ::method length abstract ::method getNamedItem abstract @@ -252,17 +445,35 @@ ::method systemID abstract ::method internalSubset abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: Notation */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract notation definition ::class "Notation" mixinclass Node public ::method publicID abstract ::method systemID abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: ProcessingInstruction */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- abstract processinginstruction definition ::class "ProcessingInstruction" mixinclass Node public ::method data abstract ::method target abstract ::method "data=" abstract +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: UserDataHandler */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- interface class for implementing a user data handler ::class "UserDataHandler" public mixinclass object ::constant NODE_CLONED 1 @@ -274,6 +485,12 @@ -- called as handle(key, data, srcNode, destNode) ::method handle +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/* Class: DOMEventListener */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + -- interface class for implementing a DOM event handler ::class "DOMEventListener" public mixinclass object -- called as handleEvent(event) @@ -467,13 +684,6 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Section: Concrete implementation of the DOM classes */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ /* Class: QName -- a qualified XML name */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -508,6 +718,13 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Section: Concrete implementation of the DOM classes */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: NodeListImpl -- concrete NodeList class */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -662,34 +879,26 @@ end currentSize = self~nodes~items - if index < currentSize then do - return self~nodes[index + 1] - end + if index < currentSize then return self~nodes[index + 1] else do -- we need to continue the traversal from the last node added - if currentSize == 0 then do - thisNode = rootNode - end - else do - thisNode = self~nodes[currentSize] - end + if currentSize = 0 then thisNode = rootNode + else thisNode = self~nodes[currentSize] -- keep adding up to the one we're looking for - do while index > currentSize + loop while index > currentSize thisNode = self~nextMatchingElementAfter(thisNode) if thisNode \= .nil then do self~nodes~append(thisNode) currentSize += currentSize end - else do - -- no more nodes available - leave - end + else leave -- no more nodes available end -- this is either the one we want or .nil return thisNode end +-- get the length of the nodelist ::attribute length GET expose nodes use strict arg @@ -697,6 +906,7 @@ self~item(999999999) return self~nodes~items +-- loop over the entire list ::method makearray expose nodes use strict arg @@ -704,15 +914,14 @@ self~item(999999999) return self~nodes~copy +-- locate the next matching element after a starting node ::method nextMatchingElementAfter private expose rootNode tagName nsName use arg current - do while current \= .nil + loop while current \= .nil -- go down to the first child if it has one - if current~hasChildNodes then do - current = current~firstChild - end + if current~hasChildNodes then current = current~firstChild -- if not the root, then check for a sibling else if current \= rootNode, current~nextSibling \= .nil then do next = current~nextSibling @@ -726,9 +935,7 @@ current = current~parentNode next = current~nextSibling -- we have a next, so quit - if next \= .nil then do - leave - end + if next \= .nil then leave end -- this is either a good node, or .nil current = next @@ -737,29 +944,20 @@ if current \= rootNode, current \= .nil, current~nodeType == .Node~ELEMENT_NODE then do -- no namespace checking? We'll take any element node if the name is -- "*" or it matches directly - if nsName == .nil then do - if tagName == "*" | current~tagName == tagName then do - return current - end - end + if nsName == .nil then + if tagName == "*" | current~tagName == tagName then return current -- namespace qualified (which might also be "*") else do -- wildcard match on the tagname, so just check the namespace name if tagName == "*" then do -- wildcards on both, this is easy - if nsName == "*" then do - return current - end + if nsName == "*" then return current else do -- null string is a non-specific namepace request, which -- matches only if the element does not have a namespace - if nsName == "" & current~namespaceURI == .nil then do - return current - end + if nsName == "" & current~namespaceURI == .nil then return current -- requires an exact namespace match - else if nsName == current~namespaceURI then do - return current - end + else if nsName == current~namespaceURI then return current end end -- non-wild card on the name @@ -769,19 +967,13 @@ if current~localName == tagName then do -- ok, the local name matches, the ns rules are the -- same as above - if nsName == "*" then do - return current - end + if nsName == "*" then return current else do -- null string is a non-specific namepace request, which -- matches only if the element does not have a namespace - if nsName == "" & current~namespaceURI == .nil then do - return current - end + if nsName == "" & current~namespaceURI == .nil then return current -- requires an exact namespace match - else if nsName == current~namespaceURI then do - return current - end + else if nsName == current~namespaceURI then return current end end end @@ -1094,7 +1286,7 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: NamedNodeMap */ +/* Class: NamedNodeMapImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -1107,14 +1299,6 @@ changed = .false readonly = .false - -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/* Class: NamedNodeMapImpl */ -/* Private methods */ -/*----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ - -- find the index position for a given attribute ::method findItemPoint private expose attributes @@ -1198,48 +1382,33 @@ ::attribute changed ::attribute readonly - -/*----------------------------------------------------------------------------*/ -/* Method: getNamedItem */ -/* Description: get a named item. */ -/*----------------------------------------------------------------------------*/ - +-- get a named item ::method getNamedItem expose attributes use strict arg name if attributes == .nil then return .nil - do attribute over attributes + loop attribute over attributes if attribute~name == name then return attribute end return .nil - -/*----------------------------------------------------------------------------*/ -/* Method: getNamedItemNS */ -/* Description: get a named item by namespace */ -/*----------------------------------------------------------------------------*/ - +-- get a named item by namespace ::method getNamedItemNS expose attributes use strict arg namespace, name if attributes == .nil then return .nil - do attribute over attributes + loop attribute over attributes if attribute~localname == name & attribute~namespaceURI == namespace then return attribute end return .nil - -/*----------------------------------------------------------------------------*/ -/* Method: setNamedItem */ -/* Description: set a named item. */ -/*----------------------------------------------------------------------------*/ - +-- set a named item ::method setNamedItem expose attributes use strict arg node @@ -1259,11 +1428,7 @@ return previous -/*----------------------------------------------------------------------------*/ -/* Method: setNamedItemNS */ -/* Description: set a named item. */ -/*----------------------------------------------------------------------------*/ - +-- set a named item ::method setNamedItemNS expose attributes use strict arg node @@ -1291,11 +1456,7 @@ return previous -/*----------------------------------------------------------------------------*/ -/* Method: removeNamedItem */ -/* Description: remove a named item. */ -/*----------------------------------------------------------------------------*/ - +-- remove a named item ::method removeNamedItem expose attributes use strict arg name @@ -1309,12 +1470,7 @@ end return previous - -/*----------------------------------------------------------------------------*/ -/* Method: removeNamedItemNS */ -/* Description: remove a named item. */ -/*----------------------------------------------------------------------------*/ - +-- remove a named item ::method removeNamedItemNS expose attributes use strict arg namespace, name @@ -1328,20 +1484,14 @@ end return previous -/*----------------------------------------------------------------------------*/ -/* Method: cloneMap */ -/* Description: perform a deep copy of this map object */ -/*----------------------------------------------------------------------------*/ +-- perform a deep copy of this map object ::method cloneMap expose attributes use strict arg owner newMap = .NamedNodeMap(owner) newMap~cloneContent(attributes) -/*----------------------------------------------------------------------------*/ -/* Method: cloneContent */ -/* Description: initialize the content from another map */ -/*----------------------------------------------------------------------------*/ +-- initialize the content from another map ::method cloneContent expose attributes use arg source @@ -1353,12 +1503,7 @@ end end - -/*----------------------------------------------------------------------------*/ -/* Method: item */ -/* Description: return the named item. */ -/*----------------------------------------------------------------------------*/ - +-- return the named item ::method item expose attributes use strict arg position @@ -1366,11 +1511,7 @@ if attributes == .nil then return .nil else return attributes[position + 1] -/*----------------------------------------------------------------------------*/ -/* Method: length */ -/* Description: return the number of named items. */ -/*----------------------------------------------------------------------------*/ - +-- return the number of named items in the list ::method length expose attributes use strict arg @@ -1415,6 +1556,7 @@ end end +-- set a named item ::method setNamedItem use strict arg attribute -- replacing an attribute with itself does nothing @@ -1570,20 +1712,12 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: Node */ +/* Class: NodeImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ ::CLASS "NodeImpl" public inherit Node DOMEventTarget --- DocumentPosition indicators -::constant DOCUMENT_POSITION_DISCONNECTED 1 -::constant DOCUMENT_POSITION_PRECEDING 2 -::constant DOCUMENT_POSITION_FOLLOWING 4 -::constant DOCUMENT_POSITION_CONTAINS 8 -::constant DOCUMENT_POSITION_IS_CONTAINED 16 -::constant DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC 32 - -- initialize a counter to give new nodes a unique id ::method init class expose ctr @@ -1751,7 +1885,7 @@ -- just punt and return a disconnected indicator if these have -- different owners if thisOwner \= otherOwner then - return self~DOCUMENT_POSITION_DISCONNECTED + return .Node~DOCUMENT_POSITION_DISCONNECTED -- Find the ancestor of each node, and the distance each node is from -- its ancestor. @@ -1772,7 +1906,7 @@ -- we're a descendant of other...this is an easy test. Other precedes us -- and also contains us if node == other then - return self~DOCUMENT_POSITION_CONTAINS + DOCUMENT_POSITION_PRECEDING + return .Node~DOCUMENT_POSITION_CONTAINS + .Node~DOCUMENT_POSITION_PRECEDING thisAncestor = node node = node~parentNode @@ -1785,7 +1919,7 @@ -- we're a descendant of other...this is an easy test. Other follows us -- and also contains us if node == self then - return self~DOCUMENT_POSITION_CONTAINS + DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_CONTAINS + .Node~DOCUMENT_POSITION_FOLLOWING otherAncestor = node node = node~parentNode @@ -1805,30 +1939,30 @@ if thisAncestorType == .Node~NOTATION_NODE | thisAncestorType == .Node~ENTITY_NODE then do container = thisOwner~doctype if container = otherAncestor then - return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_PRECEDING + return .Node~DOCUMENT_POSITION_CONTAINS + .Node~DOCUMENT_POSITION_PRECEDING -- now look for the reverse relationship if otherAncestorType == .Node~NOTATION_NODE | otherAncestorType == .Node~ENTITY_NODE then do -- if the nodes are of different types, the order depends on the -- type number if thisAncestorType \= otherAncestorType then do if thisAncestorType > otherAncestorType then - return self~DOCUMENT_POSITION_PRECEDING - else return self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_PRECEDING + else return .Node~DOCUMENT_POSITION_FOLLOWING end else do -- this is either part of the doctype notations or entities, -- so query the appropriate list if thisAncestorType == .Node~NOTATION_NODE then do if container~notations~precedes(otherAncestor, thisAncestor) then - return self~DOCUMENT_POSITION_PRECEDING + return .Node~DOCUMENT_POSITION_PRECEDING else - return self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_FOLLOWING end else do if container~entities~precedes(otherAncestor, thisAncestor) then - return self~DOCUMENT_POSITION_PRECEDING + return .Node~DOCUMENT_POSITION_PRECEDING else - return self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_FOLLOWING end end end @@ -1836,9 +1970,9 @@ -- owned by a document type else if thisAncestorType == .Node~DOCUMENT_TYPE_NODE then do if otherNode == thisOwner then - return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_PRECEDING + return .Node~DOCUMENT_POSITION_CONTAINS + .Node~DOCUMENT_POSITION_PRECEDING else if thisOwner \== .nil & thisOwner == otherOwner then - return self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_FOLLOWING end -- an attribute else if thisAncestorType == .Node~ATTRIBUTE_NODE then do @@ -1849,8 +1983,8 @@ -- life is easy...just check the container if otherNode == thisNode then do if thisNode~attributes~precedes(other, this) then - return self~DOCUMENT_POSITION_PRECEDING - else return self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_PRECEDING + else return .Node~DOCUMENT_POSITION_FOLLOWING end -- owned by different elements...see if one element is an ancestor of @@ -1862,7 +1996,7 @@ -- the other node is an ancestor of the owning element, which -- means it precedes this one if node == otherNode then - return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_PRECEDING + return .Node~DOCUMENT_POSITION_CONTAINS + .Node~DOCUMENT_POSITION_PRECEDING thisAncestor = node node = node~parentNode end @@ -1873,16 +2007,16 @@ if otherAncestorType == .Node~NOTATION_NODE | otherAncestorType == .Node~ENTITY_NODE then do container = thisOwner~doctype if container = this then - return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_CONTAINS + .Node~DOCUMENT_POSITION_FOLLOWING otherNode = thisOwner otherAncestor = thisOwner end -- owned by a document type else if otherAncestorType == .Node~DOCUMENT_TYPE_NODE then do if thisNode == otherOwner then - return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_CONTAINS + .Node~DOCUMENT_POSITION_FOLLOWING else if otherOwner \== .nil & thisOwner == otherOwner then - return self~DOCUMENT_POSITION_PRECEDING + return .Node~DOCUMENT_POSITION_PRECEDING end -- an attribute. We already know they are not both attributes else if otherAncestorType == .Node~ATTRIBUTE_NODE then do @@ -1894,7 +2028,7 @@ -- the other node is an descendent of the reference node's element, which -- means it follows this one if node == otherNode then - return self~DOCUMENT_POSITION_CONTAINS + self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_CONTAINS + .Node~DOCUMENT_POSITION_FOLLOWING otherAncestor = node node = node~parentNode end @@ -1903,7 +2037,7 @@ -- thisAncestor and otherAncestor must be the same at this point, -- otherwise, the original nodes are disconnected if thisAncestor \= otherAncestor then do - return self~DOCUMENT_POSITION_DISCONNECTED + return .Node~DOCUMENT_POSITION_DISCONNECTED end -- Go up the parent chain of the deeper node, until we find a node @@ -1916,7 +2050,7 @@ -- happen in the case of attributes. In this case, otherNode -- "precedes" this. if thisNode == otherNode then - return self~DOCUMENT_POSITION_PRECEDING; + return .Node~DOCUMENT_POSITION_PRECEDING; end -- moving up the way else do @@ -1927,7 +2061,7 @@ -- happen in the case of attributes. In this case, otherNode -- "follow" this. if thisNode == otherNode then - return self~DOCUMENT_POSITION_PRECEDING; + return .Node~DOCUMENT_POSITION_PRECEDING; end -- We now have nodes at the same depth in the tree. Find a common -- ancestor. @@ -1947,15 +2081,15 @@ current = thisNodeParent~firstChild loop while current \= .nil if current == otherNode then - return self~DOCUMENT_POSITION_PRECEDING + return .Node~DOCUMENT_POSITION_PRECEDING else if current == thisNode then - return self~DOCUMENT_POSITION_FOLLOWING + return .Node~DOCUMENT_POSITION_FOLLOWING current = current~nextSibling end -- should never get here...throw up our hands and -- say they are disconnected. - return self~DOCUMENT_POSITION_DISCONNECTED + return .Node~DOCUMENT_POSITION_DISCONNECTED -- get the default text content for a node. This is -- the same as the nodevalue for many node types This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-11 21:55:19
|
Revision: 8038 http://oorexx.svn.sourceforge.net/oorexx/?rev=8038&view=rev Author: bigrixx Date: 2012-07-11 21:55:13 +0000 (Wed, 11 Jul 2012) Log Message: ----------- fix bug in last update Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-11 21:38:29 UTC (rev 8037) +++ incubator/orxutils/xml/xmldom.cls 2012-07-11 21:55:13 UTC (rev 8038) @@ -42,8 +42,6 @@ -- initial tables .XPathToken~setup -::options trace c - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Section: Abstract DOM interface class definitions */ @@ -944,8 +942,9 @@ if current \= rootNode, current \= .nil, current~nodeType == .Node~ELEMENT_NODE then do -- no namespace checking? We'll take any element node if the name is -- "*" or it matches directly - if nsName == .nil then + if nsName == .nil then do if tagName == "*" | current~tagName == tagName then return current + end -- namespace qualified (which might also be "*") else do -- wildcard match on the tagname, so just check the namespace name This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-11 23:56:19
|
Revision: 8039 http://oorexx.svn.sourceforge.net/oorexx/?rev=8039&view=rev Author: bigrixx Date: 2012-07-11 23:56:13 +0000 (Wed, 11 Jul 2012) Log Message: ----------- rework the error handling to more closely mimic the DOM exception model Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-11 21:55:13 UTC (rev 8038) +++ incubator/orxutils/xml/xmldom.cls 2012-07-11 23:56:13 UTC (rev 8039) @@ -69,7 +69,6 @@ /*----------------------------------------------------------------------------*/ ::method length abstract - -- some compatibility methods to make nodelist feel like a Rexx collection ::method makearray abstract ::method "[]" @@ -1808,7 +1807,7 @@ return .nil ::attribute prefix SET -- this is an error by default - .DomErrors~raiseError(.DomException~NAMESPACE_ERR) + .DomException~raiseError(.DomException~NAMESPACE_ERR) -- for node types that don't support a real localname, -- this is the same as nodeName ::attribute localName GET @@ -1847,17 +1846,17 @@ ::method insertBefore use strict arg newChild, refChild -- not implemented in the base node - .DomErrors~raiseError(.DomException~Hierarchy_request_err) + .DomException~raiseError(.DomException~Hierarchy_request_err) ::method replaceChild use strict arg newChild, oldChild -- not implemented in the base node - .DomErrors~raiseError(.DomException~Hierarchy_request_err) + .DomException~raiseError(.DomException~Hierarchy_request_err) ::method removeChild use strict arg oldChild -- not implemented in the base node - .DomErrors~raiseError(.DomException~Not_found_err) + .DomException~raiseError(.DomException~Not_found_err) ::method appendChild use strict arg newChild @@ -1871,7 +1870,7 @@ -- this must be from the same dom type if other \== .nil, \other~isa(.NodeImpl) then - .DomErrors~raiseError(.DomException~Not_supported_err) + .DomException~raiseError(.DomException~Not_supported_err) -- get the owners of the two nodes if self~nodeType == .Node~DOCUMENT_NODE then @@ -2959,7 +2958,7 @@ use strict arg type if type~caselessEquals("Event") then return .DOMEvent~new else if type~caselessEquals("MutationEvent") then return .DOMMutationEvent~new - else .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) + else .DomException~raiseError(.DomException~NOT_SUPPORTED_ERR) -- flag to indicate if there are any mutation event listeners in use. -- provides an optimization for the normal case of no listeners. @@ -5196,14 +5195,14 @@ use strict arg qname if \.XMLChar~isValidQName(qname) then - .DomErrors~raiseError(.DomException~INVALID_CHARACTER_ERR) + .DomException~raiseError(.DomException~INVALID_CHARACTER_ERR) -- create a document node ::method createDocument use strict arg namespaceURI = .nil, qualifiedName = .nil, doctype = .nil if doctype \= .nil, doctype~ownerDocument \= .nil then - .DomErrors~raiseError(.DomException~WRONG_DOCUMENT_ERR) + .DomException~raiseError(.DomException~WRONG_DOCUMENT_ERR) doc = .CoreDocument~new(doctype) @@ -5229,11 +5228,59 @@ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: BaseDOMException */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +-- this is the base framework for DOM exception classes. This class does not define +-- and message codes or error messages, but creates the base infrastructure +::class "BaseDomException" public + +-- the message table used by the class instance. This will be set with different +-- values by each sub class +::attribute messageTable class get + expose messageTable + -- deferred setup of the message table until first request + if messageTable == .nil then + messageTable = self~setupMessages + return messageTable + +-- class to initialize the message table to empty +::method init class + expose messageTable + messageTable = .nil + +-- dummy method intended to be overridden by subclasses to provide their own messages +::method setupMessages class + return .array~new + +-- raise an error using the error numbers for the particular exception +::method raiseError class + use arg code + + exception = self~new(code, self~messageTable[code]) + -- this generates both the formatted error message and attaches the + -- exception object to the condition object + raise syntax 98.900 array(exception~string, exception) + + +-- instance item for DOM errors. This is attached to the condition information +::method init + expose code message + use strict arg code, message + +-- string method to display the message value +::method string + expose code message + return self~class~id "error" code":" message + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: DOMException */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -::class "DOMException" public +::class "DOMException" public subclass BaseDomException ::constant INDEX_SIZE_ERR 1 ::constant DOMSTRING_SIZE_ERR 2 ::constant HIERARCHY_REQUEST_ERR 3 @@ -5251,57 +5298,48 @@ ::constant INVALID_ACCESS_ERR 15 ::constant VALIDATION_ERR 16 ::constant TYPE_MISMATCH_ERR 17 -::constant BAD_BOUNDARYPOINTS_ERR 18 -::constant INVALID_NODE_TYPE_ERR 19 --- instance item for DOM errors. This is attached to the condition information -::method init - expose code message - use strict arg code, message +-- this needs to be overridden in each class to set up the tables +::method setupMessages class + messageTable = .array~new + messageTable[self~HIERARCHY_REQUEST_ERR] = "An attempt was made to insert a node where it is not permitted." + messageTable[self~INDEX_SIZE_ERR] = "The index or size is negative, or greater than the allowed value." + messageTable[self~INUSE_ATTRIBUTE_ERR] = "An attempt is made to add an attribute that is already in use elsewhere." + messageTable[self~INVALID_ACCESS_ERR] = "A parameter or an operation is not supported by the underlying object." + messageTable[self~INVALID_CHARACTER_ERR] = "An invalid or illegal XML character is specified." + messageTable[self~INVALID_MODIFICATION_ERR] = "An attempt is made to modify the type of the underlying object." + messageTable[self~INVALID_STATE_ERR] = "An attempt is made to use an object that is not, or is no longer, usable." + messageTable[self~NAMESPACE_ERR] = "An attempt is made to create or change an object in a way which is incorrect with regard to namespaces." + messageTable[self~NOT_FOUND_ERR] = "An attempt is made to reference a node in a context where it does not exist." + messageTable[self~NOT_SUPPORTED_ERR] = "The implementation does not support the requested type of object or operation." + messageTable[self~NO_DATA_ALLOWED_ERR] = "Data is specified for a node which does not support data." + messageTable[self~NO_MODIFICATION_ALLOWED_ERR] = "An attempt is made to modify an object where modifications are not allowed." + messageTable[self~SYNTAX_ERR] = "An invalid or illegal string is specified." + messageTable[self~VALIDATION_ERR] = "A call to a method such as insertBefore or removeChild would make the Node invalid with respect to document grammar." + messageTable[self~WRONG_DOCUMENT_ERR] = "A node is used in a different document than the one that created it." + messageTable[self~TYPE_MISMATCH_ERR] = "The value type for this parameter name is incompatible with the expected value type." -::method string - expose code message - return "DOM Error" code":" message + return messageTable /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ -/* Class: DOMErrors */ +/* Class: RangeException */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +::class "RangeException" public subclass BaseDomException +::constant BAD_BOUNDARYPOINTS_ERR 1 +::constant INVALID_NODE_TYPE_ERR 2 --- central class for raising DOMException events. -::class "DOMErrors" public subclass DomException -::method init class - expose messageTable +-- setup messages. Designed to be overridden by subclass exception types +::method setupMessages class messageTable = .array~new - messageTable[.DomException~HIERARCHY_REQUEST_ERR] = "An attempt was made to insert a node where it is not permitted." - messageTable[.DomException~INDEX_SIZE_ERR] = "The index or size is negative, or greater than the allowed value." - messageTable[.DomException~INUSE_ATTRIBUTE_ERR] = "An attempt is made to add an attribute that is already in use elsewhere." - messageTable[.DomException~INVALID_ACCESS_ERR] = "A parameter or an operation is not supported by the underlying object." - messageTable[.DomException~INVALID_CHARACTER_ERR] = "An invalid or illegal XML character is specified." - messageTable[.DomException~INVALID_MODIFICATION_ERR] = "An attempt is made to modify the type of the underlying object." - messageTable[.DomException~INVALID_STATE_ERR] = "An attempt is made to use an object that is not, or is no longer, usable." - messageTable[.DomException~NAMESPACE_ERR] = "An attempt is made to create or change an object in a way which is incorrect with regard to namespaces." - messageTable[.DomException~NOT_FOUND_ERR] = "An attempt is made to reference a node in a context where it does not exist." - messageTable[.DomException~NOT_SUPPORTED_ERR] = "The implementation does not support the requested type of object or operation." - messageTable[.DomException~NO_DATA_ALLOWED_ERR] = "Data is specified for a node which does not support data." - messageTable[.DomException~NO_MODIFICATION_ALLOWED_ERR] = "An attempt is made to modify an object where modifications are not allowed." - messageTable[.DomException~SYNTAX_ERR] = "An invalid or illegal string is specified." - messageTable[.DomException~VALIDATION_ERR] = "A call to a method such as insertBefore or removeChild would make the Node invalid with respect to document grammar." - messageTable[.DomException~WRONG_DOCUMENT_ERR] = "A node is used in a different document than the one that created it." - messageTable[.DomException~TYPE_MISMATCH_ERR] = "The value type for this parameter name is incompatible with the expected value type." - messageTable[.DomException~BAD_BOUNDARYPOINTS_ERR] = "The boundary-points of a Range do not meet specific requirements." - messageTable[.DomException~INVALID_NODE_TYPE_ERR] = "The container of a boundary-point of a Range is being set to either a node of an invalid type or a node with an ancestor of an invalid type." + messageTable[self~BAD_BOUNDARYPOINTS_ERR] = "The boundary-points of a Range do not meet specific requirements." + messageTable[self~INVALID_NODE_TYPE_ERR] = "The container of a boundary-point of a Range is being set to either a node of an invalid type or a node with an ancestor of an invalid type." --- raise an error using the DOMException error numbers -::method raiseError class - expose messageTable - use arg code + return messageTable - raise syntax 98.900 array(.DOMException~new(code, messageTable[code])) -- just raise this as a user execution error - /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: DOMEvent */ @@ -6547,7 +6585,7 @@ ::method checkIndex private use strict arg refNode, offset - if offset < 0 then .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) + if offset < 0 then .DomException~raiseError(.DomException~INDEX_SIZE_ERR) type= refNode~nodeType @@ -6555,11 +6593,11 @@ if nodeType == .Node~TEXT_NODE | nodeType == .Node~CDATA_SECTION_NODE | - nodeType == .Node~COMMENT_NODE | nodeType == .Node~PROCESSING_INSTRUCTION_NODE then do if offset > refNode~nodeValue~length then - .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) + .DomException~raiseError(.DomException~INDEX_SIZE_ERR) end -- must lie with the range of children for the node else if offset > refNode~childNodes~length then - .DOMErrors~raiseError(.DomException~INDEX_SIZE_ERR) + .DomException~raiseError(.DomException~INDEX_SIZE_ERR) -- check the start and end positions and determine if the range -- needs to be collapsed @@ -7355,10 +7393,10 @@ newNode~systemId = source~systemId end when type == .Node~DOCUMENT_NODE then do - .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) + .DomException~raiseError(.DomException~NOT_SUPPORTED_ERR) end otherwise do - .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) + .DomException~raiseError(.DomException~NOT_SUPPORTED_ERR) end end @@ -7401,10 +7439,10 @@ source~ownerDocument = self end when type == .Node~ENTITY_NODE | type == .Node~NOTATION_NODE then do - .DomErrors~raiseError(.DomException~NO_MODIFICATION_ALLOWED_ERR) + .DomException~raiseError(.DomException~NO_MODIFICATION_ALLOWED_ERR) end when type == .Node~DOCUMENT_NODE | type == .Node~DOCUMENT_TYPE_NODE then do - .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) + .DomException~raiseError(.DomException~NOT_SUPPORTED_ERR) end when type == .Node~ENTITY_REFERENCE_NODE then do parent = source~parentNode @@ -7476,7 +7514,7 @@ self~renamedAttrNode(node, nodeName) end else - .DomErrors~raiseError(.DomException~NOT_SUPPORTED_ERR) + .DomException~raiseError(.DomException~NOT_SUPPORTED_ERR) -- clear our identifiers table ::method clearIdentifiers private This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <bi...@us...> - 2012-07-12 00:55:16
|
Revision: 8040 http://oorexx.svn.sourceforge.net/oorexx/?rev=8040&view=rev Author: bigrixx Date: 2012-07-12 00:55:10 +0000 (Thu, 12 Jul 2012) Log Message: ----------- rework the event classes for DOM level 3 additions Modified Paths: -------------- incubator/orxutils/xml/xmldom.cls Modified: incubator/orxutils/xml/xmldom.cls =================================================================== --- incubator/orxutils/xml/xmldom.cls 2012-07-11 23:56:13 UTC (rev 8039) +++ incubator/orxutils/xml/xmldom.cls 2012-07-12 00:55:10 UTC (rev 8040) @@ -230,6 +230,7 @@ ::method hasChildNodes abstract ::method insertBefore abstract ::method isSupported abstract +::method getFeature abstract ::method normalize abstract ::method removeChild abstract ::method replaceChild abstract @@ -1839,10 +1840,21 @@ return newNode +-- test if this node supports a given feature. The owner document +-- implementation really determines this ::method isSupported use strict arg feature, version - return .false + return self~ownerDocument~implementation~hasFeature(feature, version) +-- return an instance of an object that implements a named feature. +-- for use, this just means return the same node since the base +-- node supports all of the features directly +::method getFeature + use strict arg feature, version + + if self~isFeature(feature, version) then return self + return .nil + ::method insertBefore use strict arg newChild, refChild -- not implemented in the base node @@ -2192,10 +2204,6 @@ if \thisChildren~item(i)~isEqualNode(otherChildren~item(i)) then return .false end -::method getFeature - use strict arg feature, version - return .nil - -- associate an object to a key on this node. ::method setUserData use strict arg key, data, handler @@ -2958,6 +2966,7 @@ use strict arg type if type~caselessEquals("Event") then return .DOMEvent~new else if type~caselessEquals("MutationEvent") then return .DOMMutationEvent~new + else if type~caselessEquals("MutationNameEvent") then return .DOMMutationNameEvent~new else .DomException~raiseError(.DomException~NOT_SUPPORTED_ERR) -- flag to indicate if there are any mutation event listeners in use. @@ -3126,7 +3135,7 @@ -- check the capture descriptors. If there are no active listeners -- for this event type, then we don't dispatch this capture = self~lookupCapture(event~type) - if capture~total == 0 then return event~defaultPrevented + if capture~total == 0 then return event~isDefaultPrevented -- initialize the events dispatch status event~target = node @@ -5148,42 +5157,78 @@ expose singleton singleton = .nil +-- get the singleton instance for this dom ::attribute implementation GET class expose singleton use strict arg - if singleton == .nil then do + + -- create the singleton if this is the first call + if singleton == .nil then singleton = self~new - end - return singleton +-- indicate what features we support ::method hasFeature use strict arg feature, version = .nil anyVersion = version == .nil | version == "" + -- remove the plus here...we don't consider this here + if feature~subchar(1) == '+' then feature = feature~substr(2) feature = feature~upper select when feature = "CORE" then do - return anyVersion | version == 1.0 | verison == 2.0 | version == 3.0 + return anyVersion | version == "1.0" | verison == "2.0" | version == "3.0" end when feature = "XML" then do - return anyVersion | version == 1.0 | verison == 2.0 | version == 3.0 + return anyVersion | version == "1.0" | verison == "2.0" | version == "3.0" end when feature = "XMLVERSION" then do - return anyVersion | version == 1.0 | verison == 1.1 + return anyVersion | version == "1.0" | verison == "1.1" end - when feature = "LS" then do - return anyVersion | version == 3.0 - end +-- not yet +-- when feature = "LS" then do +-- return anyVersion | version == "3.0" +-- end when feature = "XPATH" then do - return anyVersion | version == 3.0 + return anyVersion | version == "3.0" end + when feature == "EVENTS" then do + return anyVersion | version == "3.0" + end + when feature == "MUTATIONEVENTS" then do + return anyVersion | version == "3.0" + end +-- still to be done +-- when feature == "MUTATIONNAMEEVENTS" then do +-- return anyVersion | version == "3.0" +-- end + when feature == "TRAVERSAL" then do + return anyVersion | version == "3.0" + end + when feature == "RANGE" then do + return anyVersion | version == "3.0" + end + when feature == "ELEMENTTRAVERSAL" then do + return anyVersion | version == "3.0" + end + when feature == "RANGE" then do + return anyVersion | version == "3.0" + end + otherwise do return .false end end +-- return an instance of an object that implements a named feature. +-- for use, this just means return the singleton instance +::method getFeature + use strict arg feature, version + + if self~hasFeature(feature, version) then return self + return .nil + -- create a document type value ::method createDocumentType use strict arg qualifiedName, publicID, systemID @@ -5213,18 +5258,7 @@ return doc -::method getFeature - singleton = self~class~DOMImplementation - if singleton~hasFeature(feature, version) then do - if feature~upper = "XPATH" then do - return .XPathEvaluator~new - end - else do - return singleton - end - end - return .nil /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ @@ -5352,7 +5386,8 @@ ::constant BUBBLING_PHASE 3 ::method init - expose type initialized cancelable target eventPhase currentTarget timeStamp propagationStopped defaultPrevented isTrusted immediatePropagationStopped + expose type initialized cancelable target eventPhase currentTarget timeStamp - + propagationStopped defaultPrevented isTrusted immediatePropagationStopped namespaceURI type = .nil initialized = .false currentTarget = .nil @@ -5363,12 +5398,20 @@ cancelable = .false isTrusted = .false -- spec requires this initially be false immediatePropagationStopped = .false + namespaceURI = .nil +-- initialize the event ::method initEvent expose type bubbles cancelable initialized use strict arg type, bubbles, cancelable initialized = .true +-- initialize the event +::method initEventNS + expose namespaceURI + use strict arg namespaceURI, type, bubbles, cancelable + self~initEvent(type, bubbles, cancelable) + ::attribute bubbles GET ::attribute cancelable GET ::attribute currentTarget GET @@ -5376,9 +5419,20 @@ ::attribute target GET ::attribute type GET ::attribute timeStamp GET -::attribute defaultPrevented -::attribute propagationStopped +::attribute isDefaultPrevented GET + expose defaultPrevented + return defaultPrevented +::attribute isPropagationStopped GET + expose propagationStopped + return propagationStopped +::attribute isImmediatePropagationStopped GET + expose immediatePropagationStopped + return immediatePropagationStopped ::attribute isTrusted GET +::attribute namespaceURI GET +-- no custom events supported +::attribute isCustum GET + return .false ::method preventDefault expose defaultPrevented @@ -5395,6 +5449,10 @@ use strict arg immediatePropagationStopped = .true +-- internal attributes +::attribute defaultPrevented +::attribute propagationStopped + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Class: DOMMutationEvent */ @@ -5435,8 +5493,46 @@ use strict arg type, bubble, cancelable, relatedNode, prevValue, newValue, attrName, attrChange self~initEvent(type, canBubble, cancelable) +::method initMutationEventNS + expose relatedNode prevValue newValue attrName attrChange + use strict arg namespaceURI, type, bubble, cancelable, relatedNode, prevValue, newValue, attrName, attrChange + self~initEvent(type, canBubble, cancelable) + /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ +/* Class: DOMMutationNameEvent */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ + +::class "DOMMutationNameEvent" subclass DOMMutationEvent public +::constant DOM_ATTR_NAME_CHANGED "DOMAttrNameChanged" +::constant DOM_ELEMENT_NAME_CHANGED "DOMElementNameChanged" + +::method init + expose relatedNode prevValue newValue attrName + self~init:super + relatedNode = .nil + prevValue = .nil + newValue = .nil + attrName = .nil + +::attribute prevNamespaceURI GET +::attribute prevNodeName GET + +-- initialized the mutation name event +::method initMutationNameEvent + expose prevNamespaceURI prevNodeName + use strict arg type, bubble, cancelable, relatedNode, prevNamespaceURI, prevNodeName + self~initMutationEvent(type, canBubble, cancelable, relatedNode, .nil, .nil, .nil, .nil) + +-- initialized the mutation name event +::method initMutationNameEventNS + expose prevNamespaceURI prevNodeName + use strict arg namespaceURI, type, bubble, cancelable, relatedNode, prevNamespaceURI, prevNodeName + self~initMutationEventNS(namespaceURI, type, canBubble, cancelable, relatedNode, .nil, .nil, .nil, .nil) + +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ /* Class: NodeIteratorImpl */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |