This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a commit to branch improvements/Language
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit 722f16599441be4fd0243d6fe9f2cd856f1a6b0b
Author: greg-dove <[email protected]>
AuthorDate: Wed May 15 10:54:34 2019 +1200

    Numerous updates to XML/XMLList to address issues identified during testing
---
 frameworks/projects/XML/src/main/royale/XML.as     | 258 ++++++++++++++-------
 frameworks/projects/XML/src/main/royale/XMLList.as |  43 +++-
 2 files changed, 206 insertions(+), 95 deletions(-)

diff --git a/frameworks/projects/XML/src/main/royale/XML.as 
b/frameworks/projects/XML/src/main/royale/XML.as
index e6ea42e..01229c2 100644
--- a/frameworks/projects/XML/src/main/royale/XML.as
+++ b/frameworks/projects/XML/src/main/royale/XML.as
@@ -19,6 +19,9 @@
 package
 {
        COMPILE::JS
+       /**
+        * @royaleignorepublicvarwarning
+        */
        public class XML
        {
                import org.apache.royale.debugging.assert;
@@ -127,7 +130,6 @@ package
                
                static private function 
escapeAttributeValue(value:String):String
                {
-                       var outArr:Array = [];
                        var arr:Array = String(value).split("");
                        var len:int = arr.length;
                        for(var i:int=0;i<len;i++)
@@ -135,61 +137,55 @@ package
                                switch(arr[i])
                                {
                                        case "<":
-                                               outArr[i] = "&lt;";
+                                               arr[i] = "&lt;";
                                                break;
                                        case "&":
-                                               if(arr[i+1] == "#")
-                                                       outArr[i] = "&";
-                                               else
-                                                       outArr[i] = "&amp;";
+                                               if(arr[i+1] != "#")
+                                                       arr[i] = "&amp;";
                                                break;
                                        case '"':
-                                               outArr[i] = "&quot;";
+                                               arr[i] = "&quot;";
                                                break;
                                        case "\u000A":
-                                               outArr[i] = "&#xA;";
+                                               arr[i] = "&#xA;";
                                                break;
                                        case "\u000D":
-                                               outArr[i] = "&#xD;";
+                                               arr[i] = "&#xD;";
                                                break;
                                        case "\u0009":
-                                               outArr[i] = "&#x9;";
+                                               arr[i] = "&#x9;";
                                                break;
                                        default:
-                                               outArr[i] = arr[i];
                                                break;
                                }
                        }
-                       return outArr.join("");
+                       return arr.join("");
                }
 
                static private function escapeElementValue(value:String):String
                {
                        var i:int;
-                       var outArr:Array = [];
                        var arr:Array = value.split("");
-                       for(i=0;i<arr.length;i++)
+                       const len:uint = arr.length;
+                       for(i=0;i<len;i++)
                        {
                                switch(arr[i])
                                {
                                        case "<":
-                                               outArr[i] = "&lt;";
+                                               arr[i] = "&lt;";
                                                break;
                                        case ">":
-                                               outArr[i] = "&gt;";
+                                               arr[i] = "&gt;";
                                                break;
                                        case "&":
-                                               if(arr[i+1] == "#")
-                                                       outArr[i] = "&";
-                                               else
-                                                       outArr[i] = "&amp;";
+                                               if(arr[i+1] != "#")
+                                                       arr[i] = "&amp;";
                                                break;
                                        default:
-                                               outArr[i] = arr[i];
                                                break;
                                }
                        }
-                       return outArr.join("");
+                       return arr.join("");
                }
 
                static private function insertAttribute(att:Attr,parent:XML):XML
@@ -208,9 +204,15 @@ package
                        // add attributes
                        var attrs:* = node.attributes;
                        var len:int = node.attributes.length;
+                       
                        for(i=0;i<len;i++)
                        {
-                               insertAttribute(attrs[i],xml);
+                               var att:Attr = attrs[i];
+                               if (att.prefix == 'xmlns' && att.namespaceURI 
== 'http://www.w3.org/2000/xmlns/') {
+                                       //from e4x spec: NOTE Although 
namespaces are declared using attribute syntax in XML, they are not represented 
in the [[Attributes]] property.
+                                       xml.addNamespace(new 
Namespace(att.localName, att.nodeValue));
+                               }
+                               else insertAttribute(att,xml);
                        }
                        // loop through childNodes which will be one of:
                        // text, cdata, processing instrution or comment and 
add them as children of the element
@@ -218,18 +220,24 @@ package
                        len = childNodes.length;
                        for(i=0;i<len;i++)
                        {
-                               var child:XML = fromNode(childNodes[i]);
-                               xml.addChildInternal(child);
+                               var nativeNode:Node = childNodes[i];
+                               if (nativeNode.nodeType == 7 && 
XML.ignoreProcessingInstructions) {
+                                       continue;
+                               }
+                               var child:XML = fromNode(nativeNode);
+                               if (child)
+                                       xml.addChildInternal(child);
                        }
                }
                /**
                * returns an XML object from an existing node without the need 
to parse the XML.
                * The new XML object is not normalized
+               *
+               * @royaleignorecoercion Element
                */
