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 @ <entry><name>{ Text(Name) }</name>{ ch1 @ _* }</entry> =>
var updated = false;
val ch2 = for(val c <- ch1) yield c match { // does it have the phone number?
case y @ <phone>{ _* }</phone> if y \ "@where" == Where =>
updated = true
<phone where={ Where }>{ newPhone }</phone>
case y => y
}
if( !updated ) { // no, so we add as first entry
<entry>
<name>{ Name }</name>
<phone where={ Where }>{ newPhone }</phone>
{ ch1 }
</entry>
} else { // yes, and we changed it as we should
<entry>
{ ch2 }
</entry>
}
// end case x @ <entry>...
// other entries are copied without changing them
case x =>
x
}
} ; // for ... yield ... returns an Iterator[Node]
// decompose phonebook, apply updates
phonebook match {
case <phonebook>{ ch @ _* }</phonebook> =>
<phonebook>{ copyOrChange( ch.elements ) }</phonebook>
}
}
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 ));
}
}