快学Scala 第16章 XML处理 习题解答

1. <fred/>(0) 得到什么?<fred/>(0)(0)呢?为什么?

回答:<fred/>(0) 得到一个scala.xml.Node,<fred/>(0)(0)也是得到scala.xml.Node。

因为scala.xml.Node 实现了方法 def apply(i: Int): Node,所以支持串接调用。

注意:scala-xml-x.x.x.jar 需要另外导入。

scala> val a = <fred/>

a: scala.xml.Elem = <fred/>

scala> a(0)

res2: scala.xml.Node = <fred/>

scala> a(0)(0)

res3: scala.xml.Node = <fred/>

scala> a(0)(0)(0)

res4: scala.xml.Node = <fred/>

scala> a(0)(0)(0)(0)

res5: scala.xml.Node = <fred/>

scala>

2. 如下代码的值是什么?

<ul>

<li>Opening bracket: [</li>

<li>Closing bracket: ]</li>

<li>Opening brace: {</li>

<li>Closing brace: }</li>

</ul>

你如何修复它?

回答:会有编译错误。要在XML字面量中包含左花括号和右花括号,连续写两个即可。

package ex16_02

import scala.xml._

object Main extends App{

/*

Multiple markers at this line:

in XML literal: in XML content, please use ‘}}‘ to express ‘}‘

I encountered a ‘}‘ where I didn‘t expect one, maybe this tag isn‘t closed <li>

I encountered a ‘}‘ where I didn‘t expect one, maybe this tag isn‘t closed <li>

*/

val a =

<ul>

<li>Opening bracket: [</li>

<li>Closing bracket: ]</li>

<li>Opening brace: {{</li>

<li>Closing brace: }}</li>

</ul>

println(a)

}

/*output:

<ul>

<li>Opening bracket: [</li>

<li>Closing bracket: ]</li>

<li>Opening brace: {</li>

<li>Closing brace: }</li>

</ul>

*/

3. 比对 <li>Fred</li> match { case <li>{Text(t)}</li> => t } 和

<li>{"Fred"}</li> match { case <li>{Text(t)}</li> => t }

为什么它们的行为不同?

回答:内嵌表达式中的字符串并不会被转成Text节点而是Atom[String]节点。这和普通的Text节点还是有区别的——Text是Atom[String]的子类。

这对于保存文档没有问题。但如果你事后打算以Text节点的模式对它做匹配时,匹配会失败。像这种情况你应该插入Text节点而不是字符串。

package ex16_03

import scala.xml._

object Main extends App {

val a = <li>Fred</li> match { case <li>{ Text(t) }</li> => t }

//val b = <li>{ "Fred" }</li> match { case <li>{ Text(t) }</li> => t }

val c = <li>{ Text("Fred") }</li> match { case <li>{ Text(t) }</li> => t }

//println("a=" + a)

println("c=" + c)

}

/*output:

a=Fred

b: Exception in thread "main" scala.MatchError: <li>Fred</li> (of class scala.xml.Elem)

c=Fred

*/

4. 读取一个XHTML文件并打印所有不带alt属性的img元素。

package ex16_04

import scala.xml._

object Main extends App {

val root = XML.loadFile("./src/test.xhtml")

val imgs: NodeSeq = root \\ "img"

// img \ "@alt " ‘s type is scala.xml.NodeSeq

for (img <- imgs if (img \ "@alt").text == "") println(img)

}

/*output:

<img src="hamster.jpg"/>

<img src="frog.jpg"/>

*/

test.xhtml

<html>

<head>

<title>My Scala</title>

</head>

<body>

<p>Hello Scala</p>

<p><img src="hamster.jpg"/></p>

<p><img src="frog.jpg"/></p>

<p><img src="dog.jpg" alt="inu"/></p>

</body>

</html>

5. 打印XHTML文件中所有图像的名称。即,打印所有位于img元素内的src属性值。

package ex16_05

import scala.xml._

object Main extends App {

val root = XML.loadFile("./src/test.xhtml")

val imgs: NodeSeq = root \\ "img"

// img \ "@alt " ‘s type is scala.xml.NodeSeq

imgs.foreach { x => println(x \ "@src" text) }

}

/*output:

hamster.jpg

frog.jpg

dog.jpg

*/

6. 读取XHTML文件并打印一个包含了文件中给出的所有超链接及其URL的表格。

即,打印所有a元素的child文本和href属性。

package ex16_06

import scala.xml._

object Main extends App {

val root = XML.loadFile("./src/oschina.xhtml")

val imgs: NodeSeq = root \\ "a"

imgs.foreach { x =>

val child = x.child

println("%s: %s".format(child(0).text, x.attribute("href").getOrElse("")))

}

}

/*output:

Android: http://www.oschina.net/app

iPhone: http://www.oschina.net/app

WP7: http://www.oschina.net/app

*/

oschina.xml:

<html>

<head>