-               static private function fromNode(node:Element):XML
+               static private function fromNode(node:Node):XML
                {
                        var xml:XML;
-                       var i:int;
                        var data:* = node.nodeValue;
                        var localName:String = node.nodeName;
                        var prefix:String = node.prefix;
@@ -245,22 +253,24 @@ package
                                        xml = new XML();
                                        xml.setNodeKind("element");
                                        xml.setName(qname);
-                                       iterateElement(node,xml);
+                                       iterateElement(node as Element,xml);
                                        break;
                                //case 2:break;// ATTRIBUTE_NODE (handled 
separately)
                                case 3:
                                        //TEXT_NODE
+                                       if (XML.ignoreWhitespace) {
+                                               data = data.trim();
+                                               if (!data) return null;
+                                       }
                                        xml = new XML();
                                        xml.setNodeKind("text");
-                                       xml.setName(qname);
-                                       if(XML.ignoreWhitespace)
-                                               data = data.trim();
+                                       //xml.setName(qname); e4X: the name 
must be null (text node rules)
                                        xml.setValue(data);
                                        break;
                                case 4:
                                        //CDATA_SECTION_NODE
                                        xml = new XML();
-                                       xml.setName(qname);
+                                       //xml.setName(qname); e4X: the name 
must be null (text node rules)
                                        xml.setNodeKind("text");
                                        data = "<![CDATA[" + data + "]]>";
                                        xml.setValue(data);
@@ -276,8 +286,10 @@ package
                                        break;
                                case 8:
                                        //COMMENT_NODE
+                                       
                                        xml = new XML();
                                        xml.setNodeKind("comment");
+                                       //e4X: the name must be null (comment 
node rules)
                                        xml.setValue(data);
                                        break;
                                //case 9:break;//DOCUMENT_NODE
@@ -398,7 +410,7 @@ package
                        // _children = [];
                        if(xml)
                        {
-                               var xmlStr:String = "" + xml;
+                               var xmlStr:String = ignoreWhitespace ? 
trimXMLWhitespace("" + xml) : "" + xml;
                                if(xmlStr.indexOf("<") == -1)
                                {
                                        _nodeKind = "text";
@@ -418,11 +430,15 @@ package
                                        configurable: true
                                }
                        );
-                       
                }
                private static var xmlRegEx:RegExp = /&(?![\w]+;)/g;
                private static var parser:DOMParser;
                private static var errorNS:String;
+               
+               /**
+                *
+                * @royaleignorecoercion Element
+                */
                private function parseXMLStr(xml:String):void
                {
                        //escape ampersands
@@ -440,6 +456,10 @@ package
                                        errorNS = "na";
                                }
                        }
