美文网首页JavaScript < ES5、ES6、ES7、… >
JavaScript 高级程序设计(第19章 E4X)

JavaScript 高级程序设计(第19章 E4X)

作者: yinxmm | 来源:发表于2018-08-19 22:22 被阅读12次

    第19章 E4X

    E4X(ECMAScript for XML)为处理 XML 定义了新的语法,也定义了特定于 XML 的对象。

    1. E4X 的类型

    (1) XML:XML 结构中的任何一个独立的部分。
    (2) XMLList:XML 对象的集合。
    (3) Namespace:命名空间前缀与命名空间 URI 之间的映射。
    (4) QName:由内部名称和命名空间 URI 组成的一个限定名。

    (1) XML类型

    1. XML 的实例可以表现元素、特性、注释、处理指令或文本节点。
    2. XML 类型继承自 Object 类型,因此它也继承了所有对象默认的所有属性和方法。

    创建 XML 对象:

    var x = new XML(); // 创建一个空的 XML 对象
    
    //传入到构造函数中的 XML 字符串会被解析为分层的 XML 对象。
    var x = new XML("<employee position=\"Software Engineer\"><name>Nicholas " +
                    "Zakas</name></employee>");
    
    //传入 DOM 文档或节点,以便它们的数据可以通过 E4X 来表现
    var x = new XML(xmldom);
    
    //使用 XML 字面量将 XML数据直接指定给一个变量。
    var employee = <employee position="Software Engineer">
                        <name>Nicholas C. Zakas</name>
                   </employee>;
    
    1. toXMLString()方法会返回 XML 对象及其子节点的 XML 字符串表示。
    2. toString()方法则会基于不同 XML 对象的内容返回不同的字符串。
    var data = <name>Nicholas C. Zakas</name>;
    alert(data.toString()); //"Nicholas C. Zakas"
    alert(data.toXMLString()); //"<name>Nicholas C. Zakas</name>"
    

    (2) XMLList类型

    XMLList 类型表现 XML 对象的有序集合。

    创建 XMLList 对象:

    //1. 使用 XMLList 构造函数
    var list = new XMLList();
    
    //保存在这个 list 变量中的 XMLList 就包含了两个 XML 对象,分别是两个<item/>元素。
    var list = new XMLList("<item/><item/>");
    
    //2. 使用加号(+)操作符来组合两个或多个 XML 对象,从而创建 XMLList 对象。
     var list = <item/> + <item/> ;
    
    //3. 使用特殊的<>和</>语法来完成
    var list = <><item/><item/></>;
    
    //4. 在解析较大的 XML 结构的过程中捎带着
    被创建出来的。
    var employees = <employees>
            <employee position="Software Engineer">
                <name>Nicholas C. Zakas</name>
            </employee>
            <employee position="Salesperson">
                <name>Jim Smith</name>
            </employee>
        </employees>;
    

    使用方括号语法及位置来访问每个元素

    var firstEmployee = employees.employee[0];
    var secondEmployee = employees.employee[1];
    

    每个 XMLList 对象都有length()方法,用于返回对象中包含的元素对象。

    alert(employees.employee.length()); //2
    

    (3) Namespace 空间

    创建 Namespace 对象:

    var ns = new Namespace();
    var ns = new Namespace("http://www.wrox.com/");////没有前缀的命名空间
    var wrox = new Namespace("wrox", "http://www.wrox.com/");////wrox 命名空间
    
    1. 使用prefixuri 属性来取得 Namespace 对象中的信息。
    alert(ns.uri);//"http://www.wrox.com/"
    alert(ns.prefix);//undefined
    
    1. 如果 XML 字面量中包含命名空间,或者通过 XML 构造函数解析的 XML 字符串中包含命名空间信息, 那么就会自动创建 Namespace 对象
    2. 可以通过前缀namespace()方法来取得对 Namespace 对象的引用。
    var xml = <wrox:root xmlns:wrox="http://www.wrox.com/">
                <wrox:message>Hello World!</wrox:message>
              </wrox:root>;
    var wrox = xml.namespace("wrox");
    alert(wrox.uri);
    alert(wrox.prefix);
    
    1. Namespace 对象的 toString()方法始终会返回命名空间 URI。

    (4) QName类型

    1. 向 QName 构造函数中传 入名称或 Namespace 对象和名称,可以手工创建新的 QName 对象。
    var wrox = new Namespace("wrox", "http://www.wrox.com/");
    var wroxMessage = new QName(wrox, "message"); //表示"wrox:message"
    
    1. uri 属性返回在创 建对象时指定的命名空间的 URI(如果未指定命名空间,则返回空字符串),而localName 属性返回限定名中的内部名称。
    alert(wroxMessage.uri); //"http://www.wrox.com/"
    alert(wroxMessage.localName);       //"message"
    
    1. QName 对象重写了toString() 方法,会以uri::localName形式返回一个字符串,对于前面的例子来说,就是"http://www.wrox. com/::message"。
    2. 在解析 XML 结构时,会为表示相应元素或特性的 XML 对象自动创建 QName 对象。可以使用这个 XML 对象的 name()方法取得与该 XML 对象关联的 QName 对象。
    var xml = < wrox:root xmlns:wrox="http://www.wrox.com/">
                <wrox:message>Hello World!</wrox:message>
              </wrox:root> ;
    var wroxRoot = xml.name();
    alert(wroxRoot.uri);             //"http://www.wrox.com/"
    alert(wroxRoot.localName);       //"root"
    
    1. 使用 setName()方法并传入一个新 QName 对象,可以修改 XML 对象的限定名。
    xml.setName(new QName("newroot"));
    
    1. 如果该名称不属于任何命 名空间,则可以像下面这样使用 setLocalName()方法来修改内部名称:
    xml.setLocalName("newtagname");
    

    2. 一般用法

    1. 可以使用点号加特性或标签名的方式来访问其中不同的层次和结构。每个子元素都是父元素的一个属性,而属性名与元素的内部名称相同。
      (1) 如果子元素只包含文本,则相应的属性只返回文本。
      (2) 如果有多个元素 具有相同的标签名,则会返回 XMLList。
    var employees = <employees>
            <employee position="Software Engineer">
                <name>Nicholas C. Zakas</name>
            </employee>
            <employee position="Salesperson">
                    <name>Jim Smith</name>
            </employee>
    </employees>;
    alert(employees.employee[0].name);//"Nicholas C. Zakas"
    alert(employees.employee[1].name);//"Jim Smith"
    

    (1) 如果你不确定子元素的内 部名称,或者你想访问所有子元素,不管其名称是什么,也可以像下面这样使用星号(*)

    var allChildren = employees.*; //返回所有子元素,不管其名称是什么 
    alert(employees.*[0].name); //"Nicholas C. Zakas"
    

    (2) child()方法将属性名或索引值传递给 child() 方法,也会得到相同的值。

    var firstChild = employees.child(0);//与employees.*[0]相同
    var employeeList = employees.child("employee");//与 employees.employee 相同 
    var allChildren = employees.child("*");//与employees.*相同
    

    (3) children()方法始终返回所有子元素。

    var allChildren = employees.children(); //与employees.*相同
    

    (4) elements()的行为与 child()类似,区别仅在于它只返回表示元素的 XML 对象。

    var employeeList = employees.elements("employee"); //与 employees.employee 相同
    var allChildren = employees.elements("*"); //与employees.*相同
    

    (5) 要删除子元素,可以使用 delete 操作符

    delete employees.employee[0];
    alert(employees.employee.length());     //1
    

    (1) 访问特性

    * 访问特性的方法:
    1. 使用 点语法,为了区分特性名与子元素的标签名,必须在名称前面加上一个@字符
    var employees = <employees>
        <employee position="Software Engineer">
            <name>Nicholas C. Zakas</name>
        </employee>
        <employee position="Salesperson">
            <name>Jim Smith</name>
        </employee>
    </employees>;
    alert(employees.employee[0].@position); //"Software Engineer"
    

    以这种语法访问特性会得到一个表示特性的 XML 对象,对象的 toString()方法始终会返回特性的值。要取得特性的名称,可以使用对象的 name()方法

    1. 使用 child()方法来访问特性,只要传入带有@前缀的特性的名称即可。
    alert(employees.employee[0].child("@position")); //"Software Engineer"
    
    1. 使用attribute()方法并传入特性名,可以只访问 XML 对象的特性,不需要传入带@字符的特性名。
    alert(employees.employee[0].attribute("position")); //"Software Engineer"
    
    *取得 XML 或 XMLList 对象中的所有特性

    可以使用 attributes()方法,这个方法会返回一个表示所有特性的 XMLList 对象。使用这个方法与使用@*

    //下面两种方式都会取得所有特性
    var atts1 = employees.employee[0].@*;
    var atts2 = employees.employee[0].attributes();
    
    *修改特性的值
    employees.employee[0].@position = "Author"; //修改 position 特性
    
    employees.employee[0].@experience = "8 years"; //添加 experience 特性 employees.employee[0].@manager = "Jim Smith"; //添加 manager 特性
    
    *使用 delete 操作符来删除特性
    delete employees.employee[0].@position; //删除 position 特性
    

    (2) 其他节点类型

    1. 在默认情况上,E4X 不会解析注释或处理指令,因此这些部分不会出现在最终的对象层次中。如果想让解析器解析这些部分,可以像下面这样设置 XML 构造函数的下列两个属性。在设置了这两个属性之后,E4X 就会将注释和处理指令解析到 XML 结构中。
    XML.ignoreComments = false;
    XML.ignoreProcessingInstructions = false;
    
    1. nodeKind()方法可以得到 XML 对象表示的类型,该访问可能会返回"text"、"element"、"comment"、
      "processinginstruction"或"attribute"。
      不能在包含多个 XML 对象的 XMLList 上调用 nodeKind()方法;否则,会抛出一个错误。
    1. 取得特定类型的节点:
      (1) attributes():返回 XML 对象的所有特性。
      (2) comments():返回 XML 对象的所有子注释节点。
      (3) elements(tagName):返回 XML 对象的所有子元素。可以通过提供元素的 tagName(标签名)来过滤想要返回的结果。
      (4) processingInstructions(name):返回 XML 对象的所有处理指令。可以通过提供处理指令的 name(名称)来过滤想要返回的结果。
      (5) text():返回 XML 对象的所有文本子节点。
    1. 使用 hasSimpleContent()hasComplexContent()方法,可以确定 XML 对象中是只包含文本, 还是包含更复杂的内容。如果 XML 对象中只包含子文本节点,则前一个方法会返回 true;如果 XML 对 象的子节点中有任何非文本节点,则后一个方法返回 true。

    (3) 查询

    1. 使用两个点,则可以 进一步扩展查询的深度,查询到所有后代节点。
    var allDescendants = employees..*; //取得<employees/>的所有后代节点
    
    1. 取得特定标签的元素,需要将星号替换成实际的标签名。
    var allNames = employees..name; //取得作为<employees/>后代的所有<name/>节点
    
    1. descendants()方法来完成。在不给这个方法传递参数的情况下,它会返回 所有后代节点(与使用..*相同),而传递一个名称作为参数则可以限制结果。
    var allDescendants = employees.descendants(); //所有后代节点
    var allNames = employees.descendants("name"); //后代中的所有<name/>元素
    
    1. 取得所有后代元素中的所有特性
    var allAttributes = employees..@*; //取得所有后代元素中的所有特性 var allAttributes2 = employees.descendants("@*"); //同上
    
    1. 通过用完整的特性名来替换星号达到过滤特性的目的.
    
    var allAttributes = employees..@position; //取得所有 position 特性 var allAttributes2 = employees.descendants("@position"); //同上
    
    1. 指定查询的条件。返回 position 特性值为 "Salesperson"的所有<employee/>元素,可以使用下面的查询:
    var salespeople = employees.employee.(@position == "Salesperson");
    
    1. 修改 XML 结构中的某一部分。例如,可以将第一位销售员(salesperson) 的 position 特性修改为"Senior Salesperson",代码如下:
    employees.employee.(@position == "Salesperson")[0].@position= "Senior Salesperson";
    

    8.parent()方法能够在 XML 结构中上溯,这个方法会返回一个 XML 对象,表示当前 XML 对象 的父元素。

    var employees2 = employees.employee.parent();//变量 employees2 中包含着与变量 employees 相同的值。
    

    (4) 构建和操作XML

    1. 可以在XML字面量中嵌入 JavaScript 变量,语法是使用花括号({})
    var tagName = "color";
    var color = "red";
    var xml = <{tagName}>{color}</{tagName}>;
    alert(xml.toXMLString());     //"<color>red</color>
    
    1. E4X 也支持使用标准的 JavaScript 语法来构建完整的 XML 结构。
    var employees = <employees/>;
    employees.employee.name = "Nicholas C. Zakas";
    employees.employee.@position = "Software Engineer";
    
    //最终构建的 XML 结构
    <employees>
        <employee position="Software Engineer">
            <name >Nicholas C. Zakas</name>
         </employee>
    </employees>
    
    
    1. 用加号操作符也可以再添加一个<employee/>元素
    employees.employee += <employee position="Salesperson">
                              <name>Jim Smith</name>
                          </employee>;
    //最终构建的 XML 结构
    <employees>
          <employee position="Software Engineer">
              <name>Nicholas C. Zakas</name>
          </employee>
          <employee position="Salesperson">
              <name>Jim Smith</name>
          </employee>
    </employees>
    

    4.类似 DOM 的方法

    (1) appendChild(child):将给定的 child 作为子节点添加到 XMLList 的末尾。
    (2) copy():返回 XML 对象副本。
    (3) insertChildAfter(refNode, child):将 child 作为子节点插入到 XMLList 中 refNode 的后面。
    (4) insertChildBefore(refNode, child):将 child 作为子节点插入到 XMLList 中 refNode 的前面。
    (5) prependChild(child):将给定的 child 作为子节点添加到 XMLList 的开始位置。
    (6) replace(propertyName, value):用 value 值替换名为 propertyName 的属性,这个属性 可能是一个元素,也可能是一个特性。
    (7) setChildren(children):用 children 替换当前所有的子元素,children 可以是 XML 对 象,也可是 XMLList 对象。

    (5) 解析和序列化

    1. 与 XML 解析相关的设置有如下三个。
    • ignoreComments:表示解析器应该忽略标记中的注释。默认设置为 true。
    • ignoreProcessingInstructions:表示解析器应该忽略标记中的处理指令。默认设置为 true。
    • ignoreWhitespace:表示解析器应该忽略元素间的空格,而不是创建表现这些空格的文本节
      点。默认设置为 true。
    1. 与 XML 数据序列化相关的设置有如下两个。
    • prettyIndent:表示在序列化 XML 时,每次缩进的空格数量。默认值为 2。
    • prettyPrinting:表示应该以方便人类认读的方式输出 XML,即每个元素重起一行,而且子元素都要缩进。默认设置为 true。

    这两个设置将影响到 toString()和 toXMLString()的输出。

    1. 以上五个设置都保存在 settings 对象中,通过 XML 构造函数的 settings()方法可以取得这个对象。
    var settings = XML.settings();
    alert(settings.ignoreWhitespace);//true
    alert(settings.ignoreComments);//true
    
    1. setSettings()方法中传入包含全部 5 项设置的对象,可以一次性指定所有设置。
    var settings = XML.settings();
    XML.prettyIndent = 8;
    XML.ignoreComments = false;
    //执行某些处理
    XML.setSettings(settings); //重置前面的设置
    
    1. defaultSettings()方法则可以取得一个包含默认设置的对象,因此任何时候都可以使用下面的代码重置设置。
    XML.setSettings(XML.defaultSettings());
    

    (6) 命名空间

    1. 使用 setNamespace()并传入 Namespace 对象,也可以为给定元素设置命名空间。
    var messages = <messages>
            <message>Hello world!</message>
    </messages>;
    messages.setNamespace(new Namespace("wrox", "http://www.wrox.com/"));
    
     <wrox:messages xmlns:wrox="http://www.wrox.com/">
            <message>Hello world!</message>
      </wrox:messages>
    
    1. 如果只想添加一个命名空间声明,而不想改变元素,可以使用 addNamespace()方法并传入 Namespace 对象。
    messages.addNamespace(new Namespace("wrox", "http://www.wrox.com/"));
    
    <messages xmlns:wrox="http://www.wrox.com/">
            <message>Hello world!</message>
    </messages>
    
    1. removeNamespace()方法并传入 Namespace 对象,可以移除表示特定命名空间前缀和 URI的命名空间声明。
    messages.removeNamespace(new Namespace("wrox", "http://www.wrox.com/"));
    
    1. 返回与节点相关的 Namespace 对象的数组
      (1) namespaceDeclarations()返回在给定节点上声明的所有命名空间的数组。
      (2) inScopeNamespaces() 返回位于给定节点 作用域中(即包括在节点自身和祖先元素中声明的)所有命名空间的数组。
    var messages = <messages xmlns:wrox="http://www.wrox.com/">
            <message>Hello world!</message>
    </messages>;
    
    alert(messages.namespaceDeclarations()); //"http://www.wrox.com"
    alert(messages.inScopeNamespaces()); //",http://www.wrox.com"
    alert(messages.message.namespaceDeclarations()); //""
    alert(messages.message.inScopeNamespaces()); //",http://www.wrox.com"
    
    1. 使用双冒号(::)也可以基于 Namespace 对象来查询 XML 结构中具有特定命名空间的元素。
    // 取得包含在 wrox 命名空间中的所有<message/>元素
    var messages = <messages xmlns:wrox="http://www.wrox.com/">
        <wrox:message>Hello world!</message>
    </messages>;
    var wroxNS = new Namespace("wrox", "http://www.wrox.com/");
    var wroxMessages = messages.wroxNS::message;
    
    1. 以为某个作用域中的所有 XML 对象设置默认命名空间。为此,要使用default xml namespace语句,并将一个 Namespace 对象或一个命名空间 URI 作为值赋给它。
    default xml namespace = "http://www.wrox.com/";
    function doSomething(){
    //只为这个函数设置默认的命名空间
    default xml namespace = new Namespace("your", "http://www.yourdomain.com");
    }
    

    3. 其他变化

    1. 引入了for-each-in 循环,以便迭代遍历每一个属性并返回属性的值。
    var employees = <employees>
                            <employee position="Software Engineer">
                                <name>Nicholas C. Zakas</name>
                            </employee>
                            <employee position="Salesperson">
                                <name>Jim Smith</name>
                            </employee>
                    </employees>;
    
    for each (var child in employees){
        alert(child.toXMLString());
    }
    
    for each (var attribute in employees.@*){ //遍历特性 alert(attribute);
    }
    
    1. E4X 还添加了一个全局函数,名叫 isXMLName()。这个函数接受一个字符串,并在这个字符串是 元素或特性的有效内部名称的情况下返回 true。
    alert(isXMLName("color"));           //true
    alert(isXMLName("hello world"));     //false
    
    1. E4X 对标准 ECMAScript 的最后一个修改是typeof 操作符。在对 XML 对象或 XMLList 对象使用 这个操作符时,typeof 返回字符串"xml"。
    var xml = new XML();
    var list = new XMLList();
    var object = {};
    alert(typeof xml); //"xml" 
    alert(typeof list); //"xml" 
    alert(typeof object); //"object"
    

    4. 全面启用 E4X

    要想完整地启用 E4X,需要将<script>标签的 type 特性设置为 2
    "text/javascript;e4x=1"

    相关文章

      网友评论

        本文标题:JavaScript 高级程序设计(第19章 E4X)

        本文链接:https://www.haomeiwen.com/subject/kwuhiftx.html