因为自己选修了XML这门课,所以想现在就开始学习。
文中用到的xml:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="web">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
xml与html
xml
和html
其实并没有太大关系,html
经常被用来显示数据,让用户直观的看到效果,而xml
被用来传输和储存数据,xml
的写法是类似于html
的,但xml
中的标签都是自定义标签
。
xml的文档结构也是类似于html的DOM树结构。
语法
基本结构:
在文档开头需要首先声明是xml文档:
<?xml version="1.0" encoding="UTF-8"?>
xml中必须要有根元素,类似于:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<child>
<subchild></subchild>
</child>
<secondchild></secondchild>
</root>
root
就是根元素,根据划分有一层一层的子元素。
xml中所有标签都必须要有闭合标签。
xml中空格不会被删减。
实体引用:
xml实体引用:
>; | > |
---|---|
<; | < |
&; | & |
&apos; | ’ |
"; | " |
在 XML 中,只有字符 "<"
和 "&"
确实是非法的,必须用实体引用代替。
css
xml文档中的元素也可以用css来决定样式,我们需要引用css文件:
<?xml-stylesheet href="file.css" type="text/css"?>
DOM
xml
的DOM
可以根据html
的DOM
来学习,基本功能都是一样的。事先了解html的DOM会更容易理解。
如何获取xml
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xhttp=new XMLHttpRequest();
}
else
{
// IE6, IE5 浏览器执行代码
xhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.open("GET","test.xml",false);//创建一个新的请求,带有请求方法、URL、验证信息
xhttp.send();//将请求发送至服务器
xmlDoc=xhttp.responseXML;//定义变量接收返回的信息
更多的可以去看看我之前写的AJAX部分:AJAX学习
这样我们就获得了xml结构的数据。
属性和方法
属性:
x.nodeName
: x 的名称x.nodeValue
:x 的值x.nodeType
:x的节点类型x.parentNode
: x 的父节点x.childNodes
:x 的子节点x.attributes
: x 的属性节点x.firstChild
:x的第一个子节点x.lastChild
:x的最后一个子节点x.nextSibling
:x的下一个兄弟节点x.previousSibling
:x的上一个兄弟节点
方法:
x.appendChild(node)
: 向 x 插入子节点x.removeChild(node)
:从 x 删除子节点x.getAttributeNode()
:返回x节点的某属性节点x.getAttribute()
:返回x节点的某属性值
节点
节点类型
- 文档节点:整个文档就是一个文档节点
- 元素节点:xml元素
- 文本节点:包含在xml元素中的文本
- 属性节点:xml元素属性
- 注释节点:注释
节点属性
节点有三个重要的属性:
- nodeName:节点名称
- nodeValue:节点的值
- nodeType:节点类型
nodeName
:
元素节点
的 nodeName与标签名相同
属性节点
的 nodeName 是属性的名称
文本节点
的 nodeName 永远是#text
文档节点
的 nodeName 永远是#document
document.write(xmlDoc.nodeName+'</br>');//文档节点的nodeName
document.write(xmlDoc.documentElement.nodeName+'</br>');//根节点的nodeName
document.write(xmlDoc.getElementsByTagName("title")[0].nodeName+'</br>');//第一个title元素节点的nodeName
document.write(xmlDoc.getElementsByTagName("title")[0].attributes[0].nodeName+'</br>');//第一个title元素节点的第一个属性节点的nodeName
document.write(xmlDoc.getElementsByTagName("title")[0].firstChild.nodeName);
nodeValue
:
元素节点的
nodeValue
是undefined
文本节点的nodeValue
是文本本身
属性节点的nodeValue
是属性的值
document.write(xmlDoc.nodeName+'(value:'+xmlDoc.nodeValue+')'+'</br>');//文档节点的nodeValue
document.write(xmlDoc.documentElement.nodeName+'(value:'+xmlDoc.documentElement.nodeValue+')'+'</br>');//根节点的nodeValue
var x=xmlDoc.documentElement.childNodes[1].childNodes[1];//第一个title元素节点
document.write(x.nodeName+'(value:'+x.nodeValue+')'+'</br>');//第一个title元素节点的nodeValue
document.write(x.attributes[0].nodeName+'(value:'+x.attributes[0].nodeValue+')'+'</br>');//第一个title元素节点的第一个属性节点的nodeValue
document.write(x.firstChild.nodeName+'(value:'+x.firstChild.nodeValue+')');//第一个title元素节点的文本节点的nodeValue
到这里为什么我的childNodes是选取的[1]而不是[0]?
可以看我的另一篇:XML获取节点时多出来#text
nodeType
:
节点类型 | nodeType |
---|---|
元素 | 1 |
属性 | 2 |
文本 | 3 |
注释 | 8 |
文档 | 9 |
对节点的操作
改变值
- 改变
文本节点
的值:用文本节点的nodeValue
属性 - 改变
属性节点
的值:用setAttribute()
方法设置属性值或用属性节点的nodeValue
属性
//改变元素的值其实就是改变元素中文本节点的值
x=xmlDoc.getElementsByTagName("title")[0];//获取第一个title
console.log(x.childNodes[0].nodeValue);
x.childNodes[0].nodeValue='hello world';
console.log(x.childNodes[0].nodeValue);
//改变属性节点的值
console.log(x.getAttribute('lang'));//输出title节点属性为lang的值
x.setAttribute('lang','fun');
console.log(x.getAttribute('lang'));
//用nodeValue重写上面方法
//getAttribute()/setAttribute()=getAttributeNode().nodeValue
console.log(x.getAttribute('lang'));//输出title节点属性为lang的值
console.log(x.getAttributeNode('lang').nodeValue);
x.getAttributeNode('lang').nodeValue='fun2';
console.log(x.getAttribute('lang'));
删除节点
- 删除节点:
removeChild()
:所有的节点都可以删除 - 清空文本节点:
nodeValue=""
- 根据名称删除属性节点:
removeAttribute(name)
- 根据对象删除属性节点:
removeAttributeNode(node)
console.log(xmlDoc.documentElement.childNodes);
//删除元素节点
x=xmlDoc.getElementsByTagName("book");//获取book节点列表,长度为4
xmlDoc.documentElement.removeChild(x[0]);//在根节点(bookstore)中删除第一个book节点,长度为3
console.log(xmlDoc.documentElement.childNodes);
//删除自身节点
//如果不知道book节点的父节点就是根节点的情况下,可以使用parentNode
x[0].parentNode.removeChild(x[0]);//在x[0]的父节点中删除x[0]节点,长度为2
console.log(x[0].parentNode.childNodes);
//removeChild可以移除所有的节点,包括文本节点
//文本节点也可以用nodeValue属性
console.log(x[0].childNodes[1].firstChild.nodeValue);
x[0].childNodes[1].firstChild.nodeValue="";//清空book[0]下的title下的文本节点
console.log(x[0].childNodes[1].firstChild.nodeValue);
//删除属性节点
console.log(x[0].getAttribute('category'));
x[0].removeAttribute('category');
console.log(x[0].attributes);
//利用 removeAttributeNode(x)
console.log(x[1].getAttributeNode('cover').nodeValue);
x[1].removeAttributeNode(x[1].attributes[1]);
console.log(x[1].attributes);
替换节点
replaceChild(newNode,oldNode)
:替换元素节点replaceData(offset,length,string)
:替换文本节点的数据(nodeValue
也可以)
x=xmlDoc.documentElement;//根节点
console.log(x.childNodes[1]);
newNode=xmlDoc.createElement("book");
newTitle=xmlDoc.createElement("title");
newText=xmlDoc.createTextNode("A Notebook");
newTitle.appendChild(newText);
newNode.appendChild(newTitle);
x.replaceChild(newNode,xmlDoc.getElementsByTagName("book")[0]);//用newNode替换第一个book节点
console.log(x.childNodes[1]);
xmlDoc.getElementsByTagName("title")[1].childNodes[0].replaceData(10,11,"Two");
//第二个title节点的文本节点的第10个字符替换为Two
console.log(x.childNodes[3]);
xmlDoc.getElementsByTagName("title")[2].childNodes[0].nodeValue="hello world";
console.log(x.childNodes[5]);
创建节点
createElement()
:创建新的元素节点createAttribute()
:创建新的属性节点setAttribute()
:在属性不存在的情况下,创建新的属性节点并赋值createTextNode()
:创建新的文本节点
x=xmlDoc.documentElement;//根节点
console.log(x.childNodes);
newNode=xmlDoc.createElement("book");//创建一个新的book节点
newTitle=xmlDoc.createElement("title");//创建一个新的title节点
newText=xmlDoc.createTextNode("hello world");//创建新的文本节点,内容是hello world
newAttr=xmlDoc.createAttribute("lang");//创建新的属性节点
newAttr.nodeValue="en";//给lang赋值为en
newTitle.setAttribute("name","lucy");//不存在该属性,创建并赋值
newTitle.setAttributeNode(newAttr);//将属性节点添加到title节点中
newTitle.appendChild(newText);//将文本节点添加到title节点中
newNode.appendChild(newTitle);//将title节点添加到book节点中
x.appendChild(newNode);//将book节点添加到根节点中
console.log(x.childNodes[9]);
添加节点
注意:添加属性节点不能使用
appendChild()
,可以用setAttribute()
或setAttributeNode()
appendChild()
:在已有节点的后面追加节点insertBefore(i,j)
:在j节点之前插入i节点insertData(offset,string)
:在已有文本节点的offset
位置后插入string
newauthor=xmlDoc.createElement("author");//创建作者节点
newText2=xmlDoc.createTextNode("me");//创建文本节点
newauthor.appendChild(newText2);//将文本节点添加到author节点中
newNode.appendChild(newauthor);//在book节点的最后面追加节点author,插入到title节点后
newyear=xmlDoc.createElement("year");//创建year节点
newText3=xmlDoc.createTextNode("2020");//创建文本节点
newyear.appendChild(newText3);//将文本节点追加到year节点
newNode.insertBefore(newyear,newTitle);//将year节点添加到title节点之前
newText3.insertData(newText3.nodeValue.length,"我是后来加上的");
克隆节点
当我们想在bookstore中添加新的book节点,如果我们想添加多个,而又因为一个节点只能插入到一个节点中,比如:
newauthor=xmlDoc.createElement("author");//创建作者节点
// newText2=xmlDoc.createTextNode("me");//创建文本节点
newauthor.appendChild(newText);//将文本节点添加到author节点中
newNode.appendChild(newauthor);//在book节点的最后面追加节点author,插入到title节点后
newyear=xmlDoc.createElement("year");//创建year节点
// newText3=xmlDoc.createTextNode("2020");//创建文本节点
newyear.appendChild(newText);//将文本节点追加到year节点
newNode.insertBefore(newyear,newTitle);//将year节点添加到title节点之前
newText.insertData(newText.nodeValue.length,"我是后来加上的");
跟上面程序对比,我们想要达到将newText这个节点插入到所有节点当中,但结果却不是这样:
所以代表一个节点的这个变量只能插入到一个节点当中。
我们就可以使用克隆cloneNode(true/false)
:
- true:克隆当前节点的属性及子节点
- false:不包括
cloneNode=newNode.cloneNode(true);//克隆newNode节点以及其所有的属性和子节点
x.appendChild(cloneNode);//将克隆节点插入到根节点
console.log(x.childNodes[10]);
节点列表
- 属性:
length
-节点列表的长度 - 方法:
item(index)
-返回节点列表中指定索引号的节点。