乐趣区

JS学习笔记第19章E4X

1、E4X 的类型

1.1 XML 类型

1、创建 XML 对象的方法

(1)调用构造函数:

var x = new XML();
var x = new XML("<employee position=\"Software Engineer\"><name>Nicholas" +"Zakas</name></employee>");

(2)使用 XML 字面量将 XML 数据直接指定给一个变量。XML 字面量就是嵌入到 JavaScript 代码中的 XML 代码。

var employee = <employee position="Software Engineer">
                        <name>Nicholas C. Zakas</name>
                </employee>;

2、XML 类型的 toXMLString() 方法 会返回 XML 对象及其子节点的 XML 字符串表示。另一方面,该类型的 toString()方法 则会基于不同 XML 对象的内容返回不同的字符串。

var data = <name>Nicholas C. Zakas</name>;
alert(data.toString()); //"Nicholas C. Zakas"
alert(data.toXMLString()); //"<name>Nicholas C. Zakas</name>"

1.2 XMLList 类型

XMLList 类型表现 XML 对象的有序集合。XMLList 的 DOM 对等类型是 NodeList。

1、创建 XMLList 对象的方法
(1)可以向其中传入一个待解析的 XML 字符串;

var list = new XMLList("<item/><item/>");

(2)还可以使用加号(+)操作符来组合两个或多个 XML 对象,从而创建 XMLList 对象。

var list = <item/> + <item/> ;  // 这个例子使用加号操作符组合了两个 XML 字面量,结果得到一个 XMLList。

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

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

(3)XMLList 对象的 toString()和 toXMLString()方法返回相同的字符串值,也就是将其包含的 XML 对象序列化之后再拼接起来的结果。

1.3 Namespace 类型

使用 Namespace 对象来表现命名空间。通常,Namespace 对象是用来映射命名空间前缀和命名空间 URI 的。
1、创建 Namespace 对象的方法

(1)使用 Namespace 构造函数,传入 URI 或前缀加 URI,就可以初始化 Namespace 对象

var ns = new Namespace();
var ns = new Namespace("http://www.wrox.com/"); // 没有前缀的命名空间
var wrox = new Namespace("wrox", "http://www.wrox.com/"); //wrox 命名空间

(2)通过 XML 构造函数解析的 XML 字符串中包含命名空间信息,那么就会自动创建 Namespace 对象。然后,就可以通过前缀和 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);

2、可以使用 prefix 和 uri 属性来取得 Namespace 对象中的信息

var ns = new Namespace("http://www.wrox.com/"); // 没有前缀的命名空间
var wrox = new Namespace("wrox", "http://www.wrox.com/"); //wrox 命名空间
alert(ns.uri); //"http://www.wrox.com/"
alert(ns.prefix); //undefined
alert(wrox.uri); //"http://www.wrox.com/"
alert(wrox.prefix); //"wrox"

3、Namespace 对象的 toString()方法始终会返回命名空间 URI

1.4 QName 类型

QName 类型表现的是 XML 对象的限定名,即命名空间与内部名称的组合。

1、创建 QName 对象的方法

(1)向 QName 构造函数中传入名称或 Namespace 对象和名称,可以手工创建新的 QName 对象。

var wrox = new Namespace("wrox", "http://www.wrox.com/");
var wroxMessage = new QName(wrox, "message"); // 表示 "wrox:message"

创建了 QName 对象之后,可以访问它的两个属性:uri 和 localName。其中,uri 属性返回在创建对象时指定的命名空间的 URI(如果未指定命名空间,则返回空字符串),而 localName 属性返回限定名中的内部名称。

alert(wroxMessage.uri); //"http://www.wrox.com/"
alert(wroxMessage.localName); //"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"

2、(1)使用 setName()方法并传入一个新 QName 对象,可以修改 XML 对象的限定名。

xml.setName(new QName("newroot"));

(2)如果该名称不属于任何命名空间,则可以像下面这样使用 setLocalName()方法来修改内部名称。

xml.setLocalName("newtagname");

2、一般用法

1、使用 点号加特性或标签名的方式 来访问其中不同的层次和结构。每个子元素都是父元素的一个属性,而属性名与元素的内部名称相同。

