package phonebook; object phonebook3 { import scala.xml.{Elem, Node, Text} ; import scala.xml.PrettyPrinter ; import Node.NoAttributes ; /* this method "changes" (returns an updated copy) of the phonebook when the * entry for Name exists. If it has an attribute "where" whose value is equal to the * parameter Where, it is changed, otherwise, it is added. */ def change ( phonebook:Node, Name:String, Where:String, newPhone:String ) = { /** this nested function walks through tree, and returns an updated copy of it */ def copyOrChange ( ch: Iterator[Node] ) = { import xml.Utility.{trim,trimProper} //removes whitespace nodes, which are annoying in matches for( val c <- ch ) yield trimProper(c) match { // if the node is the particular entry we are looking for, return an updated copy case x @ { Text(Name) }{ ch1 @ _* } => var updated = false; val ch2 = for(c <- ch1) yield c match { // does it have the phone number? case y @ { _* } if y \ "@where" == Where => updated = true { newPhone } case y => y } if( !updated ) { // no, so we add as first entry { Name } { newPhone } { ch1 } } else { // yes, and we changed it as we should { ch2 } } // end case x @ ... // other entries are copied without changing them case x => x } } ; // for ... yield ... returns an Iterator[Node] // decompose phonebook, apply updates phonebook match { case { ch @ _* } => { copyOrChange( ch.iterator ) } } } val pb2 = change( phonebook1.labPhoneBook, "John", "work", "+41 55 555 55 55" ); val pp = new PrettyPrinter( 80, 5 ); def main( args:Array[String] ) = { Console.println("---before---"); Console.println( pp.format( phonebook1.labPhoneBook )); Console.println("---after---"); Console.println( pp.format( pb2 )); } }