1 /*
  2  * CKEditor - The text editor for Internet - http://ckeditor.com
  3  * Copyright (C) 2003-2008 Frederico Caldeira Knabben
  4  *
  5  * == BEGIN LICENSE ==
  6  *
  7  * Licensed under the terms of any of the following licenses at your
  8  * choice:
  9  *
 10  *  - GNU General Public License Version 2 or later (the "GPL")
 11  *    http://www.gnu.org/licenses/gpl.html
 12  *
 13  *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
 14  *    http://www.gnu.org/licenses/lgpl.html
 15  *
 16  *  - Mozilla Public License Version 1.1 or later (the "MPL")
 17  *    http://www.mozilla.org/MPL/MPL-1.1.html
 18  *
 19  * == END LICENSE ==
 20  */
 21 
 22 /**
 23  * @fileOverview The XML object class, representing a loaded XML document.
 24  */
 25  
 26 /**
 27  * Represents a loaded XML document.
 28  * @constructor
 29  * @param {object|string} xmlObjectOrData A native XML (DOM document) object or
 30  *		a string containing the XML definition to be loaded.
 31  */
 32 CKEDITOR.xml = function( xmlObjectOrData )
 33 {
 34 	var baseXml = null;
 35 
 36 	if ( typeof xmlObjectOrData == 'object' )
 37 		baseXml = xmlObjectOrData;
 38 	else
 39 	{
 40 		if ( window.DOMParser )
 41 			baseXml = (new DOMParser()).parseFromString( xmlObjectOrData || '', 'text/xml' );
 42 		else if ( window.ActiveXObject )
 43 		{
 44 			try { baseXml = new ActiveXObject( 'MSXML2.DOMDocument' ); }
 45 			catch(e)
 46 			{
 47 				try { baseXml = new ActiveXObject( 'Microsoft.XmlDom' ); } catch(e) {}
 48 			}
 49 
 50 			if ( baseXml )
 51 			{
 52 				baseXml.async = false;
 53 				baseXml.resolveExternals = false;
 54 				baseXml.validateOnParse = false;
 55 				baseXml.loadXML( xmlObjectOrData || '' );
 56 			}
 57 		}
 58 	}
 59 
 60 	/**
 61 	 * The native XML (DOM document) used by the class instance.
 62 	 * @type object
 63 	 */
 64 	this.baseXml = baseXml;
 65 };
 66 
 67 CKEDITOR.xml.prototype =
 68 {
 69 	/**
 70 	 * Get a single node from the XML document, based on a XPath query.
 71 	 * @param {String} xpath The XPath query to execute.
 72 	 * @param {Object} [contextNode] The XML DOM node to be used as the context
 73 	 *		for the XPath query. The document root is used by default.
 74 	 * @returns {Object} A XML node element or null if the query has no results.
 75 	 * @example
 76 	 * // Create the XML instance.
 77 	 * var xml = new CKEDITOR.xml( '<list><item id="test1" /><item id="test2" /></list>' );
 78 	 * // Get the first <item> node.
 79 	 * var itemNode = <b>xml.selectSingleNode( 'list/item' )</b>;
 80 	 * // Alert "item".
 81 	 * alert( itemNode.nodeName );
 82 	 */
 83 	selectSingleNode : function( xpath, contextNode )
 84 	{
 85 		var baseXml = this.baseXml;
 86 
 87 		if ( contextNode || ( contextNode = baseXml ) )
 88 		{
 89 			if ( CKEDITOR.env.ie || contextNode.selectSingleNode )	// IE
 90 				return contextNode.selectSingleNode( xpath );
 91 			else if ( baseXml.evaluate )							// Others
 92 			{
 93 				var result = baseXml.evaluate( xpath, contextNode, null, 9, null);
 94 				return ( result && result.singleNodeValue ) || null;
 95 			}
 96 		}
 97 
 98 		return null;
 99 	},
100 
101 	/**
102 	 * Gets a list node from the XML document, based on a XPath query.
103 	 * @param {String} xpath The XPath query to execute.
104 	 * @param {Object} [contextNode] The XML DOM node to be used as the context
105 	 *		for the XPath query. The document root is used by default.
106 	 * @returns {Array} An array containing all matched nodes. The array will
107 	 *		be empty if the query has no results.
108 	 * @example
109 	 * // Create the XML instance.
110 	 * var xml = new CKEDITOR.xml( '<list><item id="test1" /><item id="test2" /></list>' );
111 	 * // Get the first <item> node.
112 	 * var itemNodes = xml.selectSingleNode( 'list/item' );
113 	 * // Alert "item" twice, one for each <item>.
114 	 * for ( var i = 0 ; i < itemNodes.length ; i++ )
115 	 *     alert( itemNodes[i].nodeName );
116 	 */
117 	selectNodes : function( xpath, contextNode )
118 	{
119 		var baseXml = this.baseXml,
120 			nodes = [];
121 
122 		if ( contextNode || ( contextNode = baseXml ) )
123 		{
124 			if ( CKEDITOR.env.ie || contextNode.selectNodes )		// IE
125 				return contextNode.selectNodes( xpath );
126 			else if ( baseXml.evaluate )							// Others
127 			{
128 				var result = baseXml.evaluate( xpath, contextNode, null, 5, null);
129 
130 				if ( result )
131 				{
132 					var node;
133 					while( ( node = result.iterateNext() ) )
134 						nodes.push( node );
135 				}
136 			}
137 		}
138 
139 		return nodes;
140 	},
141 
142 	/**
143 	 * Gets the string representation of a XML node, based on a XPath query.
144 	 * @param {String} xpath The XPath query to execute.
145 	 * @param {Object} [contextNode] The XML DOM node to be used as the context
146 	 *		for the XPath query. The document root is used by default.
147 	 * @returns {String} The textual representation of the XML node or null if
148 	 *		the query has no results.
149 	 * @example
150 	 * // Create the XML instance.
151 	 * var xml = new CKEDITOR.xml( '<list><item id="test1" /><item id="test2" /></list>' );
152 	 * // Alert "<item id="test1" />".
153 	 * alert( xml.getOuterXml( 'list/item' ) );
154 	 */
155 	getOuterXml : function( xpath, contextNode )
156 	{
157 		var node = this.selectSingleNode( xpath, contextNode );
158 		if ( node )
159 		{
160 			if ( node.xml )				// IE
161 				return node.xml;
162 			else if ( window.XMLSerializer )	// Others
163 				return ( new XMLSerializer() ).serializeToString( node );
164 		}
165 
166 		return null;
167 	}
168 };