JavaScript < ES5、ES6、ES7、… >

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

2018-08-19  本文已影响12人  yinxmm

第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"

上一篇下一篇

猜你喜欢

热点阅读