summaryrefslogtreecommitdiff
path: root/sources/scala/xml/Generic.scala
blob: bc760bcfeff09bdd532fcc4eade7fd142cbe3394 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package scala.xml;

import scala.xml.javaAdapter.Map ;
import scala.xml.javaAdapter.HashMap ;


/** Generic.load( <fileName> ) will load the xml document from file and
 *  create a tree with scala.Labelled, PCDATA and scala.Symbol objects.
 *  Text can appear within PCDATA at the leaves.
 */

object Generic {

          // utility functions

    def iterToList[ a ]( iter:java.util.Iterator ):List[a] =
        if( !iter.hasNext() )
            Nil
        else
            (iter.next().asInstanceOf[ a ])::iterToList( iter ) ;

    def mapToMap[a,b]( map:java.util.Map ):Map[a,b] = {

         val keys:java.util.Iterator = map.keySet().iterator();
         val res = new HashMap[a,b] ;

         def iterToMap:Unit =
         if( keys.hasNext() ) {
              val key   = keys.next();
              val value = map.get( key ).asInstanceOf[ b ];
              res.put( key.asInstanceOf[ a ], value.asInstanceOf[ b ]);
              iterToMap
         } else
              () ;

        iterToMap;
        res
    }

    def toXML( attrib:Map[ String, String ] ):String = {
	def iterate( keys:Iterator[String] ) =
	    if( keys.hasNext ) {
                        val key = keys.next;
			" " + key + "=\"" + attrib.get( key ) + "\"";
            } else {
			""
	    }

	if( attrib != null ) iterate( attrib.keys.elements ) else "";
    }

  //  attributes

  trait Attribbed {

    // only CDATA / String attributes for now
    def attribs : Map[String,String] ;

  }
  // functions for generic xml loading, saving

  def load( filename:String ):Labelled = {
    val b = new GenericFactoryAdapter().loadXML( filename );
    b.asInstanceOf[Labelled]
  };

  def save( filename:String, doc:Any ):Unit = {
    import java.io.{FileOutputStream,Writer};
    import java.nio.channels.{Channels,FileChannel};
    def toXML( xs: List[Any], fc:Writer ):Unit = xs match {
        case _::ys =>
                toXML( xs.head, fc );
                toXML( ys, fc );
        case _ => ()
    }
    def toXML( doc: Any, fc:Writer ):Unit = doc match {
        case PCDATA( s ) =>
                fc.write( (doc.asInstanceOf[ PCDATA ]).toXML );
        case Labelled( Symbol( tag ), xs ) =>
                fc.write( "<" );
                fc.write( tag );
                fc.write( Generic.toXML(( doc.asInstanceOf[ Attribbed ])
					.attribs ));
                fc.write( ">" );
                toXML( xs, fc );
                fc.write( "</" );
                fc.write( tag );
                fc.write( ">" );

    }
    val fos = new FileOutputStream( filename );
    val w = Channels.newWriter( fos.getChannel(), "ISO-8859-1" );
    toXML( doc, w );
    w.close();
    fos.close();
  }

  class GenericFactoryAdapter extends FactoryAdapter()  {

    def   elementContainsText( name:java.lang.String ):boolean = true;

    // default behaviour is hash-consing
    val cache = new HashMap();

    def   createElement( elemName: String,
                         attrs: java.util.Map,
                         children: java.util.Iterator ):scala.Object = {

          val el = new Labelled( Symbol( elemName ),
			     Generic.iterToList[ Any ]( children ))
                with Attribbed {
                     def attribs = Generic.mapToMap[String,String]( attrs );
                };

	  val el_cache = cache.get( el.asInstanceOf[scala.All])
			     .asInstanceOf[scala.Object];
	  if ( el_cache != null ) {
	    System.err.println("[using cached elem!]");
	    el_cache
	  } else {
	    cache.put( el.asInstanceOf[scala.All], el.asInstanceOf[scala.All] );
	    el
	  }


    }

    def createPCDATA( text:String ):scala.Object  = {
          new PCDATA( text );
    };

  } // GenericFactoryAdapter

}