var employee = <employee position="Software Engineer">
<name>Nicholas C. Zakas</name>
</employee>;
alert(employee.name); //"Nicholas C. Zakas"、

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

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

3、还可以使用 child()方法 。将属性名或索引值传递给 child() 方法,也会得到相同的值。

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

4、为了再方便一些,还有一个 children() 方法始终返回所有子元素;

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

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

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

6、要删除子元素,可以使用 delete 操作符

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

2.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"

(2)使用 child() 方法 来访问特性,只要传入带有 @前缀的特性的名称即可

alert(employees.employee[0].child("@position")); //"Software Engineer"

(3)使用 attribute() 方法 并传入特性名,可以只访问 XML 对象的特性。与 child()方法不同,使用 attribute()方法时,不需要传入带 @字符的特性名。

alert(employees.employee[0].attribute("position")); //"Software Engineer"

2、要取得 XML 或 XMLList 对象中的所有特性,可以使用 attributes()方法。这个方法会返回一个表示所有特性的 XMLList 对象。使用这个方法与使用 @* 的结果相同,如下面的例子所示。

// 下面两种方式都会取得所有特性
var atts1 = employees.employee[0].@*;
var atts2 = employees.employee[0].attributes();

3、对特性的操作

(1)修改

employees.employee[0].@position = "Author"; // 修改 position 特性

(2)增加

employees.employee[0].@experience = "8 years"; // 添加 experience 特性
employees.employee[0].@manager = "Jim Smith"; // 添加 manager 特性

(3)删除

delete employees.employee[0].@position; // 删除 position 特性

2.2 其他节点类型

1、E4X 定义了表现 XML 文档中所有部分的类型,包括注释和处理指令。在默认情况上,E4X 不会解析注释或处理指令,因此这些部分不会出现在最终的对象层次中。如果想让解析器解析这些部分,可以像下面这样设置 XML 构造函数的下列两个属性。

XML.ignoreComments = false;
XML.ignoreProcessingInstructions = false;
// 在设置了这两个属性之后,E4X 就会将注释和处理指令解析到 XML 结构中。

2、使用 nodeKind() 方法 可以得到 XML 对象表示的类型,该访问可能会返回 ”text”、“element”、“comment”、”processinginstruction” 或 ”attribute”。

3、可以只取得特定类型的节点,而这就要用到下列方法:

  • attributes():返回 XML 对象的所有特性。
  • comments():返回 XML 对象的所有子注释节点。
  • elements(tagName):返回 XML 对象的所有子元素。可以通过提供元素的 tagName(标签名)来过滤想要返回的结果。
  • processingInstructions(name):返回 XML 对象的所有处理指令。可以通过提供处理指令的 name(名称)来过滤想要返回的结果。
  • text():返回 XML 对象的所有文本子节点。

4、使用 hasSimpleContent()hasComplexContent()方法,可以确定 XML 对象中是只包含文本,还是包含更复杂的内容。如果 XML 对象中只包含子文本节点,则前一个方法会返回 true;如果 XML 对象的子节点中有任何非文本节点,则后一个方法返回 true。来看下面的例子。

alert(employees.employee[0].hasComplexContent()); //true
alert(employees.employee[0].hasSimpleContent()); //false
alert(employees.employee[0].name.hasComplexContent()); //false
alert(employees.employee[0].name.hasSimpleContent()); //true

2.3 查询

1、像下面这样使用两个点,则可以进一步扩展查询的深度,查询到所有后代节点。

var allDescendants = employees..*; // 取得 <employees/> 的所有后代节点

2、使用 descendants()方法来完成。在不给这个方法传递参数的情况下,它会返回所有后代节点(与使用..* 相同),而传递一个名称作为参数则可以限制结果。

var allDescendants = employees.descendants(); // 所有后代节点
var allNames = employees.descendants("name"); // 后代中的所有 <name/> 元素

3、可以取得所有后代元素中的所有特性,方法是使用下列任何一行代码。

var allAttributes = employees..@*; // 取得所有后代元素中的所有特性
var allAttributes2 = employees.descendants("@*"); // 同上

4、完整的特性名来替换星号达到过滤特性的目的

var allAttributes = employees..@position; // 取得所有 position 特性
var allAttributes2 = employees.descendants("@position"); // 同上

