⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmltools.js

📁 javascript 很酷的类库
💻 JS
📖 第 1 页 / 共 5 页
字号:
        element.setAttribute(propName, values[propName]);    }},// XPath // ---------------------------------------------------------------------------------------// make all namespaces declared on the document element available under the same prefix used in// the document itself, and make the default namespace, if there is one, available as// "default".  "namespaces" can be passed it to avoid redeclaration of existing prefixes._makeIEDefaultNamespaces : function (doc, namespaces) {    var buffer = isc.SB.create(),        docElement = doc.documentElement,        namespaces = namespaces || isc.emptyObject,        defaultNamespace;    // if it hasn't been specified explicitly, try to figure out the default namespaces    // NOTE: default is a keyword in IE    if (!namespaces["default"]) {        defaultNamespace = this._deriveDefaultNamespace(docElement);        if (defaultNamespace) buffer.append('xmlns:default="', defaultNamespace, '" ');    }    // add all the namespaces on the document element    var attrs = doc.documentElement.attributes;    for (var i = 0; i < attrs.length; i++) {        var attr = attrs[i],            prefix = attr.prefix;        // NOTE: attr.name is the full name of the attribute, including prefix, so for a        // non-default namespace declaration attr.name will be eg xmlns:somePrefix        if (prefix == "xmlns" && prefix != attr.name) {            // don't redefine already defined selection namespaces            // NOTE: baseName is IE-only            if (namespaces[attr.baseName] != null) continue;            buffer.append(attr.name, '="', attr.value, '" ');        }    }    return buffer.toString();},// Method to determine the "default" namespace by looking at the namespaceURI of the document// element or (if appropriate) children of the documentElement.// Used in IE as part of _makeIEDefaultNamespaces()// // Note: This handles the common case where the document element declares a namespace, but // is itself in a different namespace_deriveDefaultNamespace : function (docElement) {                var shouldLog = this.logIsDebugEnabled("xmlSelect");    if ((docElement.prefix == null || isc.isAn.emptyString(docElement.prefix)) &&         docElement.namespaceURI)     {        if (shouldLog) {            this.logWarn("using docElement ns, prefix: " + docElement.prefix,                               "xmlSelect");        }        return docElement.namespaceURI;                                                      } else if (docElement.firstChild) {        var defaultNamespace        for (var i = 0; i < docElement.childNodes.length; i++) {            var childNode = docElement.childNodes[i];            // text nodes show up in the childNodes collection in Safari            if (childNode.nodeType == 3) continue;                        var nsURI = childNode.namespaceURI;                            if (!nsURI) break;            if (childNode.prefix == null || isc.isAn.emptyString(childNode.prefix)) {                defaultNamespace = childNode.namespaceURI;                break;            }        }        if (defaultNamespace != null) {            if (shouldLog) {                this.logDebug("using default namespace detected on child: " +                               defaultNamespace, "xmlSelect");            }        }        // if there is no default namespace, still define the namespace prefix "default" as        // the document element's namespace, for conveniece        if (defaultNamespace == null && docElement.namespaceURI) {            defaultNamespace = docElement.namespaceURI;            if (shouldLog) {                this.logDebug("using document element's namespace as default namespace: " +                               defaultNamespace, "xmlSelect");            }        }        // if no appropriate default namespace could be derived, still define one, so that        // using "default:" doesn't create a JS error.  This allows an XPath like        // "//default:item|//item" to handle both namespaced and non-namespaced RSS feeds        if (!defaultNamespace) defaultNamespace = "http://openuri.org/defaultNamespace";        return defaultNamespace;    }},//> @classMethod xmlTools.selectObjects()   (A)// Applies an XPath expression to JavaScript objects, returning matching objects.// <P>// Both child and attribute names are interpreted as property names, and array access notation// can be used to select elements from Arrays.  For example:<pre>//     var results = {//        searchResults:[//            { title:"Page One", relevance:6.3 },//            { title:"Page Two", relevance:5.2, //              summary: "Summary of Page One" }//        ]//     };////     // returns the "searchResults" two-item Array//     isc.XMLTools.selectObjects(results, "/searchResults");////     // returns the first item under "searchResults", in an Array (NOTE: in XPath, Array//     // index starts at 1, not 0)//     isc.XMLTools.selectObjects(results, "/searchResults[1]");////     // returns ["Page One"]//     isc.XMLTools.selectObjects(results, "/searchResults[1]/title");////     // also returns ["Page One"]//     isc.XMLTools.selectObjects(results, "/searchResults[1]@title");// </pre>// A limited form of XPath "predicates", that is, expressions with brackets that filter// returned objects, is allowed.  A predicate can be either:// <ul>// <li> a number only, eg [5], for Array access// <li> the XPath function call "last()", eg [last()], to retrieve the last item// <li> a property name (*without* any leading "@"), meaning that the property contains a value//      that is considered "true" in JavaScript.  For example: [summary]// <li> a property name, comparison operator, and either a number or String literal, for//      example, [name = "bob"].  In this case the property can also be the XPath function//      position(), for example, [position() > 5]// </ul>// Some examples of using simple predicates with the sample data above:// <pre>//     // returns an Array with only the first result//     isc.XMLTools.selectObjects(results, "/searchResults[relevance > 5.5]");// //     // return an Array with only the second result, since the first has no summary//     isc.XMLTools.selectObjects(results, "/searchResults[summary]");// </pre>// Details of the XPath -> Objects mapping:// <ul> // <li> JavaScript Object properties are considered element children, and text children do not//      exist (in the XML model, text children exist *between* element children, but nothing//      exists between JavaScript properties)// <li> The contents of Array-valued properties are considered immediate element children (this//      is consistent with the predicate "[5]" acting like Array access)// <li> "*" in XML selects all element children, so "*" in Object XPath selects the values of//      all properties, that is, +link{classMethod:isc.getValues(),isc.getValues(object)}, except//      that Array-valued properties are "flattened" into the returned list.// </ul>//// @param object (Object) Object to select results from// @param xPath (String) XPath expression// @return (Array) Array of matching objects, or null for no match// @visibility external//<_$leftBracket : "[",selectObjects : function (object, xPath, singleValue) {    if (isc.contains("|")) {        var subExpressions = xPath.split(/|/),            results = [];        for (var i = 0; i < subExpressions.length; i++) {            results.addList(this.selectObjects(subExpressions[i], object));        }        return results;    }    // canonicalize to an Array    var objects = isc.isAn.Array(object) ? object : [object];    if (xPath != isc.slash) {        if (isc.startsWith(xPath, isc.slash)) xPath = xPath.substring(1);        var segments = xPath.split(/[\/@]/);        //this.logWarn("segments: " + this.echo(segments));        objects = this._selectObjects(segments, objects, isc.slash);    }    // return the single value, or null on no match    if (singleValue && objects.length <= 1) return objects[0];    return objects;},_selectObjects : function (segments, objects, path) {    var segment = segments[0];    segments = segments.length > 1 ? segments.slice(1) : null;    //this.logWarn("at path: " + path +     //             ", applying segment: '" + segment +     //             "' to " + this.echoLeaf(objects));    if (objects == null) return null;    // break segment into nodeTest and predicate    var predicate,         nodeTest = segment,        bracketIndex = segment.indexOf(this._$leftBracket);            if (bracketIndex != -1) {        nodeTest = segment.substring(0, bracketIndex);        // extract predicate expression (NOTE: assume one only)        predicate = segment.substring(bracketIndex + 1, segment.length-1);        //this.logWarn("nodeTest: " + nodeTest + ", predicate: " + predicate);    }    // apply nodeTest to each node    var resultObjects = [];    for (var i = 0; i < objects.length; i++) {        var object = objects[i];            // apply the node test        if (nodeTest != isc.star) {            object = object[nodeTest];        } else {            var properties = isc.getValues(object);            object = [];            for (var i = 0; i < properties.length; i++) {                if (!isc.isAn.Array(properties[i])) object.add(properties[i]);                else object.addList(properties[i]);            }        }        //this.logWarn("nodeTest: " + nodeTest + ", result: " + this.echoLeaf(object));        if (object == null) continue;        if (!isc.isAn.Array(object)) {            resultObjects.add(object);        } else {            resultObjects.addList(object);        }    }    // filter result by predicate    if (predicate) {        // canonicalize object to an Array if we have a predicate        var predResult = this._applyPredicateExpression(resultObjects, predicate);                //this.logWarn("predicate expression: '" + predicate +        //             "' applied to: " + this.echoLeaf(resultObjects) +        //             ", with result: " + this.echoLeaf(predResult));        resultObjects = predResult;    }        if (segments == null || segments.length == 0) return resultObjects;    //this.logWarn("recursing with remaining path: " + segments.join("/"));    // recurse if there are more segments    path += segment + isc.slash;    return this._selectObjects(segments, resultObjects, path);},_applyPredicateExpression : function (objects, expr) {    // check for simple index (this will actually accept anything that starts with a    // number)    var index = parseInt(expr);    if (!isNaN(index)) {        // xPath indices are 1-based        return [objects[index - 1]];    }    if (expr == "last()") return [objects.last()];    // NOTE: not making property first char vs remaining chars distinction in XML "QName"    // identifier.  Allowing () as a quick way to allow the position() function    var parts = expr.match(/^([a-zA-Z_0-9:\-\.\(\)]*)\s*(<|>|!=|=|<=|>=|)\s*(.*)$/),        property, operator, value;    //this.logWarn("predicate parts: " + parts);    if (parts == null) {        // assume just an identifier        if (!expr.match(/^[a-zA-Z_0-9:\-\.]*$/)) {            this.logWarn("couldn't parse predicate expression: " + expr);            return null;        }        property = expr;    } else {        property = parts[1], // parts[0] is the entire match        operator = parts[2],        value = parts[3];    }    // convert this simple expression to a JavaScript expression we can apply to each object        // XPath uses single = operator    if (operator == "=") operator = "==";    // XPath uses functions for true and false literals    if (value == "true()") value = true;    else if (value == "false()") value = false;    // support the position() function specially, by passing in params    if (property == "position()") property = "position";    //this.logWarn("property: " + property + ", operator: " + operator + ", value: " + value);    var predFunc = new Function ("item,position",         "return " +             (property != "position" ? "item." : "") + property +             (operator ? operator + value : ""));    // apply the function to each object    var matchingObjects = [];    //this.logWarn("predicate function: " + predFunc);    for (var i = 0; i < objects.length; i++) {        if (predFunc(objects[i], i+1)) matchingObjects.add(objects[i]);    }    return matchingObjects;},//> @classMethod XMLTools.selectNodes()// Retrieve a set of nodes from an XML element or document based on an XPath expression.// <P>// If the target document is namespaced, namespace prefixes declared in the document element of// the target document will be available, as well as the default namespace, if declared, under// the prefix "default".// <P>// To declare your own namespace prefixes, provide a prefix to URI mapping as a simple JS// Object, for example:// <pre>//   {//      az : "http://webservices.amazon.com/AWSECommerceService/2005-03-23",//      xsd : "http://www.w3.org/2001/XMLSchema"//   }// </pre>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -