| author | haftmann | 
| Tue, 10 Aug 2010 14:53:41 +0200 | |
| changeset 38312 | 9dd57db3c0f2 | 
| parent 38233 | 501dcbd8f399 | 
| child 38263 | 11c2b8d1fde0 | 
| permissions | -rw-r--r-- | 
| 27931 | 1 | /* Title: Pure/General/xml.scala | 
| 2 | Author: Makarius | |
| 3 | ||
| 27947 | 4 | Simple XML tree values. | 
| 27931 | 5 | */ | 
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 34108 | 9 | import java.util.WeakHashMap | 
| 10 | import java.lang.ref.WeakReference | |
| 11 | import javax.xml.parsers.DocumentBuilderFactory | |
| 12 | ||
| 27947 | 13 | |
| 29203 | 14 | object XML | 
| 15 | {
 | |
| 27947 | 16 | /* datatype representation */ | 
| 17 | ||
| 27931 | 18 | type Attributes = List[(String, String)] | 
| 19 | ||
| 34046 | 20 |   sealed abstract class Tree {
 | 
| 29204 | 21 |     override def toString = {
 | 
| 22 | val s = new StringBuilder | |
| 23 | append_tree(this, s) | |
| 24 | s.toString | |
| 25 | } | |
| 29203 | 26 | } | 
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 27 | case class Elem(markup: Markup, body: List[Tree]) extends Tree | 
| 29204 | 28 | case class Text(content: String) extends Tree | 
| 29203 | 29 | |
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 30 | def elem(name: String, body: List[Tree]) = Elem(Markup(name, Nil), body) | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 31 | def elem(name: String) = Elem(Markup(name, Nil), Nil) | 
| 33999 | 32 | |
| 29203 | 33 | |
| 34 | /* string representation */ | |
| 35 | ||
| 36 |   private def append_text(text: String, s: StringBuilder) {
 | |
| 36016 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 37 | if (text == null) s ++= text | 
| 34005 | 38 |     else {
 | 
| 36011 
3ff725ac13a4
adapted to Scala 2.8.0 Beta1 -- with notable changes to scala.collection;
 wenzelm parents: 
34871diff
changeset | 39 |       for (c <- text.iterator) c match {
 | 
| 36016 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 40 | case '<' => s ++= "<" | 
| 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 41 | case '>' => s ++= ">" | 
| 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 42 | case '&' => s ++= "&" | 
| 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 43 | case '"' => s ++= """ | 
| 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 44 | case '\'' => s ++= "'" | 
| 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 45 | case _ => s += c | 
| 34005 | 46 | } | 
| 29203 | 47 | } | 
| 48 | } | |
| 49 | ||
| 50 |   private def append_elem(name: String, atts: Attributes, s: StringBuilder) {
 | |
| 36016 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 51 | s ++= name | 
| 29203 | 52 |     for ((a, x) <- atts) {
 | 
| 36016 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 53 | s ++= " "; s ++= a; s ++= "=\""; append_text(x, s); s ++= "\"" | 
| 29203 | 54 | } | 
| 55 | } | |
| 56 | ||
| 29204 | 57 |   private def append_tree(tree: Tree, s: StringBuilder) {
 | 
| 29203 | 58 |     tree match {
 | 
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 59 | case Elem(Markup(name, atts), Nil) => | 
| 36016 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 60 | s ++= "<"; append_elem(name, atts, s); s ++= "/>" | 
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 61 | case Elem(Markup(name, atts), ts) => | 
| 36016 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 62 | s ++= "<"; append_elem(name, atts, s); s ++= ">" | 
| 29203 | 63 | for (t <- ts) append_tree(t, s) | 
| 36016 
4f5c7a19ebe0
recovered StringBuilder functionality after subtle change of + and ++ in Scala 2.8.0 Beta 1;
 wenzelm parents: 
36011diff
changeset | 64 | s ++= "</"; s ++= name; s ++= ">" | 
| 29203 | 65 | case Text(text) => append_text(text, s) | 
| 66 | } | |
| 67 | } | |
| 27941 | 68 | |
| 69 | ||
| 27942 | 70 | /* iterate over content */ | 
| 27941 | 71 | |
| 72 | private type State = Option[(String, List[Tree])] | |
| 73 | ||
| 74 |   private def get_next(tree: Tree): State = tree match {
 | |
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 75 | case Elem(_, body) => get_nexts(body) | 
| 27941 | 76 | case Text(content) => Some(content, Nil) | 
| 77 | } | |
| 78 |   private def get_nexts(trees: List[Tree]): State = trees match {
 | |
| 79 | case Nil => None | |
| 80 |     case t :: ts => get_next(t) match {
 | |
| 81 | case None => get_nexts(ts) | |
| 28007 | 82 | case Some((s, r)) => Some((s, r ++ ts)) | 
| 27941 | 83 | } | 
| 84 | } | |
| 85 | ||
| 86 |   def content(tree: Tree) = new Iterator[String] {
 | |
| 87 | private var state = get_next(tree) | |
| 88 | def hasNext() = state.isDefined | |
| 89 |     def next() = state match {
 | |
| 90 |       case Some((s, rest)) => { state = get_nexts(rest); s }
 | |
| 91 |       case None => throw new NoSuchElementException("next on empty iterator")
 | |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 27947 | 95 | |
| 34108 | 96 | /* cache for partial sharing -- NOT THREAD SAFE */ | 
| 97 | ||
| 98 | class Cache(initial_size: Int) | |
| 99 |   {
 | |
| 100 | private val table = new WeakHashMap[Any, WeakReference[Any]](initial_size) | |
| 101 | ||
| 102 | private def lookup[A](x: A): Option[A] = | |
| 103 |     {
 | |
| 104 | val ref = table.get(x) | |
| 105 | if (ref == null) None | |
| 106 |       else {
 | |
| 107 | val y = ref.asInstanceOf[WeakReference[A]].get | |
| 108 | if (y == null) None | |
| 109 | else Some(y) | |
| 110 | } | |
| 111 | } | |
| 112 | private def store[A](x: A): A = | |
| 113 |     {
 | |
| 114 | table.put(x, new WeakReference[Any](x)) | |
| 115 | x | |
| 116 | } | |
| 117 | ||
| 118 | def cache_string(x: String): String = | |
| 119 |       lookup(x) match {
 | |
| 120 | case Some(y) => y | |
| 38233 | 121 | case None => store(new String(x.toCharArray)) // trim string value | 
| 34108 | 122 | } | 
| 123 | def cache_props(x: List[(String, String)]): List[(String, String)] = | |
| 34133 | 124 | if (x.isEmpty) x | 
| 125 | else | |
| 126 |         lookup(x) match {
 | |
| 127 | case Some(y) => y | |
| 128 | case None => store(x.map(p => (cache_string(p._1), cache_string(p._2)))) | |
| 129 | } | |
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 130 | def cache_markup(x: Markup): Markup = | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 131 |       lookup(x) match {
 | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 132 | case Some(y) => y | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 133 | case None => | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 134 |           x match {
 | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 135 | case Markup(name, props) => | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 136 | store(Markup(cache_string(name), cache_props(props))) | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 137 | } | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 138 | } | 
| 34117 | 139 | def cache_tree(x: XML.Tree): XML.Tree = | 
| 34108 | 140 |       lookup(x) match {
 | 
| 141 | case Some(y) => y | |
| 142 | case None => | |
| 143 |           x match {
 | |
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 144 | case XML.Elem(markup, body) => | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 145 | store(XML.Elem(cache_markup(markup), cache_trees(body))) | 
| 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 146 | case XML.Text(text) => store(XML.Text(cache_string(text))) | 
| 34108 | 147 | } | 
| 148 | } | |
| 34117 | 149 | def cache_trees(x: List[XML.Tree]): List[XML.Tree] = | 
| 34133 | 150 | if (x.isEmpty) x | 
| 151 | else | |
| 152 |         lookup(x) match {
 | |
| 153 | case Some(y) => y | |
| 154 | case None => x.map(cache_tree(_)) | |
| 155 | } | |
| 34108 | 156 | } | 
| 157 | ||
| 158 | ||
| 33953 | 159 | /* document object model (W3C DOM) */ | 
| 27948 
2638b611d3ce
renamed DOM to document, add xml version and optional stylesheets;
 wenzelm parents: 
27947diff
changeset | 160 | |
| 34871 
e596a0b71f3c
incorporate "proofdocument" part into main Isabelle/Pure.jar -- except for html_panel.scala, which depends on external library (Lobo/Cobra browser);
 wenzelm parents: 
34133diff
changeset | 161 | def get_data(node: org.w3c.dom.Node): Option[XML.Tree] = | 
| 38231 | 162 |     node.getUserData(Markup.Data.name) match {
 | 
| 34047 | 163 | case tree: XML.Tree => Some(tree) | 
| 164 | case _ => None | |
| 165 | } | |
| 166 | ||
| 34871 
e596a0b71f3c
incorporate "proofdocument" part into main Isabelle/Pure.jar -- except for html_panel.scala, which depends on external library (Lobo/Cobra browser);
 wenzelm parents: 
34133diff
changeset | 167 | def document_node(doc: org.w3c.dom.Document, tree: Tree): org.w3c.dom.Node = | 
| 33953 | 168 |   {
 | 
| 34871 
e596a0b71f3c
incorporate "proofdocument" part into main Isabelle/Pure.jar -- except for html_panel.scala, which depends on external library (Lobo/Cobra browser);
 wenzelm parents: 
34133diff
changeset | 169 |     def DOM(tr: Tree): org.w3c.dom.Node = tr match {
 | 
| 38231 | 170 | case Elem(Markup.Data, List(data, t)) => | 
| 34046 | 171 | val node = DOM(t) | 
| 38231 | 172 | node.setUserData(Markup.Data.name, data, null) | 
| 34046 | 173 | node | 
| 38230 
ed147003de4b
simplified type XML.Tree: embed Markup directly, avoid slightly odd triple;
 wenzelm parents: 
36817diff
changeset | 174 | case Elem(Markup(name, atts), ts) => | 
| 38231 | 175 | if (name == Markup.Data.name) | 
| 34046 | 176 |           error("Malformed data element: " + tr.toString)
 | 
| 27947 | 177 | val node = doc.createElement(name) | 
| 178 | for ((name, value) <- atts) node.setAttribute(name, value) | |
| 27952 | 179 | for (t <- ts) node.appendChild(DOM(t)) | 
| 27947 | 180 | node | 
| 181 | case Text(txt) => doc.createTextNode(txt) | |
| 182 | } | |
| 33953 | 183 | DOM(tree) | 
| 184 | } | |
| 27931 | 185 | } |