<title>My Scala</title>

</head>

<body>

<p>Hello Scala</p>

<p><img src="hamster.jpg"/></p>

<p><img src="frog.jpg"/></p>

<p><img src="dog.jpg" alt="inu"/></p>

<ul>

<li><a href="http://www.oschina.net/app" class=‘android‘ title=‘Android客户端‘>Android</a></li>

<li><a href="http://www.oschina.net/app" class=‘iphone‘ title=‘iPhone 客户端‘>iPhone</a></li>

<li><a href="http://www.oschina.net/app" class=‘wp7‘ title=‘Windows Phone 客户端‘>WP7</a></li>

</ul>

</body>

</html>

7. 编写一个函数,带一个类型为Map[String, String]的参数,返回一个dl元素,其中针对映射中每个键对应有一个dt,每个值对应有一个dd。例如:

Map("A" -> "1", "B" -> "2")

应产出 <dl><dt>A</dt><dd>1</dd><dt>B</dt><dd>2</dd></dl>

package ex16_07

import scala.xml._

object Main extends App {

def genDl(input: Map[String,String])={

<dl>{for((k,v) <- input) yield <dt>{k}</dt><dd>{v}</dd>}</dl>

}

val input = Map("A" -> "1", "B" -> "2")

println(genDl(input))

}

/*output:

<dl><dt>A</dt><dd>1</dd><dt>B</dt><dd>2</dd></dl>

*/

8. 编写一个函数,接受dl元素,将它转成Map[String,String]。该函数应该是前一个练习中的反向处理,前提是所有dt后代都是唯一(各不相同)的。

package ex16_08

import scala.xml._

import scala.collection.mutable.Map

object Main extends App {

def dl2map(input: scala.xml.Elem): Map[String, String] = {

val map = Map[String, String]()

val keys = input \ "dt"

val values = input \ "dd"

for (i <- 0 until keys.size) map += keys(i).text -> values(i).text

map

}

val input = <dl><dt>A</dt><dd>1</dd><dt>B</dt><dd>2</dd></dl>

val obj = dl2map(input)

println(obj)

}

/*output:

Map(A -> 1, B -> 2)

*/

9. 对一个XHTML文档进行变换,对所有不带alt属性的img元素添加一个alt="TODO"属性,其余内容完全不变。

package ex16_09

import scala.xml._

import scala.xml.transform._

object Main extends App {

def transform(filename: String) {

val root = XML.loadFile(filename)

val rule1 = new RewriteRule {

override def transform(n: Node) = n match {

case x @ <img/> => if (x.attributes("alt") == null) x.asInstanceOf[Elem] % Attribute(null, "alt", "TODO", scala.xml.Null) else x

case _ => n

}

}

val transformed = new RuleTransformer(rule1).transform(root)

//println(transformed)

scala.xml.XML.save("./src/test_new.xhtml", transformed(0))

}

transform("./src/test.xhtml")

}

/*output:

<html>

<head>

<title>My Scala</title>

</head>

<body>

<p>Hello Scala</p>

<p><img alt="TODO" src="hamster.jpg"/></p>

<p><img alt="TODO" src="frog.jpg"/></p>

<p><img alt="inu" src="dog.jpg"/></p>

</body>

</html>

*/

10.  编写一个函数,读取XHTML文档,执行前一个练习中的变换,并保存结果。确保保存了DTD及所有CDATA内容。

package ex16_10

import scala.xml._

import scala.xml.transform._

import scala.xml.parsing.ConstructingParser

import scala.xml.dtd._