+                       //various node types not supported directly
+                       //maybe it should always wrap (e4x seems to say yes on 
p34, 'Semantics' of e4x-Ecma-357.pdf)
+                       var wrap:Boolean = (xml.indexOf('<?') == 0 && 
xml.indexOf('<?xml ') != 0) || (xml.indexOf('<![CDATA[') == 0) || 
(xml.indexOf('<!--') == 0);
+                       if (wrap) xml = '<parseRoot>'+xml+'</parseRoot>';
                        try
                        {
                                var doc:Document = parser.parseFromString(xml, 
"application/xml");
@@ -453,9 +473,10 @@ package
                        var errorNodes:NodeList = 
doc.getElementsByTagNameNS(errorNS, 'parsererror');
                        if(errorNodes.length > 0)
                                throw new Error(errorNodes[0].innerHTML);
+                       if (wrap) doc = doc.childNodes[0];
                        for(var i:int=0;i<doc.childNodes.length;i++)
                        {
-                               var node:Element = doc.childNodes[i];
+                               var node:Node = doc.childNodes[i];
                                if(node.nodeType == 1)
                                {
                                        _version = doc.xmlVersion;
@@ -465,16 +486,52 @@ package
                                        // _name.prefix = node.prefix;
                                        // _name.uri = node.namespaceURI;
                                        // _name.localName = node.localName;
-                                       iterateElement(node,this);
+                                       iterateElement(node as Element,this);
                                }
                                else
                                {
+                                       if (node.nodeType == 7) {
+                                               if 
(XML.ignoreProcessingInstructions) {
+                                                       
this.setNodeKind('text');
+                                                       //e4x: The value of the 
[[Name]] property is null if and only if the XML object represents an XML 
comment or text node
+                                                       _name = null;
+                                                       this.setValue('');
+                                               } else {
+                                                       
this.setNodeKind('processing-instruction');
+                                                       
this.setName(node.nodeName);
+                                                       
this.setValue(node.nodeValue);
+                                               }
+                                               
+                                       } else if (node.nodeType == 4) {
+                                               this.setNodeKind('text');
+                                               //e4x: The value of the 
[[Name]] property is null if and only if the XML object represents an XML 
comment or text node
+                                               _name = null;
+                                               if (node.nodeName == 
'#cdata-section') {
+                                                       
this.setValue('<![CDATA[' + node.nodeValue + ']]>');
+                                               } else {
+                                                       
this.setValue(node.nodeValue);
+                                               }
+                                       } else if (node.nodeType == 8) {
+                                               //e4x: The value of the 
[[Name]] property is null if and only if the XML object represents an XML 
comment or text node
+                                               _name = null;
+                                               if (XML.ignoreComments) {
+                                                       
this.setNodeKind('text');
+                                                       this.setValue('');
+                                               } else {
+                                                       
this.setNodeKind('comment');
+                                                       
this.setValue(node.nodeValue);
+                                               }
+                                               
+                                               
+                                       }
+
                                        // Do we record the nodes which are 
probably processing instructions?
 //                                             var child:XML = 
XML.fromNode(node);
 //                                             addChild(child);
                                }
                        }
-                       normalize();
+                       //normalize seems wrong here:
+                       //normalize();
                //need to deal with errors 
https://bugzilla.mozilla.org/show_bug.cgi?id=45566
                // get rid of nodes we do not want
                //loop through the child nodes and build XML obejcts for each.
@@ -499,8 +556,6 @@ package
                        
                        return _namespaces;
                }
-               private var _origStr:String;
-
 
                /**
                 * @private
@@ -614,34 +669,38 @@ package
                 * @param child
                 * @return
                 *
+                * @royaleignorecoercion XML
+                *
                 */
                public function appendChild(child:*):XML
                {
                        /*
-                               [[Insert]] (P, V)
-                               1. If x.[[Class]] ∈ {"text", "comment", 
"processing-instruction", "attribute"}, return
-                               2. Let i = ToUint32(P)
-                               3. If (ToString(i) is not equal to P), throw a 
TypeError exception
-                               4. If Type(V) is XML and (V is x or an ancestor 
of x) throw an Error exception
-                               5. Let n = 1
-                               6. If Type(V) is XMLList, let n = V.[[Length]]
-                               7. If n == 0, Return
-                               8. For j = x.[[Length]]-1 downto i, rename 
property ToString(j) of x to ToString(j + n)
-                               9. Let x.[[Length]] = x.[[Length]] + n
-                               10. If Type(V) is XMLList
-                                 a. For j = 0 to V.[[Length-1]]
-                                   i. V[j].[[Parent]] = x
-                                   ii. x[i + j] = V[j]
-                               11. Else
-                                 a. Call the [[Replace]] method of x with 
arguments i and V
-                               12. Return
+                       1. Let children be the result of calling the [[Get]] 
method of x with argument "*"
+                       2. Call the [[Put]] method of children with arguments 
children.[[Length]] and child
+                       3. Return x
+               
                        */
                        var childType:String = typeof child;
-                       if(childType != "object")
-                               child = xmlFromStringable(child);
+                       
+                       if(childType != "object") {
+                var last:uint = childrenLength();
+                               const lastChild:XML = last ? _children[last-1] 
: null;
+                               if (lastChild && lastChild.nodeKind() == 
'element') {
+                                       
+                                       const wrapper:XML = new XML();
+                                       child = new XML(child.toString());
+                                       wrapper.setName(lastChild.name());
+                    child.setParent(wrapper);
+                    wrapper.getChildren().push(child);
+                                       child = wrapper;
+                               } else {
+                    child = xmlFromStringable(child);
+                               }
+                       }
                        
                        appendChildInternal(child);
-                       normalize();
+                       //normalize seems not correct here:
+                       //normalize();
                        return this;
                }
                
