Summary: Newlines are not currently escaped in XML serialization.
New Features:
Bugs Fixed: N/A
Technical Reviewer: max
QA Reviewer: pablo
Doc Reviewer: n/a
Documentation:
Release Notes:
XML serialization has been updated to escape newlines in attribute values.
Details:
W3 character escaping says that the canonical form of CR uses an escape code.
Server code that we're writing appears to support this.
http://www.w3.org/TR/1999/WD-xml-c14n-19991109.html#charescaping
NB that the linefeed or carriage return would be a reasonable
choice here, but I went with carriage return since that best
matches the definition of Javascript charCode 13.
Tests:
This is hard to test without server support, as the
LFC allows literal newlines in attribute values.
Files:
WEB-INF/lps/lfc/data/LzDataNode.as
===================================================================
--- WEB-INF/lps/lfc/data/LzDataNode.as (revision 4120)
+++ WEB-INF/lps/lfc/data/LzDataNode.as (working copy)
@@ -108,11 +108,16 @@
var olen = t.length;
var r = "";
for ( var i = 0; i < olen; i++ ){
- var c = t.charAt( i );
- if ( this.__LZescapechars[ c ] != null ){
- r += this.__LZescapechars[ c ];
+ //handle newlines
+ if ( t.charCodeAt( i ) == 13 ){
+ r += "
";
} else {
- r += c;
+ var c = t.charAt( i );
+ if ( this.__LZescapechars[ c ] != null ){
+ r += this.__LZescapechars[ c ];
+ } else {
+ r += c;
+ }
}
}
/******************************************************************************
* LzDataNode.as
*****************************************************************************/
//* A_LZ_COPYRIGHT_BEGIN ******************************************************
//* Copyright 2001-2006 Laszlo Systems, Inc. All Rights Reserved. *
//* Use is subject to license terms. *
//* A_LZ_COPYRIGHT_END ********************************************************
//==============================================================================
// DEFINE OBJECT: LzDataNode
//
// LzDataNode is the abstract baseclass for LzDataElement and LzDataText.
//==============================================================================
var LzDataNode = Class( "LzDataNode" , null, function (){ this.childNodes = [];
} );
//@field Number nodeType: The type of this node -- ELEMENT_NODE or TEXT_NODE
LzDataNode.prototype.nodeType = null;
//@field LzDataNode ownerDocument: The ownerDocument of this node.
LzDataNode.prototype.ownerDocument = null;
//@field LzDataNode parentNode: The name of this node.
LzDataNode.prototype.parentNode = null;
LzDataNode.prototype.onparentNode = null;
//@problem: how do I document these?
LzDataNode.ELEMENT_NODE = 1;
LzDataNode.TEXT_NODE = 3;
LzDataNode.DOCUMENT_NODE = 9;
//------------------------------------------------------------------------------
// Returns the sibling before this one this node's parentNodes List of children
// @return LzDataNode: The node preceeding this one in this node's childNodes
//------------------------------------------------------------------------------
LzDataNode.prototype.getPreviousSibling = function (){
if ( this.parentNode.__LZcoDirty ) this.parentNode.__LZupdateCO();
return this.parentNode.childNodes[ this.__LZo - 1 ];
}
//------------------------------------------------------------------------------
// @keywords private
//------------------------------------------------------------------------------
LzDataNode.prototype.getPreviousSibling.dependencies = function( who, self ){
return [ this.parentNode , "childNodes" , this , "parentNode" ];
}
//------------------------------------------------------------------------------
// Returns the sibling after this one this node's parentNodes List of children
// @return LzDataNode: The node succeeding this one in this node's childNodes
//------------------------------------------------------------------------------
LzDataNode.prototype.getNextSibling = function (){
if ( this.parentNode.__LZcoDirty ) this.parentNode.__LZupdateCO();
return this.parentNode.childNodes[ this.__LZo + 1 ];
}
//------------------------------------------------------------------------------
// @keywords private
//------------------------------------------------------------------------------
LzDataNode.prototype.getNextSibling.dependencies = function( who, self ){
return [ this.parentNode , "childNodes" , this , "parentNode" ];
}
//------------------------------------------------------------------------------
// Tells whether the given node is above this one in the node hierarchy.
// @param LzDataElement el: The LzDataElement to test to see if it is above
// this one
// @param Boolean allowself: If true, this function returns true if the given
// node is the same as this node.
//------------------------------------------------------------------------------
LzDataNode.prototype.childOf = function ( el , allowself ) {
var p = allowself ? this : this.parentNode
while ( p ){
if ( p == el ) return true;
p = p.parentNode;
}
return false;
}
//------------------------------------------------------------------------------
// Sets the LzDataNode which is the ownerDocument for this node.
// @param LzDataNode ownerDoc: The LzDataNode to act as the ownerDocument for
// this node.
//------------------------------------------------------------------------------
LzDataNode.prototype.setOwnerDocument = function ( ownerDoc ){
this.ownerDocument = ownerDoc;
for ( var i = 0; i < this.childNodes.length; i++ ){
this.childNodes[ i ] .setOwnerDocument( ownerDoc );
}
this.onownerDocument.sendEvent( ownerDoc );
}
//this is similar to the escape routine in LzText, but that one's shorter
//since flash it's just for escaping <>
LzDataNode.prototype.__LZescapechars = {};
LzDataNode.prototype.__LZescapechars[ "&" ] = "&" ;
LzDataNode.prototype.__LZescapechars[ "<" ] = "<" ;
LzDataNode.prototype.__LZescapechars[ ">" ] = ">" ;
LzDataNode.prototype.__LZescapechars[ '"' ] = """ ;
LzDataNode.prototype.__LZescapechars[ "'" ] = "'" ;
//------------------------------------------------------------------------------
// @keywords private
//------------------------------------------------------------------------------
LzDataNode.prototype.__LZXMLescape = function ( t ){
if ( typeof( t ) != "string" ) return t;
var olen = t.length;
var r = "";
for ( var i = 0; i < olen; i++ ){
//handle newlines
if ( t.charCodeAt( i ) == 13 ){
r += "
";
} else {
var c = t.charAt( i );
if ( this.__LZescapechars[ c ] != null ){
r += this.__LZescapechars[ c ];
} else {
r += c;
}
}
}
return r;
}
//------------------------------------------------------------------------------
// @keywords private
//------------------------------------------------------------------------------
LzDataNode.prototype.__LZlockFromUpdate = function ( locker ){
this.ownerDocument.__LZdoLock( locker );
}
//------------------------------------------------------------------------------
// @keywords private
//------------------------------------------------------------------------------
LzDataNode.prototype.__LZunlockFromUpdate = function ( locker ){
this.ownerDocument.__LZdoUnlock( locker );
}
//-----------------------------------------------------------------------------
// Converts string to XML data.
// @param String str: A valid string of XML. If the string is simple text, or
// that there isn't a single root element, this function returns null. In cases
// where the string is an invalid but well formatted snippet of XML, this
// function will close any tags to make for a valid XML document
// @param boolean trimwhitespace: if true, text nodes have whitespace trimmed
from start and end.
// @return LzDataElement: An LzDataElement which is the top of the hierarchy
// generated from the string
//-----------------------------------------------------------------------------
LzDataNode.stringToLzData = function( str, trimwhitespace, stripnsprefix ) {
var xmlobj = new XML();
xmlobj.ignoreWhite = true;
xmlobj.parseXML( str );
if ( xmlobj.childNodes.length != 1 ) return null;
var lfcnode = LzLoader.prototype.copyFlashXML(xmlobj, trimwhitespace,
stripnsprefix);
var fc = lfcnode.removeChild( lfcnode.getFirstChild() );
if ( fc instanceof LzDataText ) return null;
return fc;
}
LzDataNode.whitespaceChars = {' ': true, '\r': true, '\n': true, '\t': true};
//------------------------------------------------------------------------------
// @keywords private
// trim whitespace from start and end of string
//------------------------------------------------------------------------------
LzDataNode.trim = function( str ) {
var whitech = LzDataNode.whitespaceChars;
var len = str.length;
var sindex = 0;
var eindex = str.length -1;
var ch;
while (sindex < len) {
ch = str.charAt(sindex);
if (whitech[ch] != true) break;
sindex++;
}
while (eindex > sindex) {
ch = str.charAt(eindex);
if (whitech[ch] != true) break;
eindex--;
}
return str.slice(sindex,eindex+1);
}