前一篇文章大概地讲明了Scala处理XML文件的强大功能,这篇文章则要看看Scala怎么加载XML文件到程序当中进行修改并且重新存储到硬盘中。

 

要在Scala程序中加载已存在的XML文件,可以使用scala.xml.XML类中的load()方法。假设有如下XML文件,名为“books.xml”。

  1. <bookshelf> 
  2.     <book id="001"> 
  3.         <name>Scala</name> 
  4.         <author>John</author> 
  5.     </book> 
  6.      
  7.     <book id="002"> 
  8.         <name>XML</name> 
  9.         <author>Tom</author> 
  10.     </book> 
  11. </bookshelf> 
 

加载XML文件的脚本如下:

  1. import scala.xml._     // 导入scala.xml包 
  2.  
  3.   
  4. val xmlFile = XML.load("books.xml"// 加载XML文件 
  5.  
  6. println(xmlFile getClass) 
  7. println(xmlFile) 
  8. println("书的数目: " + (xmlFile \\ "book").size) 
 

只是调用了XML类中的load方法而已,很简单,执行结果如下:

  1. class scala.xml.Elem 
  2. <bookshelf> 
  3.         <book id="001">  
  4.                 <name>Scala</name> 
  5.                 <author>John</author>  
  6.         </book> 
  7.  
  8.   
  9.         <book id="002">  
  10.                 <name>XML</name> 
  11.                 <author>Tom</author> 
  12.         </book>  
  13. </bookshelf> 
  14. 书的数目: 2 
 

接下来如果我们想要根据某本书的id来修改其书名,然后把修改之后的XML文件重新存储到硬盘当中,可以如下操作: 

1、     先遍历整个<bookshelf>…</bookshelf>获得所有的<book>…</book>元素对;

2、     分别提取出上面获得的<book>…</book>中的每个idname,并建立一个idname之间的映射Map[String, String]对象;

3、     将获得的所有映射Map[String, String]对象保存到bookMap变量中;

4、     重新创建一个以<bookshelf>…</bookshelf>为根节点的XML文件(即scala.xml.Elem对象),将上面获得的bookMap变量中包含的Map[String, String]对象逐一地更新、修改;

5、     最后将更新后的XML保存起来,调用XML.save方法。

 

具体代码如下: 

  1. // id与name的映射变量  
  2. val bookMap = 
  3.       (Map[String, String]() /: (xmlFile \ "book")) {  
  4.              (map, bookNode) =>  
  5.                     val id = (bookNode \ "@id").toString  
  6.                     val name = (bookNode \ "name").text.toString  
  7.                     map(id) = name  
  8.       } 

 

上面的Map[String, String]() /: 方法的初始变量,也表明了该表达式返回的map(id) = name 将会是Map[String, String] 类型。另外bookNode \ "@id" 则是提取出book元素中的id属性值。

  1. // 新的Elem对象 
  2. val newXmlFile = 
  3.       <bookshelf> 
  4.              { bookMap.map{updateXmlFile} } 
  5.       </bookshelf> 
 

这只是定义一个以<bookshelf>…</bookshelf>为根节点的XML文件(即scala.xml.Elem对象),它bookMap中的每一个Map[String, String] 对象执行updateXmlFile方法(即传名参数)。

  1. // 更新、修改原XML文件 
  2. def updateXmlFile(elem: (String, String)) = { 
  3.       val (id, newName) = elem // 二元组 
  4.       <book id={id + "-01"}> 
  5.              <name>{newName + " Programming"}</name> 
  6.       </book> 
 
updateXmlFile方法用于修改原来的<book>…</book>元素对中的id属性和name元素的值。
  1. XML.save("newXmlFile.xml", newXmlFile) 
  2. println(XML.load("newXmlFile.xml")) 
 

XML.save方法将会将newXmlFile 以名为“newXmlFile.xml”保存到当前目录下。执行后生成的的newXmlFile.xml 内容如下:

  1. <bookshelf> 
  2.              <book id="001-01"> 
  3.              <name>Scala Programming</name> 
  4.       </book><book id="002-01"> 
  5.              <name>XML Programming</name> 
  6.       </book> 
  7.       </bookshelf> 
 

嗯,格式有点不美观,问题在于脚本代码中关于尖括号和花括号间的空格、换行等等有关,我调整了多次都达不到期望的效果...毕竟Scala的默认缩进是2个空格。

 

注:Scala中代码块的最后一个语句作为默认返回值(如果需要返回)在这里体现得比较明显,如果不知道这一点,则上面的代码可能有些难懂。

 

发现的问题如下:

1、如果原XML文件中的节点元素存在中文,则会修改出错,抛出以下异常:java.nio.charset.UnmappableCharacterException: Input length = 1 

2、同上面类似,如果脚本代码中包含中文字符,如书名号《》等,也会有上面的问题出现;尽管我在执行时使用了scala -encoding gb2312 编码;          

          猜你可能感兴趣:

cala:用传名参数实现断言机制及其特点

Scala:用传名参数构建并理解循环结构

        Scala:简单使用Actor的消息发送与接收求和