@@ -1405,7 +1464,7 @@ package
                 */
                public function localName():String
                {
-                       return name().localName;
+                       return _name? _name.localName : null;
                }
 
                private var _name:QName;
@@ -1418,8 +1477,8 @@ package
                 */
                public function name():QName
                {
-                       if(!_name)
-                               _name = getQName("","","",false);
+                       /*if(!_name)
+                               _name = getQName("","","",false);*/
                        return _name;
                }
                
@@ -2257,6 +2316,20 @@ package
                 */
                public function setName(name:*):void
                {
+                       //@todo add tests to review against the following:
+                       /*1. If x.[[Class]] ∈ {"text", "comment"}, return
+                       2. If (Type(name) is Object) and (name.[[Class]] == 
"QName") and (name.uri == null)
+                       a. Let name = name.localName
+                       3. Let n be a new QName created if by calling the 
constructor new QName(name)
+                       4. If x.[[Class]] == "processing-instruction", let 
n.uri be the empty string
+                       5. Let x.[[Name]] = n
+                       6. Let ns be a new Namespace created as if by calling 
the constructor new Namespace(n.prefix, n.uri)
+                       7. If x.[[Class]] == "attribute"
+                       a. If x.[[Parent]] == null, return
+                       b. Call x.[[Parent]].[[AddInScopeNamespace]](ns)
+                       8. If x.[[Class]] == "element"
+                       a. Call x.[[AddInScopeNamespace]](ns)*/
+                       if (_nodeKind == 'text' || _nodeKind == 'comment') 
return; //e4x, see 1 above
                        var nameRef:QName;
                        if(name is QName)
                                nameRef = name;
@@ -2274,22 +2347,23 @@ package
                 */
                public function setNamespace(ns:Object):void
                {
-                       if(_nodeKind == "text" || _nodeKind == "comment" || 
_nodeKind == "processing-instruction")
+                       var kind:String = _nodeKind;
+                       if(kind == "text" || kind == "comment" || kind == 
"processing-instruction")
                                return;
                        var ns2:Namespace = new Namespace(ns);
                        var nameRef:QName = new QName(ns2,name());
                        
-                       if(_nodeKind == "attribute")
+                       if(kind == "attribute")
                        {
-                               nameRef.isAttribute = true;
                                if(_parent == null)
                                        return;
+                               nameRef.isAttribute = true;
                                _parent.addNamespace(ns2);
                        }
-
+                       
                        _name = 
getQName(nameRef.localName,nameRef.prefix,nameRef.uri,nameRef.isAttribute);
 
-                       if(_nodeKind == "element")
+                       if(kind == "element")
                                addNamespace(ns2);
                }
 
@@ -2553,26 +2627,28 @@ package
                                indentArr.push(_indentStr);
 
                        var indent:String = indentArr.join("");
-                       if(this.nodeKind() == "text")
+                       const nodeType:String = this.nodeKind();
+                       if(nodeType == "text") //4.
                        {
                                if(prettyPrinting)
                                {
                                        var v:String = 
trimXMLWhitespace(_value);
-                                       if(name().localName == "#cdata-section")
+                                       if (v.indexOf('<![CDATA[') == 0) {
                                                return indent + v;
+                                       }
                                        return indent + escapeElementValue(v);
                                }
-                               if(name().localName == "#cdata-section")
+                               if (_value.indexOf('<![CDATA[') == 0)
                                        return _value;
                                return escapeElementValue(_value);
                        }
-                       if(this.nodeKind() == "attribute")
+                       if(nodeType == "attribute")
                                return indent + escapeAttributeValue(_value);
 
-                       if(this.nodeKind() == "comment")
+                       if(nodeType == "comment")
                                return indent + "<!--" +  _value + "-->";
 
-                       if(this.nodeKind() == "processing-instruction")
+                       if(nodeType == "processing-instruction")
                                return indent + "<?" + name().localName + " " + 
_value + "?>";
 
                        // We excluded the other types, so it's a normal element
@@ -2613,24 +2689,8 @@ package
                        if(ns.prefix)
                                strArr.push(ns.prefix+":");
                        strArr.push(name().localName);
-
+                       
                        //attributes and namespace declarations... (15-16)
-                       for(i=0;i<declarations.length;i++)
-                       {
-                               var decVal:String = 
escapeAttributeValue(declarations[i].uri);
-                               if(decVal)
-                               {
-                                       strArr.push(" xmlns");
-                                       if(declarations[i].prefix)
-                                       {
-                                               strArr.push(":");
-                                               
strArr.push(declarations[i].prefix);
-                                       }
-                                       strArr.push('="');
-                                       strArr.push(decVal);
-                                       strArr.push('"');
-                               }
-                       }
                        len = attributeLength();
                        for(i=0;i<len;i++)
                        {
@@ -2649,6 +2709,24 @@ package
                                
strArr.push(escapeAttributeValue(_attributes[i].getValue()));
                                strArr.push('"');
                        }
+                       // see 15. namespace declarations is after
+                       for(i=0;i<declarations.length;i++)
+                       {
+                               var decVal:String = 
escapeAttributeValue(declarations[i].uri);
+                               if(decVal)
+                               {
+                                       strArr.push(" xmlns");
+                                       if(declarations[i].prefix)
+                                       {
+                                               strArr.push(":");
+                                               
strArr.push(declarations[i].prefix);
+                                       }
+                                       strArr.push('="');
+                                       strArr.push(decVal);
+                                       strArr.push('"');
+                               }
+                       }
+                       
                        // now write elements or close the tag if none exist
                        len = childrenLength();
                        if(len == 0)
diff --git a/frameworks/projects/XML/src/main/royale/XMLList.as 
b/frameworks/projects/XML/src/main/royale/XMLList.as
index 49a902d..a54df14 100644
--- a/frameworks/projects/XML/src/main/royale/XMLList.as
+++ b/frameworks/projects/XML/src/main/royale/XMLList.as
@@ -603,6 +603,28 @@ package
                            i. Let i = i + 1
                        3. Return list
                        */
+                       var len:uint = _xmlArray.length;
+            var textAccumulator:XML;
+                       for (var i:int=0; i<len; i++) {
+                               var node:XML = XML(_xmlArray[i]);
+                               var nodeKind:String = node.nodeKind();
+                               if (nodeKind == 'element' ) {
+                    node.normalize();
+                    textAccumulator = null;
+                               } else if (nodeKind == 'text') {
+                                       if (textAccumulator) {
+                        textAccumulator.setValue(textAccumulator.getValue() + 
node.getValue());
+                        removeChildAt(i);
+                                               i--;
+                                               len--;
+                                       } else {
+                        textAccumulator = node;
+                                       }
+                               } else {
+                    textAccumulator = null;
+                               }
+                       }
+                       
                        return this;
                }
                
@@ -973,26 +995,37 @@ package
                                if(str)
                                        retVal.push(str);
                        }
-                       return retVal.join("");
+                       return retVal.join("\n");
                }
                
                /**
                 * Returns a string representation of all the XML objects in an 
XMLList object.
                 * 
                 * @return 
-                * 
+                *
+                * @royaleignorecoercion XML
                 */
                public function toString():String
                {
                        var retVal:Array = [];
                        var len:int = _xmlArray.length;
+                       var cumulativeText:String = '';
                        for (var i:int=0;i<len;i++)
                        {
                                var str:String = _xmlArray[i].toString();
-                               if(str)
-                                       retVal.push(str);
+                               if (XML(_xmlArray[i]).nodeKind() == 'text') {
+                                       cumulativeText += str;
+                               } else {
+                                       if (cumulativeText) {
+                        retVal.push(cumulativeText);
+                        cumulativeText = '';
+                                       }
+                    if(str)
+                        retVal.push(str);
+                               }
                        }
-                       return retVal.join("");
+            if (cumulativeText) retVal.push(cumulativeText);
+                       return retVal.join("\n");
                }
                
                /**

Reply via email to