5、除了访问后代元素之外,还可以指定查询的条件。

返回 position 特性值为 "Salesperson" 的所有 <employee/> 元素,可以使用下面的查询:var salespeople = employees.employee.(@position == "Salesperson");

6、使用 parent() 方法能够在 XML 结构中上溯,这个方法会返回一个 XML 对象,表示当前 XML 对象的父元素。如果在 XMLList 上调用 parent()方法,则会返回列表中所有对象的公共父元素。

var employees2 = employees.employee.parent();

2.4 构建和操作 XML

1、将 XML 数据转换成 XML 对象的方式:

(1)将 XML 字符串传递到 XML 构造函数中;

(2)使用 XML 字面量;

2、除了上面介绍的基本的 XML 构建语法之外,还有一些类似 DOM 的方法,简介如下。

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

2.5 解析和序列化

E4X 将解析和序列化数据的控制放在了 XML 构造函数的一些设置当中。

1、与 XML 解析相关的设置有如下三个。

  • ignoreComments:表示解析器应该忽略标记中的注释。默认设置为 true。
  • ignoreProcessingInstructions:表示解析器应该忽略标记中的处理指令。默认设置为 true。
  • ignoreWhitespace:表示解析器应该忽略元素间的空格,而不是创建表现这些空格的文本节点。默认设置为 true。

这三个设置会影响对传入到 XML 构造函数中的字符串以及 XML 字面量的解析。

2、另外,与 XML 数据序列化相关的设置有如下两个。

  • prettyIndent:表示在序列化 XML 时,每次缩进的空格数量。默认值为 2。
  • prettyPrinting:表示应该以方便人类认读的方式输出 XML,即每个元素重起一行,而且子元素都要缩进。默认设置为 true

以上五个设置都保存在 settings 对象中,通过 XML 构造函数的 settings()方法可以取得这个对象

var settings = XML.settings();
alert(settings.ignoreWhitespace); //true
alert(settings.ignoreComments); //true

3、使用 defaultSettings()方法则可以取得一个包含默认设置的对象,因此任何时候都可以使用下面的代码重置设置。

XML.setSettings(XML.defaultSettings());

2.6 命名空间

1、调用 setNamespace()方法后,相应的命名空间只会应用到调用这个方法的元素;

2、如果只想添加一个命名空间声明,而不想改变元素,可以使用 addNamespace()方法并传入 Namespace 对象;

3、调用 removeNamespace()方法并传入 Namespace 对象,可以移除表示特定命名空间前缀和 URI 的命名空间声明;注意,必须传入丝毫不差的表示命名空间的 Namespace 对象;

4、有两个方法可以返回与节点相关的 Namespace 对象的数组:namespaceDeclarations()和 inScopeNamespaces()。namespaceDeclarations()返回在给定节点上声明的所有命名空间的数组,inScopeNamespaces()返回位于给定节点作用域中(即包括在节点自身和祖先元素中声明的)所有命名空间的数组。

5、使用双冒号(::)也可以基于 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;

这里的双冒号表示返回的元素应该位于其中的命名空间。注意,这里使用的是 JavaScript 变量,而不是命名空间前缀。

6、可以为某个作用域中的所有 XML 对象设置默认命名空间。为此,要使用 default xml namespace 语句,并将一个 Namespace 对象或一个命名空间 URI 作为值赋给它。

3、其他变化

1、引入了 for-each-in 循环,以便迭代遍历每一个属性并返回属性的值。

2、4X 还添加了一个全局函数,名叫 isXMLName()。这个函数接受一个字符串,并在这个字符串是元素或特性的有效内部名称的情况下返回 true。在使用未知字符串构建 XML 数据结构时,这个函数可以为开发人员提供方便。

alert(isXMLName("color")); //true
alert(isXMLName("hello world")); //false

3、E4X 对标准 ECMAScript 的最后一个修改是 typeof 操作符。在对 XML 对象或 XMLList 对象使用这个操作符时,typeof 返回字符串 ”xml”。但在对其他对象使用这个操作符时,返回的都是 ”object”.

4、全面启用 E4X

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

<script type="text/javascript;e4x=1" src="e4x_file.js"></script>
退出移动版