/** * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ /** * @fileOverview Defines the {@link CKEDITOR.xml} class, which represents a * loaded XML document. */ ( function() { /* global ActiveXObject */ CKEDITOR.plugins.add( 'xml', {} ); /** * Represents a loaded XML document. * * var xml = new CKEDITOR.xml( '' ); * * @class * @constructor Creates xml class instance. * @param {Object/String} xmlObjectOrData A native XML (DOM document) object or * a string containing the XML definition to be loaded. */ CKEDITOR.xml = function( xmlObjectOrData ) { var baseXml = null; if ( typeof xmlObjectOrData == 'object' ) baseXml = xmlObjectOrData; else { var data = ( xmlObjectOrData || '' ).replace( / /g, '\xA0' ); // Check ActiveXObject before DOMParser, because IE10+ support both, but // there's no XPath support in DOMParser instance. // Also, the only check for ActiveXObject which still works in IE11+ is with `in` operator. if ( 'ActiveXObject' in window ) { try { baseXml = new ActiveXObject( 'MSXML2.DOMDocument' ); } catch ( e ) { try { baseXml = new ActiveXObject( 'Microsoft.XmlDom' ); } catch ( err ) {} } if ( baseXml ) { baseXml.async = false; baseXml.resolveExternals = false; baseXml.validateOnParse = false; baseXml.loadXML( data ); } } else if ( window.DOMParser ) { baseXml = ( new DOMParser() ).parseFromString( data, 'text/xml' ); } } /** * The native XML (DOM document) used by the class instance. * * @property {Object} */ this.baseXml = baseXml; }; CKEDITOR.xml.prototype = { /** * Get a single node from the XML document, based on a XPath query. * * // Create the XML instance. * var xml = new CKEDITOR.xml( '' ); * // Get the first node. * var itemNode = xml.selectSingleNode( 'list/item' ); * // Alert "item". * alert( itemNode.nodeName ); * * @param {String} xpath The XPath query to execute. * @param {Object} [contextNode] The XML DOM node to be used as the context * for the XPath query. The document root is used by default. * @returns {Object} A XML node element or null if the query has no results. */ selectSingleNode: function( xpath, contextNode ) { var baseXml = this.baseXml; if ( contextNode || ( contextNode = baseXml ) ) { if ( 'selectSingleNode' in contextNode ) // IEs return contextNode.selectSingleNode( xpath ); else if ( baseXml.evaluate ) { // Others var result = baseXml.evaluate( xpath, contextNode, null, 9, null ); return ( result && result.singleNodeValue ) || null; } } return null; }, /** * Gets a list node from the XML document, based on a XPath query. * * // Create the XML instance. * var xml = new CKEDITOR.xml( '' ); * // Get all nodes. * var itemNodes = xml.selectNodes( 'list/item' ); * // Alert "item" twice, one for each . * for ( var i = 0; i < itemNodes.length; i++ ) * alert( itemNodes[i].nodeName ); * * @param {String} xpath The XPath query to execute. * @param {Object} [contextNode] The XML DOM node to be used as the context * for the XPath query. The document root is used by default. * @returns {Array} An array containing all matched nodes. The array will * be empty if the query has no results. */ selectNodes: function( xpath, contextNode ) { var baseXml = this.baseXml, nodes = []; if ( contextNode || ( contextNode = baseXml ) ) { if ( 'selectNodes' in contextNode ) // IEs return contextNode.selectNodes( xpath ); else if ( baseXml.evaluate ) { // Others var result = baseXml.evaluate( xpath, contextNode, null, 5, null ); if ( result ) { var node; while ( ( node = result.iterateNext() ) ) nodes.push( node ); } } } return nodes; }, /** * Gets the string representation of hte inner contents of a XML node, * based on a XPath query. * * // Create the XML instance. * var xml = new CKEDITOR.xml( '' ); * // Alert "". * alert( xml.getInnerXml( 'list' ) ); * * @param {String} xpath The XPath query to execute. * @param {Object} [contextNode] The XML DOM node to be used as the context * for the XPath query. The document root is used by default. * @returns {String} The textual representation of the inner contents of * the node or null if the query has no results. */ getInnerXml: function( xpath, contextNode ) { var node = this.selectSingleNode( xpath, contextNode ), xml = []; if ( node ) { node = node.firstChild; while ( node ) { if ( node.xml ) // IEs xml.push( node.xml ); else if ( window.XMLSerializer ) // Others xml.push( ( new XMLSerializer() ).serializeToString( node ) ); node = node.nextSibling; } } return xml.length ? xml.join( '' ) : null; } }; } )(jQuery);