Path: blob/trunk/third_party/closure/goog/dom/xml.js
2868 views
// Copyright 2006 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview16* XML utilities.17*18*/1920goog.provide('goog.dom.xml');2122goog.require('goog.dom');23goog.require('goog.dom.NodeType');24goog.require('goog.userAgent');252627/**28* Max XML size for MSXML2. Used to prevent potential DoS attacks.29* @type {number}30*/31goog.dom.xml.MAX_XML_SIZE_KB = 2 * 1024; // In kB323334/**35* Max XML size for MSXML2. Used to prevent potential DoS attacks.36* @type {number}37*/38goog.dom.xml.MAX_ELEMENT_DEPTH = 256; // Same default as MSXML6.394041/**42* Check for ActiveXObject support by the browser.43* @return {boolean} true if browser has ActiveXObject support.44* @private45*/46goog.dom.xml.hasActiveXObjectSupport_ = function() {47if (!goog.userAgent.IE) {48// Avoid raising useless exception in case code is not compiled49// and browser is not MSIE.50return false;51}52try {53// Due to lot of changes in IE 9, 10 & 11 behaviour and ActiveX being54// totally disableable using MSIE's security level, trying to create the55// ActiveXOjbect is a lot more reliable than testing for the existence of56// window.ActiveXObject57new ActiveXObject('MSXML2.DOMDocument');58return true;59} catch (e) {60return false;61}62};636465/**66* True if browser has ActiveXObject support.67* Possible override if this test become wrong in coming IE versions.68* @type {boolean}69*/70goog.dom.xml.ACTIVEX_SUPPORT =71goog.userAgent.IE && goog.dom.xml.hasActiveXObjectSupport_();727374/**75* Creates an XML document appropriate for the current JS runtime76* @param {string=} opt_rootTagName The root tag name.77* @param {string=} opt_namespaceUri Namespace URI of the document element.78* @param {boolean=} opt_preferActiveX Whether to default to ActiveXObject to79* create Document in IE. Use this if you need xpath support in IE (e.g.,80* selectSingleNode or selectNodes), but be aware that the ActiveXObject does81* not support various DOM-specific Document methods and attributes.82* @return {Document} The new document.83* @throws {Error} if browser does not support creating new documents or84* namespace is provided without a root tag name.85*/86goog.dom.xml.createDocument = function(87opt_rootTagName, opt_namespaceUri, opt_preferActiveX) {88if (opt_namespaceUri && !opt_rootTagName) {89throw Error("Can't create document with namespace and no root tag");90}91// If document.implementation.createDocument is available and they haven't92// explicitly opted to use ActiveXObject when possible.93if (document.implementation && document.implementation.createDocument &&94!(goog.dom.xml.ACTIVEX_SUPPORT && opt_preferActiveX)) {95return document.implementation.createDocument(96opt_namespaceUri || '', opt_rootTagName || '', null);97} else if (goog.dom.xml.ACTIVEX_SUPPORT) {98var doc = goog.dom.xml.createMsXmlDocument_();99if (doc) {100if (opt_rootTagName) {101doc.appendChild(102doc.createNode(103goog.dom.NodeType.ELEMENT, opt_rootTagName,104opt_namespaceUri || ''));105}106return doc;107}108}109throw Error('Your browser does not support creating new documents');110};111112113/**114* Creates an XML document from a string115* @param {string} xml The text.116* @param {boolean=} opt_preferActiveX Whether to default to ActiveXObject to117* create Document in IE. Use this if you need xpath support in IE (e.g.,118* selectSingleNode or selectNodes), but be aware that the ActiveXObject does119* not support various DOM-specific Document methods and attributes.120* @return {Document} XML document from the text.121* @throws {Error} if browser does not support loading XML documents.122*/123goog.dom.xml.loadXml = function(xml, opt_preferActiveX) {124if (typeof DOMParser != 'undefined' &&125!(goog.dom.xml.ACTIVEX_SUPPORT && opt_preferActiveX)) {126return new DOMParser().parseFromString(xml, 'application/xml');127} else if (goog.dom.xml.ACTIVEX_SUPPORT) {128var doc = goog.dom.xml.createMsXmlDocument_();129doc.loadXML(xml);130return doc;131}132throw Error('Your browser does not support loading xml documents');133};134135136/**137* Serializes an XML document or subtree to string.138* @param {Document|Element} xml The document or the root node of the subtree.139* @return {string} The serialized XML.140* @throws {Error} if browser does not support XML serialization.141*/142goog.dom.xml.serialize = function(xml) {143// Compatible with IE/ActiveXObject.144var text = xml.xml;145if (text) {146return text;147}148// Compatible with Firefox, Opera and WebKit.149if (typeof XMLSerializer != 'undefined') {150return new XMLSerializer().serializeToString(xml);151}152throw Error('Your browser does not support serializing XML documents');153};154155156/**157* Selects a single node using an Xpath expression and a root node158* @param {Node} node The root node.159* @param {string} path Xpath selector.160* @return {Node} The selected node, or null if no matching node.161*/162goog.dom.xml.selectSingleNode = function(node, path) {163if (typeof node.selectSingleNode != 'undefined') {164var doc = goog.dom.getOwnerDocument(node);165if (typeof doc.setProperty != 'undefined') {166doc.setProperty('SelectionLanguage', 'XPath');167}168return node.selectSingleNode(path);169} else if (document.implementation.hasFeature('XPath', '3.0')) {170var doc = goog.dom.getOwnerDocument(node);171var resolver = doc.createNSResolver(doc.documentElement);172var result = doc.evaluate(173path, node, resolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);174return result.singleNodeValue;175}176// This browser does not support xpath for the given node. If IE, ensure XML177// Document was created using ActiveXObject178// TODO(joeltine): This should throw instead of return null.179return null;180};181182183/**184* Selects multiple nodes using an Xpath expression and a root node185* @param {Node} node The root node.186* @param {string} path Xpath selector.187* @return {(!NodeList<!Node>|!Array<!Node>)} The selected nodes, or empty array188* if no matching nodes.189*/190goog.dom.xml.selectNodes = function(node, path) {191if (typeof node.selectNodes != 'undefined') {192var doc = goog.dom.getOwnerDocument(node);193if (typeof doc.setProperty != 'undefined') {194doc.setProperty('SelectionLanguage', 'XPath');195}196return node.selectNodes(path);197} else if (document.implementation.hasFeature('XPath', '3.0')) {198var doc = goog.dom.getOwnerDocument(node);199var resolver = doc.createNSResolver(doc.documentElement);200var nodes = doc.evaluate(201path, node, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);202var results = [];203var count = nodes.snapshotLength;204for (var i = 0; i < count; i++) {205results.push(nodes.snapshotItem(i));206}207return results;208} else {209// This browser does not support xpath for the given node. If IE, ensure XML210// Document was created using ActiveXObject.211// TODO(joeltine): This should throw instead of return empty array.212return [];213}214};215216217/**218* Sets multiple attributes on an element. Differs from goog.dom.setProperties219* in that it exclusively uses the element's setAttributes method. Use this220* when you need to ensure that the exact property is available as an attribute221* and can be read later by the native getAttribute method.222* @param {!Element} element XML or DOM element to set attributes on.223* @param {!Object<string, string>} attributes Map of property:value pairs.224*/225goog.dom.xml.setAttributes = function(element, attributes) {226for (var key in attributes) {227if (attributes.hasOwnProperty(key)) {228element.setAttribute(key, attributes[key]);229}230}231};232233234/**235* Creates an instance of the MSXML2.DOMDocument.236* @return {Document} The new document.237* @private238*/239goog.dom.xml.createMsXmlDocument_ = function() {240var doc = new ActiveXObject('MSXML2.DOMDocument');241if (doc) {242// Prevent potential vulnerabilities exposed by MSXML2, see243// http://b/1707300 and http://wiki/Main/ISETeamXMLAttacks for details.244doc.resolveExternals = false;245doc.validateOnParse = false;246// Add a try catch block because accessing these properties will throw an247// error on unsupported MSXML versions. This affects Windows machines248// running IE6 or IE7 that are on XP SP2 or earlier without MSXML updates.249// See http://msdn.microsoft.com/en-us/library/ms766391(VS.85).aspx for250// specific details on which MSXML versions support these properties.251try {252doc.setProperty('ProhibitDTD', true);253doc.setProperty('MaxXMLSize', goog.dom.xml.MAX_XML_SIZE_KB);254doc.setProperty('MaxElementDepth', goog.dom.xml.MAX_ELEMENT_DEPTH);255} catch (e) {256// No-op.257}258}259return doc;260};261262263