2005-08-17 15:45:10 +00:00
|
|
|
(*****************************************************************************
|
2005-08-18 05:55:15 +00:00
|
|
|
* su4sml - a SecureUML repository for SML
|
2005-08-17 15:45:10 +00:00
|
|
|
*
|
|
|
|
* xmltree_parser.sml - an xmi-parser for the import interface for su4sml
|
|
|
|
* Copyright (C) 2005 Achim D. Brucker <brucker@inf.ethz.ch>
|
|
|
|
* Jürgen Doser <doserj@inf.ethz.ch>
|
|
|
|
*
|
|
|
|
* This file is part of su4sml.
|
|
|
|
*
|
|
|
|
* su4sml is free software; you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License as published by the Free
|
|
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* su4sml is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
******************************************************************************)
|
|
|
|
|
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
structure XmlTree :
|
2005-08-19 16:04:10 +00:00
|
|
|
sig
|
2005-08-20 18:42:39 +00:00
|
|
|
type Attribute
|
|
|
|
type Tag = string * Attribute list
|
|
|
|
datatype Tree = Node of Tag * Tree list
|
2005-09-14 07:58:28 +00:00
|
|
|
| Text of string
|
2005-08-20 18:42:39 +00:00
|
|
|
|
|
|
|
val tag_of : Tree -> Tag
|
2005-08-20 20:50:18 +00:00
|
|
|
val attributes_of : Tree -> Attribute list
|
2005-08-20 18:42:39 +00:00
|
|
|
val children_of : Tree -> Tree list
|
2005-09-14 09:21:47 +00:00
|
|
|
val node_children_of : Tree -> Tree list
|
|
|
|
val text_children_of : Tree -> Tree list
|
2005-08-20 18:42:39 +00:00
|
|
|
val tagname_of : Tree -> string
|
|
|
|
val attvalue_of : string -> Attribute list -> string option
|
|
|
|
|
2005-08-20 20:50:18 +00:00
|
|
|
val skip : string -> Tree -> Tree list
|
|
|
|
val filter : string -> Tree list -> Tree list
|
|
|
|
val filter_children : string -> Tree -> Tree list
|
2005-09-12 20:13:23 +00:00
|
|
|
val find_some : string -> Tree list -> Tree option
|
2005-08-20 20:50:18 +00:00
|
|
|
val find : string -> Tree list -> Tree
|
|
|
|
val find_child : string -> Tree -> Tree
|
|
|
|
val dfs : string -> Tree -> Tree option
|
|
|
|
val exists : string -> Tree list -> bool
|
|
|
|
val has_child : string -> Tree -> bool
|
|
|
|
val follow : string -> Tree list -> Tree list
|
|
|
|
val follow_all : string -> Tree list -> Tree list list
|
|
|
|
|
|
|
|
val apply_on : string -> (Attribute list -> Tree list -> 'a) -> Tree -> 'a
|
2005-08-23 08:03:09 +00:00
|
|
|
exception IllFormed of string
|
2005-08-19 16:04:10 +00:00
|
|
|
end =
|
2005-08-17 15:45:10 +00:00
|
|
|
struct
|
2005-08-19 16:04:10 +00:00
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
exception IllFormed of string
|
2005-08-19 16:04:10 +00:00
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
type Attribute = (string * string)
|
2005-08-17 15:45:10 +00:00
|
|
|
|
|
|
|
(* Tags consist of element names, and a list of attribute name-value pairs *)
|
2005-08-20 18:42:39 +00:00
|
|
|
type Tag = string * Attribute list
|
|
|
|
|
|
|
|
datatype Tree = Node of Tag * Tree list
|
2005-09-14 07:58:28 +00:00
|
|
|
| Text of string
|
2005-08-20 18:42:39 +00:00
|
|
|
|
2005-09-14 09:21:47 +00:00
|
|
|
val filter_nodes = List.filter (fn Node x => true
|
|
|
|
| _ => false)
|
|
|
|
|
|
|
|
val filter_text = List.filter (fn Text x => true
|
|
|
|
| _ => false)
|
|
|
|
|
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
fun tag_of (Node (tag,trees)) = tag
|
|
|
|
fun attributes_of (Node ((elem,atts),trees)) = atts
|
|
|
|
fun children_of (Node ((elem,atts),trees)) = trees
|
2005-09-14 09:21:47 +00:00
|
|
|
fun node_children_of (Node ((elem,atts),trees)) = filter_nodes trees
|
|
|
|
fun text_children_of (Node ((elem,atts),trees)) = filter_text trees
|
2005-08-20 18:42:39 +00:00
|
|
|
fun tagname_of (Node ((elem,atts),trees)) = elem
|
2005-09-14 09:21:47 +00:00
|
|
|
| tagname_of (Text _) = ""
|
2005-08-20 18:42:39 +00:00
|
|
|
|
|
|
|
fun attvalue_of string atts = Option.map #2 (List.find (fn (x,_) => x = string) atts)
|
|
|
|
|
|
|
|
fun skip string tree = if string = tagname_of tree
|
2005-09-14 09:21:47 +00:00
|
|
|
then node_children_of tree
|
2005-08-23 08:03:09 +00:00
|
|
|
else raise IllFormed ("in XmlTree.skip: did not find element "^string)
|
2005-08-20 18:42:39 +00:00
|
|
|
|
|
|
|
fun filter string trees = List.filter (fn x => string = tagname_of x)
|
|
|
|
trees
|
2005-08-20 20:50:18 +00:00
|
|
|
fun filter_children string tree = List.filter (fn x => string = tagname_of x)
|
2005-09-14 09:21:47 +00:00
|
|
|
(node_children_of tree)
|
2005-08-20 18:42:39 +00:00
|
|
|
|
2005-09-12 20:13:23 +00:00
|
|
|
fun find_some string trees = (List.find (fn x => string = tagname_of x) trees)
|
2005-08-20 20:50:18 +00:00
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
fun find string trees = valOf (List.find (fn x => string = tagname_of x) trees)
|
2005-08-23 08:03:09 +00:00
|
|
|
handle Option => raise IllFormed ("in XmlTree.find: did not find element "^string)
|
2005-08-20 20:50:18 +00:00
|
|
|
|
2005-09-14 09:21:47 +00:00
|
|
|
fun find_child string tree = valOf (List.find (fn x => string = tagname_of x) (node_children_of tree))
|
2005-08-23 08:03:09 +00:00
|
|
|
handle Option => raise IllFormed ("in XmlTree.find_child: did not find element "^string)
|
2005-08-20 18:42:39 +00:00
|
|
|
|
2005-08-20 20:50:18 +00:00
|
|
|
fun dfs string tree = if tagname_of tree = string
|
|
|
|
then SOME tree
|
2005-09-14 09:21:47 +00:00
|
|
|
else Option.join (List.find Option.isSome (List.map (dfs string) (node_children_of tree)))
|
2005-08-20 20:50:18 +00:00
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
fun exists string trees = List.exists (fn x => string = tagname_of x) trees
|
2005-09-14 09:21:47 +00:00
|
|
|
fun has_child string tree = List.exists (fn x => string = tagname_of x) (node_children_of tree)
|
2005-08-20 18:42:39 +00:00
|
|
|
|
2005-09-14 09:21:47 +00:00
|
|
|
fun follow string = node_children_of o (find string)
|
2005-08-20 18:42:39 +00:00
|
|
|
|
2005-09-14 09:21:47 +00:00
|
|
|
fun follow_all string trees = map node_children_of (filter string trees)
|
2005-08-20 18:42:39 +00:00
|
|
|
|
|
|
|
fun apply_on name f tree =
|
|
|
|
if tagname_of tree = name
|
2005-09-14 09:21:47 +00:00
|
|
|
then f (attributes_of tree) (node_children_of tree)
|
2005-08-23 08:03:09 +00:00
|
|
|
else raise IllFormed ("in XmlTree.apply_on: did not find element "^name)
|
2005-08-17 15:45:10 +00:00
|
|
|
|
2005-08-20 20:50:18 +00:00
|
|
|
|
2005-08-17 15:45:10 +00:00
|
|
|
end
|
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
structure XmlTreeHooks : Hooks =
|
2005-08-17 15:45:10 +00:00
|
|
|
struct
|
2005-08-20 18:42:39 +00:00
|
|
|
open IgnoreHooks XmlTree UniChar HookData
|
2005-08-19 16:04:10 +00:00
|
|
|
exception IllFormed
|
2005-08-17 15:45:10 +00:00
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
type AppData = Dtd.Dtd * Tree list * (Tag * Tree list) list
|
|
|
|
type AppFinal = Tree
|
2005-08-17 15:45:10 +00:00
|
|
|
(* val appStart = (nil,nil) *)
|
|
|
|
|
|
|
|
fun attspec2name dtd nil = nil
|
|
|
|
| attspec2name dtd ((i,AP_PRESENT (s,v,_),_)::atts) =
|
|
|
|
let val attName = UniChar.Data2String (Dtd.Index2AttNot dtd i)
|
|
|
|
val attValue = UniChar.Vector2String v
|
|
|
|
in
|
|
|
|
(attName,attValue)::(attspec2name dtd atts)
|
|
|
|
end
|
|
|
|
| attspec2name dtd ((i,AP_DEFAULT (s,v,_),_)::atts) =
|
|
|
|
let val attName = UniChar.Data2String (Dtd.Index2AttNot dtd i)
|
|
|
|
val attValue = UniChar.Vector2String v
|
|
|
|
in
|
|
|
|
(attName,attValue)::(attspec2name dtd atts)
|
|
|
|
end
|
|
|
|
| attspec2name dtd (_::atts) = attspec2name dtd atts
|
|
|
|
|
|
|
|
|
|
|
|
fun hookStartTag ((dtd,content, stack), (_,elem,atts,_,empty)) =
|
|
|
|
let val elemName = UniChar.Data2String (Dtd.Index2Element dtd elem)
|
|
|
|
val attNames = attspec2name dtd atts in
|
|
|
|
if empty
|
2005-08-20 18:42:39 +00:00
|
|
|
then (dtd,Node ((elemName,attNames),nil)::content,stack)
|
2005-08-17 15:45:10 +00:00
|
|
|
else (dtd,nil,((elemName,attNames),content)::stack)
|
|
|
|
end
|
|
|
|
|
|
|
|
fun hookEndTag ((dtd,_,nil),_) = raise IllFormed
|
|
|
|
| hookEndTag ((dtd,content,(tag,content')::stack),_) =
|
2005-08-20 18:42:39 +00:00
|
|
|
(dtd,Node (tag,rev content)::content',stack)
|
2005-08-17 15:45:10 +00:00
|
|
|
|
|
|
|
fun hookData ((dtd,content,stack),(_,vec,_)) =
|
2005-09-14 07:58:28 +00:00
|
|
|
(dtd,Text (UniChar.Vector2String vec)::content,stack)
|
2005-08-17 15:45:10 +00:00
|
|
|
|
|
|
|
fun hookCData ((dtd,content,stack),(_,vec)) =
|
2005-09-14 07:58:28 +00:00
|
|
|
(dtd,Text (UniChar.Vector2String vec)::content,stack)
|
2005-08-17 15:45:10 +00:00
|
|
|
|
2005-09-14 07:58:28 +00:00
|
|
|
fun hookCharRef ((dtd,content,stack),(_,c,_)) = (* FIX *)
|
2005-08-17 15:45:10 +00:00
|
|
|
(dtd,content,stack)
|
|
|
|
|
|
|
|
fun hookFinish (dtd,[elem],nil) = elem
|
|
|
|
| hookFinish _ = raise IllFormed
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
structure ParseXmlTree : sig
|
|
|
|
val readFile : string -> XmlTree.Tree
|
|
|
|
end =
|
2005-08-17 15:45:10 +00:00
|
|
|
struct
|
2005-08-20 18:42:39 +00:00
|
|
|
open XmlTree
|
2005-08-19 14:40:25 +00:00
|
|
|
|
|
|
|
exception FileNotFound of string
|
|
|
|
|
2005-08-17 15:45:10 +00:00
|
|
|
structure Parser = Parse (structure Dtd = Dtd
|
|
|
|
structure Hooks = XmlTreeHooks
|
|
|
|
structure ParserOptions = ParserOptions ()
|
|
|
|
structure Resolve = ResolveNull)
|
|
|
|
|
2005-08-19 14:40:25 +00:00
|
|
|
fun readFile filename =
|
2005-08-18 15:17:51 +00:00
|
|
|
let val currentDir = OS.FileSys.getDir()
|
|
|
|
val _ = OS.FileSys.fileSize filename (* dummy check to see if the file exists...*)
|
2005-08-17 17:22:10 +00:00
|
|
|
val dtd = Dtd.initDtdTables()
|
2005-08-17 15:45:10 +00:00
|
|
|
(* how to do the following in a clean/portable way? *)
|
2005-08-18 15:17:51 +00:00
|
|
|
val _ = OS.FileSys.chDir (su4sml_home())
|
|
|
|
val _ = OS.FileSys.fileSize "dummy.xmi" (* dummy check to see if the file exists...*)
|
2005-08-17 15:45:10 +00:00
|
|
|
val _ = Parser.parseDocument
|
2005-08-18 15:17:51 +00:00
|
|
|
(SOME (Uri.String2Uri ("file:dummy.xmi")))
|
2005-08-17 15:45:10 +00:00
|
|
|
(SOME dtd) (dtd,nil,nil)
|
2005-08-18 15:17:51 +00:00
|
|
|
val _ = OS.FileSys.chDir currentDir
|
2005-08-17 15:45:10 +00:00
|
|
|
in Parser.parseDocument
|
|
|
|
(SOME (Uri.String2Uri filename))
|
|
|
|
(SOME dtd) (dtd,nil,nil)
|
|
|
|
end
|
2005-08-20 20:50:18 +00:00
|
|
|
handle SysErr => (print ("Warning: in readFile: did not find file "^filename^"\n");
|
|
|
|
Node (("",nil),nil))
|
2005-08-17 15:45:10 +00:00
|
|
|
end
|
2005-08-17 17:22:10 +00:00
|
|
|
|
|
|
|
|
2005-09-12 08:58:30 +00:00
|
|
|
(* supposed to print a XmlTree to a xml file. *)
|
|
|
|
(* Works in principle, but currently does not escape *)
|
|
|
|
(* entities like "<", and is not UTF-8 clean *)
|
2005-08-20 18:42:39 +00:00
|
|
|
structure WriteXmlTree: sig
|
|
|
|
val writeFile : string -> XmlTree.Tree -> unit
|
2005-08-19 16:04:10 +00:00
|
|
|
end =
|
2005-08-17 17:22:10 +00:00
|
|
|
struct
|
2005-08-20 18:42:39 +00:00
|
|
|
open XmlTree
|
2005-08-17 17:22:10 +00:00
|
|
|
|
|
|
|
fun writeAttribute stream (name,value) =
|
|
|
|
TextIO.output (stream, " "^name^"=\""^value^"\"")
|
|
|
|
|
|
|
|
fun writeEndTag stream name = TextIO.output (stream,"</"^name^">\n")
|
|
|
|
|
|
|
|
fun writeStartTag stream tree =
|
2005-08-20 18:42:39 +00:00
|
|
|
(TextIO.output (stream,"<"^(tagname_of tree));
|
|
|
|
map (writeAttribute stream) (attributes_of tree);
|
2005-08-17 17:22:10 +00:00
|
|
|
TextIO.output (stream,">\n"))
|
|
|
|
|
|
|
|
fun writeIndent stream 0 = ()
|
|
|
|
| writeIndent stream n = (TextIO.output (stream, " "); writeIndent stream (n-1))
|
|
|
|
|
|
|
|
|
2005-08-20 18:42:39 +00:00
|
|
|
fun writeXmlTree indent stream tree =
|
|
|
|
let val elemName = tagname_of tree
|
2005-08-17 17:22:10 +00:00
|
|
|
in
|
|
|
|
writeIndent stream indent;
|
|
|
|
writeStartTag stream tree;
|
2005-08-20 18:42:39 +00:00
|
|
|
map (writeXmlTree (indent+1) stream) (children_of tree);
|
2005-08-17 17:22:10 +00:00
|
|
|
writeIndent stream indent;
|
|
|
|
writeEndTag stream elemName
|
|
|
|
end
|
|
|
|
|
2005-08-19 14:40:25 +00:00
|
|
|
fun writeFile filename tree =
|
2005-08-17 17:22:10 +00:00
|
|
|
let val stream = TextIO.openOut filename
|
|
|
|
in
|
2005-09-12 08:58:30 +00:00
|
|
|
TextIO.output (stream,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
2005-08-20 18:42:39 +00:00
|
|
|
writeXmlTree 0 stream tree;
|
2005-08-17 17:22:10 +00:00
|
|
|
TextIO.closeOut stream
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|