读取,分析,创建和编写xml
1. XML字面量
1 2 | 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。
1 2 3 4 5 6 | 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节点序列
1 2 3 4 | val items = new NodeBuffer items + = <li>Fred</li> items + = <li>Wilma</li> val nodes : NodeSeq = items |
有三个字节点,分别是两个Text节点和一个Elem节点。
3. 元素属性
要处理某个元素的属性键和值,可以用attributes属性。它将产出一个类型为MetaData的对象,该对象几乎就是但又不完全等同于一个从属性键到属性值的映射。你可以用()操作符来访问给定键的值。
1 2 | val elem = <a href = "http://scala-lang.org/" >The Scala Language</a> val url = elem.attributes( "href" ) |
1 2 3 | 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
1 2 3 | 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代码,动态的计算出元素内容
1 | <ul><li>{ < strong > items( 0 ) < /strong > }</li><li>{ < strong > items( 1 ) < /strong > }</li></ul> < br > <ul>{ for (i <- items) yield <li>{i}</li>}</ul> |
5. 在属性中使用表达式
<img src={makeURL(filename)}/>
注:被引用的字符串当中的花括号不会被解析和求值,例如<img src=“{makeURL(filename)}”/>将src属性设置为字符串“{makeURL(filename)}”。
如果内嵌代码块返回null或None,则该属性不会被设置
6. 特殊节点类型
1 2 3 4 | val js = <script><![CDATA[ if (temp) < 0 alert( "Cold" )]]></script> val code = "" "if (temp < 0) alert (" Cold ")" "" val js 1 = <script>{PCData(code)}</script> |
1 2 3 | val g 1 = <xml : group><li>Item 1 </li><li>Item 2 </li></xml : group> val g 2 = Group(Seq(<li>Item 1 </li>, <li>Item 2 </li>)) println(g 2 ) |
输出结果为: <li>Item 1</li><li>Item 2</li>
7. 类XPath表达式
\操作符定位某个节点或节点序列的直接后代。
1 2 3 | 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>
通配符可以匹配任何元素
1 2 3 | 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. 模式匹配
1 2 3 4 | 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>
要添加或删除属性,可以用%操作符
1 2 3 | val image = <img src = "hamster.jpg" /> val image 2 = image % Attribute( null , "alt" , "An image of a hamster" , Attribute( null , "val" , "frog.jpg" , Null)) println(image 2 ) |
输出结果为:<img val="frog.jpg" alt="An image of a hamster" src="hamster.jpg"/>
10. XML变换
1 2 3 4 5 6 7 8 9 10 | def main(args : Array[String]) : Unit = { val root = <ul><li>Fred</li><li>Wilma</li></ul> val rule 1 = 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(rule 1 ).transform(root) } |
可以在RuleTransformer的构造器中给出多个规则:
1 | val transformer = new RuleTransformer(rule 1 , rule 2 , rule 3 ) |
11. 加载和保存
1 2 | import scala.xml.XML val root = XML.loadFile( "myfile.xml" ) < br > val root 2 = XML.load( new FileInputStream( "myfile.xml" )) < br > val root 3 = XML.load( new InputStreamReader( new FileInpurStream( "myfile.xml" ), "UTF-8" )) < br > val root 4 = XML.load( new URL( "http://horstmann.com/index.html" )) |
注:文档是使用Java类库中标准的SAX解析器加载的。但可惜并没有提供文档类型的定义。
要保存XML到文件中,可以用sava方法。
1 | XML.save( "myfile.xml" , root) |
有三个可选参数:
- enc用来指定字符编码(缺省为"ISO-8859-1")
- xmlDecl用来指定输出中最开始是否要生成XML声明(<?xml...?>)(缺省为false)
- doctype是样例类scala.xml.dtd.DocType的对象(缺省为null)
也可以保存到java.io.Writer,但是必须给出所有参数
1 | XML.write(writer, root, "UTF-8" , false , null ) |
12. 命名空间
xmlns属性可以声明一个命名空间
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步