Showing posts with label XML. Show all posts
Showing posts with label XML. Show all posts

Thursday, June 17, 2010

Link of the day ! "DOM Deviations", sorry "Normative Variations"

The following subsections detail the normative variations from MUST requirements in [DOM Level 3 - Core].

http://msdn.microsoft.com/en-us/library/ff460357(v=VS.85).aspx


Or even better:
Internet Explorer Standards Support Documents

http://msdn.microsoft.com/en-us/library/ff405926(v=VS.85).aspx

Monday, June 14, 2010

W3 Document.textContent vs. MSXML Document.text and MSDN docs

w3 says that .textContent for DOCUMENT_NODE should be null.
Closest MS implementation (MSXML .text) documented in MSDN claims:
NODE_DOCUMENT
Returns a string representing the value of the node.
This is the concatenated text of
all subnodes with entities expanded.
But what is subnodes and what is text ?
<?xml version="1.0" encoding="utf-8" ?>
<!-- Document level comment -->
<!-- TODO: NOTATION -->
<!DOCTYPE root [
    <!ENTITY ent1 "expanded ent1">
]>
<?pi1 ?>
<root attribute="attribute.value">
    element.text.1
    <e1><![CDATA[cdata.content]]></e1>
    <e2><!--comment.content--></e2>
    <e3>&ent1;</e3>
    element.text.2
</root> 
Remarks section clarifies something:
When concatenated, the text represents the contents of text or CDATA nodes. All concatenated text nodes are normalized according to xml:space attributes and the value of the preserveWhiteSpace switch. Concatenated CDATA text is not normalized. (Child nodes that contain NODE_COMMENT and NODE_PROCESSING_INSTRUCTION nodes are not concatenated.) .text trims the whitespace on the edges of the result, and "normalizes" \r\n => \n, but otherwise just concatenates text.
Retrieves and sets the string representing the text contents of this node or the concatenated text representing this node and its descendants.
For more precise control over text manipulation in an XML document, use the lower-level nodeValue property, which returns the raw text associated with a NODE_TEXT node.
For this sample it returns:
element.text.1 cdata.content expanded ent1 element.text.2
Both comments skipped, OK, but I still, miss the text of my NODE_ENTITY.
If requested ditectly NODE_ENTITY.text returns:
expanded ent1
So I would expect:
expanded ent1 element.text.1 cdata.content expanded ent1 element.text.2
Why is NODE_ENTITY.text missing from NODE_DOCUMENT.text ? Maybe because it is inside NODE_DOCUMENT_TYPE which claims to return .text as "" ? Or because :text", does not mean text but nodeValue which is defined as null for both NODE_DOCUMENT_TYPE and NODE_ENTITY.

Results:
From my quick tests Document.text behaves the same as Document.documentElement.text. If anyone can show, how the may differ I would be pleased. Until then, considered as bad design, useless w3 deviation and insufficent documentation.

Wednesday, June 9, 2010

MSXML.createNode method (docs,design,standards?)

http://msdn.microsoft.com/en-us/library/ms757901(VS.85).aspx
A string defining the namespace URI. If specified, the node is created in the context of
the namespaceURI parameter with the prefix specified on the node name.
If the name parameter does not have a prefix, this is treated as the default namespace.

The marked part may be a bit problematic to interpret.
In the reality it means that createNode will create unprefixed element or attribute and
produce xmlns="ns" declaration.

This is fine for elements because of xmlns scoping.
However this leads to troubles if creating
unprefixed-namespaced-attribute on unprefixed-namespaced-element with different namespace,
and also if creating
prefixed-namespaced-attribute on prefixed-namespaced-element with different namespace and same prefixes.
var root = d.createNode(1, "root", "nsRoot"),
    ch1 = d.createNode(1, "p:child", "nsChild"),
    ch2 = d.createNode(1, "child", "nsChild"),
    a1 = d.createNode(2, "p2:a1", "nsAttr"),
    a2 = d.createNode(2, "a2", "nsAttr");

root.appendChild(ch1);
root.appendChild(ch2);
ch2.setAttributeNode(a1);
ch2.setAttributeNode(a2);
The last line will fail, with "bit problematic to interpret" error,
showing authors misinterpretation of namespace and prefixe terms ;-)

There was a Namespace conflict for the '' Namespace.

Actualy there was a conflict for '' prefix between nsChild and nsAttr namespaces.

XML without last line will look like this:
<root xmlns="nsRoot">
    <p:child xmlns:p="nsChild"/>
    <child xmlns="nsChild" xmlns:p2="nsAttr" p2:a1=""/>
</root>

Try to rewrite this code with createElementNS and createAttributeNS in different browsers.
Some are able to autogenerate prefixes if already taken by another namespace, some produce funny results.

MS is lucky not to declare http://www.w3.org/TR/DOM-Level-2-Core/ compliance, however the docs are confusing and
prefix colisions unsolved.

