读取,分析,创建和编写xml
1. XML字面量
val doc = <html><head><title>Fred's Memoir's</title></head><body>...</body></html> //scala.xml.Elem val items = <li>Fred</li><li>Wilma</li> //scala.xml.NodeSeq
注:有时,编译器会错误地识别出XML,例如x <y就会被理解为未结束的XML字面量
2. XML节点
Node类是所有XML节点类型的祖先。它的两个最重要的子类是Text和Elem。
def main(args: Array[String]): Unit = { val elem = <a href = "http://scala-lang.org">The <em>Scala</em>language</a> for(n <- elem.child) { println(n) } }
上述程序的输出结果为:
可以看出elem节点序列
val items = new NodeBuffer items += <li>Fred</li> items += <li>Wilma</li> val nodes: NodeSeq = items
有三个字节点,分别是两个Text节点和一个Elem节点。
3. 元素属性
要处理某个元素的属性键和值,可以用attributes属性。它将产出一个类型为MetaData的对象,该对象几乎就是但又不完全等同于一个从属性键到属性值的映射。你可以用()操作符来访问给定键的值。
val elem = <a href="http://scala-lang.org/">The Scala Language</a> val url = elem.attributes("href")
val elem = <a href = "http://scala-lang.org">The <em>Scala</em> language</a> val url = elem.attributes.get("href").getOrElse(Text("")) for(attr <- elem.attributes) printf("attr.key: %s, attr.value.text: %s\n", attr.key, attr.value.text)
输出结果为: attr.key: href, attr.value.text: http://scala-lang.org
val image = <img alt="TODO" src ="hamster.jpg"/> val map = image.attributes.asAttrMap for(key <- map.keys) printf("key: %s, value: %s\n", key, map.get(key))
4. 内嵌表达式
你可以在XML字面量中包含Scala代码,动态的计算出元素内容
<ul><li>{items(0)}</li><li>{items(1)}</li></ul>
<ul>{for (i <- items) yield <li>{i}</li>}</ul>
5. 在属性中使用表达式
<img src={makeURL(filename)}/>
注:被引用的字符串当中的花括号不会被解析和求值,例如<img src=“{makeURL(filename)}”/>将src属性设置为字符串“{makeURL(filename)}”。
如果内嵌代码块返回null或None,则该属性不会被设置
6. 特殊节点类型
val js = <script><![CDATA[if (temp) < 0 alert("Cold")]]></script> val code = """if (temp < 0) alert ("Cold")""" val js1 = <script>{PCData(code)}</script>
val g1 = <xml:group><li>Item 1</li><li>Item 2</li></xml:group> val g2 = Group(Seq(<li>Item 1</li>, <li>Item 2</li>)) println(g2)
输出结果为: <li>Item 1</li><li>Item 2</li>
7. 类XPath表达式
\操作符定位某个节点或节点序列的直接后代。
val list = <dl><dt>Java</dt><dd>Gosling</dd><dt>Scala</dt><dd>Odersky</dd></dl> val languages = list \ "dt" for(item <- languages) println(item)
输出结果为:
<dt>Java</dt>
<dt>Scala</dt>
通配符可以匹配任何元素
val list = <ds><dl><dt>Java</dt><dd>Gosling</dd><dt>Scala</dt><dd>Odersky</dd></dl></ds> val languages = list \"_" \ "dt" for(item <- languages) println(item)
\\可以定位任何深度的后代
以@开头的字符串可以定位属性 img \ "@alt"将返回给定节点的alt属性,img \\ "@alt"将定位到img中任何元素的所有alt属性。但是不能使用通配符。
8. 模式匹配
node match { case <img/> => ... ... }
如果node是一个带有任何属性但没有后代的img元素,则第一个匹配会成功。
处理单个后代的匹配表达式 case <li>{_}</li> => ...
处理多个后代的匹配表达式 case <li>{_*}</li> => ...
除了使用通配符,也可以使用变量名。成功匹配到的内容会被绑定到该变量上
case <li>{child}</li> => child.text
要匹配一个文本节点,可以用如下这样的样例类匹配: case <li>{Text(item)}</li> => item
要把节点序列绑到变量,使用如下语法: case <li>{children @_*}</li> => for (c <- children) yield c
若要匹配到属性,得用守卫: case n @ <img/> if (n.attributes("alt").text == "TODO") => ...
9. 修改元素和属性
val list = <ul><li>Fred</li><li>Wilma</li></ul>
val list2 = list.copy(label = "ol")
val list3 = list.copy(child = list.child ++ <li>Another item</li>)
println(list2)
println(list3)
输出结果为:
<ol><li>Fred</li><li>Wilma</li></ol>
<ul><li>Fred</li><li>Wilma</li><li>Another item</li></ul>
要添加或删除属性,可以用%操作符
val image = <img src="hamster.jpg"/> val image2 = image % Attribute(null, "alt", "An image of a hamster", Attribute(null, "val", "frog.jpg", Null)) println(image2)
输出结果为:<img val="frog.jpg" alt="An image of a hamster" src="hamster.jpg"/>
10. XML变换
def main(args: Array[String]): Unit = { val root = <ul><li>Fred</li><li>Wilma</li></ul> val rule1 = new RewriteRule { override def transform(n: Node): Seq[Node] = { case e @ <ul>{_*}</ul> => e.asInstanceOf[Elem].copy(label = "ol") case _ => n } } val transformed = new RuleTransformer(rule1).transform(root) }
可以在RuleTransformer的构造器中给出多个规则:
val transformer = new RuleTransformer(rule1, rule2, rule3)
11. 加载和保存
import scala.xml.XML val root = XML.loadFile("myfile.xml")
val root2 = XML.load(new FileInputStream("myfile.xml"))
val root3 = XML.load(new InputStreamReader(new FileInpurStream("myfile.xml"), "UTF-8"))
val root4 = XML.load(new URL("http://horstmann.com/index.html"))
注:文档是使用Java类库中标准的SAX解析器加载的。但可惜并没有提供文档类型的定义。
要保存XML到文件中,可以用sava方法。
XML.save("myfile.xml", root)
有三个可选参数:
- enc用来指定字符编码(缺省为"ISO-8859-1")
- xmlDecl用来指定输出中最开始是否要生成XML声明(<?xml...?>)(缺省为false)
- doctype是样例类scala.xml.dtd.DocType的对象(缺省为null)
也可以保存到java.io.Writer,但是必须给出所有参数
XML.write(writer, root, "UTF-8", false, null)
12. 命名空间
xmlns属性可以声明一个命名空间