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 Defines the {@link CKEDITOR.xml} class, which represents a
 24  *		loaded XML document.
 25  */
 26
 27 /**
 28  * Represents a loaded XML document.
 29  * @constructor
 30  * @param {object|string} xmlObjectOrData A native XML (DOM document) object or
 31  *		a string containing the XML definition to be loaded.
 32  * @example
 33  * var xml = <b>new CKEDITOR.xml( '<books><book title="My Book" /></books>' )</b>;
 34  */
 35 CKEDITOR.xml = function( xmlObjectOrData )
 36 {
 37 	var baseXml = null;
 38
 39 	if ( typeof xmlObjectOrData == 'object' )
 40 		baseXml = xmlObjectOrData;
 41 	else
 42 	{
 43 		if ( window.DOMParser )
 44 			baseXml = (new DOMParser()).parseFromString( xmlObjectOrData || '', 'text/xml' );
 45 		else if ( window.ActiveXObject )
 46 		{
 47 			try { baseXml = new ActiveXObject( 'MSXML2.DOMDocument' ); }
 48 			catch(e)
 49 			{
 50 				try { baseXml = new ActiveXObject( 'Microsoft.XmlDom' ); } catch(e) {}
 51 			}
 52
 53 			if ( baseXml )
 54 			{
 55 				baseXml.async = false;
 56 				baseXml.resolveExternals = false;
 57 				baseXml.validateOnParse = false;
 58 				baseXml.loadXML( xmlObjectOrData || '' );
 59 			}
 60 		}
 61 	}
 62
 63 	/**
 64 	 * The native XML (DOM document) used by the class instance.
 65 	 * @type object
 66 	 * @example
 67 	 */
 68 	this.baseXml = baseXml;
 69 };
 70
 71 CKEDITOR.xml.prototype =
 72 {
 73 	/**
 74 	 * Get a single node from the XML document, based on a XPath query.
 75 	 * @param {String} xpath The XPath query to execute.
 76 	 * @param {Object} [contextNode] The XML DOM node to be used as the context
 77 	 *		for the XPath query. The document root is used by default.
 78 	 * @returns {Object} A XML node element or null if the query has no results.
 79 	 * @example
 80 	 * // Create the XML instance.
 81 	 * var xml = new CKEDITOR.xml( '<list><item id="test1" /><item id="test2" /></list>' );
 82 	 * // Get the first <item> node.
 83 	 * var itemNode = <b>xml.selectSingleNode( 'list/item' )</b>;
 84 	 * // Alert "item".
 85 	 * alert( itemNode.nodeName );
 86 	 */
 87 	selectSingleNode : function( xpath, contextNode )
 88 	{
 89 		var baseXml = this.baseXml;
 90
 91 		if ( contextNode || ( contextNode = baseXml ) )
 92 		{
 93 			if ( CKEDITOR.env.ie || contextNode.selectSingleNode )	// IE
 94 				return contextNode.selectSingleNode( xpath );
 95 			else if ( baseXml.evaluate )							// Others
 96 			{
 97 				var result = baseXml.evaluate( xpath, contextNode, null, 9, null);
 98 				return ( result && result.singleNodeValue ) || null;
 99 			}
100 		}
101
102 		return null;
103 	},
104
105 	/**
106 	 * Gets a list node from the XML document, based on a XPath query.
107 	 * @param {String} xpath The XPath query to execute.
108 	 * @param {Object} [contextNode] The XML DOM node to be used as the context
109 	 *		for the XPath query. The document root is used by default.
110 	 * @returns {Array} An array containing all matched nodes. The array will
111 	 *		be empty if the query has no results.
112 	 * @example
113 	 * // Create the XML instance.
114 	 * var xml = new CKEDITOR.xml( '<list><item id="test1" /><item id="test2" /></list>' );
115 	 * // Get the first <item> node.
116 	 * var itemNodes = xml.selectSingleNode( 'list/item' );
117 	 * // Alert "item" twice, one for each <item>.
118 	 * for ( var i = 0 ; i < itemNodes.length ; i++ )
119 	 *     alert( itemNodes[i].nodeName );
120 	 */
121 	selectNodes : function( xpath, contextNode )
122 	{
123 		var baseXml = this.baseXml,
124 			nodes = [];
125
126 		if ( contextNode || ( contextNode = baseXml ) )
127 		{
128 			if ( CKEDITOR.env.ie || contextNode.selectNodes )		// IE
129 				return contextNode.selectNodes( xpath );
130 			else if ( baseXml.evaluate )							// Others
131 			{
132 				var result = baseXml.evaluate( xpath, contextNode, null, 5, null);
133
134 				if ( result )
135 				{
136 					var node;
137 					while( ( node = result.iterateNext() ) )
138 						nodes.push( node );
139 				}
140 			}
141 		}
142
143 		return nodes;
144 	},
145
146 	/**
147 	 * Gets the string representation of a XML node, based on a XPath query.
148 	 * @param {String} xpath The XPath query to execute.
149 	 * @param {Object} [contextNode] The XML DOM node to be used as the context
150 	 *		for the XPath query. The document root is used by default.
151 	 * @returns {String} The textual representation of the XML node or null if
152 	 *		the query has no results.
153 	 * @example
154 	 * // Create the XML instance.
155 	 * var xml = new CKEDITOR.xml( '<list><item id="test1" /><item id="test2" /></list>' );
156 	 * // Alert "<item id="test1" />".
157 	 * alert( xml.getOuterXml( 'list/item' ) );
158 	 */
159 	getOuterXml : function( xpath, contextNode )
160 	{
161 		var node = this.selectSingleNode( xpath, contextNode );
162 		if ( node )
163 		{
164 			if ( node.xml )				// IE
165 				return node.xml;
166 			else if ( window.XMLSerializer )	// Others
167 				return ( new XMLSerializer() ).serializeToString( node );
168 		}
169
170 		return null;
171 	}
172 };
173