Another silly decision is that namespaceURI does not accept null.
The closes standardized method (DOM2 Level createElementNS) speaks abou null values, and all browsers implement
both null and "" as "unqualified".

Monday, June 7, 2010

node.setAttributeNS(namespaceURI, qualifiedName, value)

When trying to implement this missing method in MSXML,
several interesing
inconsistencies in other browsers apeared,
all claim the native support for this method.

Pseudopcode:

set("ns1","a:a","1")
old=getAttributeWithXPath
set("ns1","b:a","2")
new=getAttributeWithXPath
print compare pointers
print new.nodeName
print new.value
print serialized xml


MSXML 6.0

result:false
p2:a
2
xmlns:p2="ns" p2:a="2"


Firefox/3.5.6

result:true
p1:a
2
p2:a="2" xmlns:p2="ns"

Safari/531.22.7

result:true
p1:a
1
p1:a="2" xmlns:p1="ns"


Chrome/5.0.375.55

result:true
p1:a
2
p1:a="2" xmlns:p1="ns"

Of course there is always an excuse:
http://www.w3.org/TR/DOM-Level-2-Core/core.html
Note: DOM Level 1 methods are namespace ignorant. Therefore, while it is safe to use these methods when not dealing with namespaces, using them and the new ones at the same time should be avoided. DOM Level 1 methods solely identify attribute nodes by their nodeName. On the contrary, the DOM Level 2 methods related to namespaces, identify attribute nodes by their namespaceURI and localName. Because of this fundamental difference, mixing both sets of methods can lead to unpredictable results. In particular, using setAttributeNS, an element may have two attributes (or more) that have the same nodeName, but different namespaceURIs. Calling getAttribute with that nodeName could then return any of those attributes. The result depends on the implementation. Similarly, using setAttributeNode, one can set two attributes (or more) that have different nodeNames but the same prefix and namespaceURI. In this case getAttributeNodeNS will return either attribute, in an implementation dependent manner. The only guarantee in such cases is that all methods that access a named item by its nodeName will access the same item, and all methods which access a node by its URI and local name will access the same node. For instance, setAttribute and setAttributeNS affect the node that getAttribute and getAttributeNS, respectively, return.

Wednesday, April 7, 2010

XHR.onreadystatechange and exceptions

Generally it is not good idea to throw exception in event handler.
However people are lazy and bugs happen, so let's see out chances in this situation.

xhr.onreadystatechange=function(){throw new Error();}

MSIE and FF supports window.onerror event, so uncought exceptions can end up in
this global handler.

All browsers support some sort of "display JavaScript errors" but usually well hidden
as small icon on status bar (MSIE) or deeply in menus (other browsers).

Uniform handling is almost impossible. The very first idea was to rely on
window.error in MSIE an FF and call window.onerror explicitly in
other browsers (even if the browser does not support this error you can define

window.onerror=function...
and call it using window.onerror(msg,..,...) syntax.

However situation is even worse.

  1. FF 3.5.6 works fine, ewrror thrown, ends in window.onerror as expected.
  2. MSIE 7.0 NativeXHR + 200 response - works fine
  3. MSIE 7.0 NativeXHR + conditional request + 304 response - exception lost, window.onerror not called
  4. MSIE 7.0 NativeXHR + cached version not tested byt expected - exception lost, window.onerror not called
  5. FF 3.6 exception lost, window.onerror not called
So it seems that we cannot rely:
  1. exception being thrown out of boundaries of the handler (eaten exception)
  2. even if thrown to be catched somewhere (missing window.onerror concept)
P.S. tested in async true scenarios, async false can reveal more troubles....

Thursday, January 7, 2010

Anti-sample Of The Day - Msxml3.XMLHTTP

http://www.quirksmode.org/js/xmlhttp.html

We have been reviewing different frameworks to see how they use MSXML progids - different versions of MSXML parser and XMLHTTP.
Look at this one:
Msxml3.XMLHTTP
Shame, the sample comes from PPKs highly credited web site http://www.quirksmode.org/js/xmlhttp.html
and if you google a bit you will see how this incorrect version is spread wide (copy-pase development ?).

This is MS XmlTeam suggestion using-the-right-version-of-msxml-in-internet-explorer(from 2006!).
After quick mailing with MS Team thay had confirmed there is no Msxml3.XMLHTTP ;-)

Thursday, December 10, 2009

loadXml MAY involve network activities

Argument that MSXML.loadXML cannot be async, because it is loading string and does not involve networking activity (which only can be async) is a bit wrong:

loadXML with string

<!DOCTYPE page [
<!ENTITY ent1 "internal">
<!ENTITY ent2 SYSTEM "test2.xml">
]>
<root>
<e1>&ent1;</e1>
<e2>&ent2;</e2>
</root>