object Main extends App {

def transform(filename: String) {

val parser = ConstructingParser.fromFile(new java.io.File(filename), preserveWS = true)

val doc = parser.document

val root = doc.docElem

val rule1 = new RewriteRule {

override def transform(n: Node) = n match {

case x @ <img/> => if (x.attributes("alt") == null) x.asInstanceOf[Elem] % Attribute(null, "alt", "TODO", scala.xml.Null) else x

case _          => n

}

}

val transformed = new RuleTransformer(rule1).transform(root)

//println(transformed)

scala.xml.XML.save("./src/cdata_new.xhtml", transformed(0),

enc = "UTF-8",

xmlDecl = true,

doctype = DocType("html",

PublicID("-//W3C//DTD XHTML 1.0 Strict//EN",

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"),

Nil))

}

transform("./src/cdata.xhtml")

}

/*output:

<?xml version=‘1.0‘ encoding=‘UTF-8‘?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>

<head>

<title>My Scala</title>

<script>

<![CDATA[

function matchwo(a,b)

{

if (a < b && a < 0) then

{

return 1;

}

else

{

return 0;

}

}

]]>

</script>

</head>

<body>

<!-- This is a comment -->

<p>Hello Scala</p>

<p><img alt="TODO" src="hamster.jpg"/></p>

<p><img alt="TODO" src="frog.jpg"/></p>

<p><img alt="inu" src="dog.jpg"/></p>

</body>

</html>

*/

时间: 2024-10-11 08:53:39

快学Scala 第16章 XML处理 习题解答的相关文章

快学Scala 第18章 高级类型 习题解答

1. 实现一个Bug类,对沿着水平线爬行的虫子建模.move方法向当前方向移动,turn方法让虫子转身,show方法打印出当前的位置.让这些方法可以被串接调用.例如: bugsy.move(4).show().move(6).show().turn().move(5).show() 上述代码应显示 4 10 5. package ex18_01 class Bug {   var x = 0   var y = 0   var curr_direction = 0   def move(len:

快学scala 第十一章 操作符 读书笔记及习题答案代码

chapter 11 操作符 标签:快学scala 一.笔记 scala种可以在反引号中包含几乎任何字符序列, val 'val' = 42 所有的操作符都是左结合的,除了以冒号(:)结尾的操作符,和赋值操作符.用于构造列表的::操作符是又结合的.1::2::Ni1的意思是1::(2::Ni1),先创建出包含2的列表,这个列表又被作为尾巴拼接到以1作为头部的列表中. 2. 函数调用语法:f(arg1, arg2,...)扩展到可以应用于函数之外的值,如果f不是函数或方法,那么这个表达式等于f.a

快学Scala第13章----集合

本章要点 所有集合都扩展自Iterable特质 集合有三大类:序列.集.映射 对于几乎所有集合类,Scala都同时提供了可变的和不可变的版本 Scala列表要么是空的,要么拥有一头一尾,其中尾部本身又是一个列表 集是无先后次序的集合 用LinkedhashSet 来保留插入顺序,或者用SortedSet来按顺序进行迭代 '+' 将元素添加到无先后次序的集合中: +: 和 :+ 向前或向后追加到序列: ++将两个集合串接在一起: -和–移除元素 Iterable和Seq特质有数十个用于常见操作的方

快学Scala第10章----特质

本章要点 类可以实现任意数量的特质 特质可以要求实现它们的类具备特定的字段.方法或超类 和Java接口不同,Scala特质可以提供方法和字段的实现 当你将多个特质叠加在一起时,顺序很重要--其方法先被执行的特质排在更后面 为什么没有多重继承 Scala和Java一样不允许类从多个超类继承:从多了超类继承可能会导致许多问题,例如两个超类有相同的方法,子类该如何使用和菱形继承.在java 中类只能扩展自一个超类,它可以实现任意数量的接口,但接口只能包含抽象方法,不能包含字段. Scala提供了特质(

快学Scala第14章----模式匹配和样例类

本章要点 match表达式是一个更好的switch,不会有意外掉入到下一个分支的问题. 如果没有模式能够匹配,会抛出MatchError.可以用case _ 模式来避免. 模式可以包含一个随意定义的条件,称作守卫. 你可以对表达式的类型进行匹配:优先选择模式匹配而不是isInstanceOf/asInstanceOf. 你可以匹配数组.元组和样例类的模式,然后将匹配到的不同部分绑定到变量. 在for表达式中,不能匹配的情况会被安静的跳过. 样例类继承层级中的公共超类应该是sealed的. 用Op

快学Scala 第13章 集合 - 练习解答

1. 编写一个函数,给定字符串,产出一个包含所有字符的下标的映射.举例来说:indexes("Mississippi")应返回一个映射,让'M'对应集{0},'i'对应集{1,4,7,10},依此类推. 使用字符到可变集的映射.另外,你如何保证集是经过排序的? 回答:使用SortedSet可以保证集是经过排序的. package ex13_01 import scala.collection.mutable.SortedSet import scala.collection.mutab

快学Scala 第6章 对象 - 练习

1. 编写一个Conversions对象,加入inchesToCentimeters.gallonsToLiters和milesToKilometers方法. object Conversions {     def main(args: Array[String]){         printf("1 inch = %g centimeters\n", inchesToCentimeters(1))         printf("2 gallons = %g liter

快学Scala第2章–控制结构和函数 笔记

条件表达式 在Scala中,if/else 表达式是有值的,这个就是跟在if或者else之后的表达式的值.例如: val s = if(x > 0) 1 else -1 // 类似于 var s = 0 if(x > 0) s = 1 else s = -1 Scala允许使用混合类型的返回值,例如: if(x > 0) "positive" else -1 上式表达式返回的类型是它们类型的公共超类型, 在这里java.lang.String 和 Int 它们的公共超

快学Scala 第17章 - 类型参数 习题解答

1. 定义一个不可变类Pair[T,S],带一个swap方法,返回组件交换过位置的新对偶. package ex17_01 object Main extends App {   val p = new Pair(97 -> 'a')   val a = p.swap   println(a) } class Pair[T, S](val p: (T, S)) {   def swap = {     (p._2, p._1)   } } /*output: (a,97) */ 2. 定义一个可