1. <fred/>(0) 獲得什麼?<fred/>(0)(0)呢?爲何?html
回答:<fred/>(0) 獲得一個scala.xml.Node,<fred/>(0)(0)也是獲得scala.xml.Node。java
由於scala.xml.Node 實現了方法 def apply(i: Int): Node,因此支持串接調用。android
注意:scala-xml-x.x.x.jar 須要另外導入。express
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. 以下代碼的值是什麼?app
<ul>iphone
<li>Opening bracket: [</li>ide
<li>Closing bracket: ]</li> 函數
<li>Opening brace: {</li> this
<li>Closing brace: }</li> es5
</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> */