will cause request to URL test2.xml (resolved against URI of the current page).
So Yes there is network activity with loading strings !.

Anyway even this scenario seems to behave synchronously (loadXml is blocking) even with async=true ;-)

"More on XML entities", and "Damned Defaults" are comming soon.... keep in touch

Wednesday, December 2, 2009

loadXML,load(uri),load(dom) sync or async ?

This post is to clarify some of my statements presented in webreflection blog comments (do not want to waste your space Andrea).

"Official Documentation" (more cookbook than API specification)


Question: is it guaranteed by "specification" that dom.loadXML is blocking regardless on dom.async property ? Do I have to write dom.async=false to perform intentional synchronous load of xml string ?

(not)Final Note

Since I have failed to "clearly" decrypt the documentation wording to come up with presentable argument I provide tests: Experiments show that current implementation of MSXML (all tested versions) show:
  • async=false - load(uri) - IS BLOCKING
  • async=true - load(uri) - IS NONBLOCKING
  • async=true - load(dom) - IS BLOCKING (logical ?, documented ?)
  • async=true - loadXML(string) - IS BLOCKING (logical ?, documented ?)

Usage of onreadystatechange is available in both async, and sync modes.
Would you write different code for load(uri) and load(dom/stream) ?
I do not.


For intentionaly synchronous code I will write async=false before any load (loadXml/load(dom)/load(uri))
and will continue processing after load exits (even if "runtime behavior" shows async=false as unnecesary for loadXml/load(dom)).


For intentionaly asynchronous code I will write async=true before any load (loadXml/load(dom)/load(uri))
(even if it's default) and will use readystatechange, and will not rely on load blocking (even if "runtime behavior" show that loadXml/load(dom) blocks).

Argument that loading string cannot be asynchronous is naive, anything can be made asynchronous even i++ if component designer decides to be and language + runtime features alow that ;-)

loadXmlIsSAsync.js (testcase)

/** loadXml - blocking, async propery ignored ? load(DOM) - blocking, async propery ignored ? load(uri) - blocking/nonblocking, async propery honored **/ function main() { var progids= [ "Msxml.DOMDocument", "Msxml2.DOMDocument", "Msxml2.DOMDocument.3.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.6.0", "Msxml2.FreeThreadedDOMDocument.3.0", "Msxml2.FreeThreadedDOMDocument.4.0", "Msxml2.FreeThreadedDOMDocument.5.0", "Msxml2.FreeThreadedDOMDocument.6.0" ]; var depth=200,width=200; var line=nTimes("<test>",depth)+nTimes("</test>",depth); var strXml= "<root xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +nTimes(line,width) +"</root>"; for(var i=0;i<progids.length;i++) { //loadXML(str) var dom1s=loadXml(progids[i],false,strXml); var dom1a=loadXml(progids[i],true,strXml); // load(dom) var dom2s=load(progids[i],false,dom1s); var dom2a=load(progids[i],true,dom1s); //load(url) var dom3s=load(progids[i],false,"loadXmlIsAsync.xml"); //200x200 size var dom3a=load(progids[i],true,"loadXmlIsAsync.xml"); print([]); } } function loadXml(progid,async,strXml) { var _dbg=["\r\n"+progid+".loadXml(strXml) "+async]; var xml=new ActiveXObject(progid); xml.onreadystatechange=function() { _dbg.push("rsch:"+xml.readyState); //window.confirm(); } xml.async=async; var success=xml.loadXML(strXml); _dbg.push("success:"+success); _dbg.push("xml.async:"+xml.async); _dbg.push("xml.readyState:"+xml.readyState); _dbg.push("xml.length:"+xml.xml.length); _dbg.push("xml.parseError:"+xml.parseError+","+xml.parseError.reason); print(_dbg); return xml; } function load(progid,async,xmlSource) { var _dbg=["\r\n"+progid+".load("+(typeof xmlSource=="string"?"url":"dom")+") "+async]; var xml=new ActiveXObject(progid); xml.onreadystatechange=function() { _dbg.push("rsch:"+xml.readyState); //window.confirm(); } xml.async=async; var success=xml.load(xmlSource); _dbg.push("success:"+success); _dbg.push("xml.async:"+xml.async); _dbg.push("xml.readyState:"+xml.readyState); _dbg.push("xml.length:"+xml.xml.length); _dbg.push("xml.parseError:"+xml.parseError+","+xml.parseError.reason); print(_dbg); return xml; } function nTimes(str,n) { var buff=new Array(n); for(var i=0;i<n;i++){buff[i]=str;}; return buff.join(""); } var print; if(typeof window != 'undefined') { print=function(_dbg) { document.getElementsByTagName("body")[0].innerHTML+=("<HR>"+_dbg.join("<BR>")); } window.onload=function() { main(); } } else { print=function(_dbg) { WScript.Echo(_dbg.join("\r\n")); } main(); }