[m-dev.] for review: namespaces in xml interface

Ina Cheng inch at students.cs.mu.oz.au
Tue Jan 2 11:02:02 AEDT 2001


Hi,

Add some predicates in the xml interface to take into account 
namespaces in xml.

Ina

========================================================================

Estimated hours taken: 6 days

Add a module to turn an xml document into a namespace-aware xml document.

extra/xml/tryit.m
        change the sample program to print out the new xml output

extra/xml/xml.m
        add xml.ns.m to the wrapper module

extra/xml/xml.ns.m
        the new module containing predicates to turn an xml document to a 
        namespace-aware xml document


cvs diff: Diffing .
Index: tryit.m
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/xml/tryit.m,v
retrieving revision 1.2
diff -u -r1.2 tryit.m
--- tryit.m     2000/12/01 06:07:37     1.2
+++ tryit.m     2001/01/01 23:39:23
@@ -17,7 +17,7 @@
 
 :- implementation.
 
-:- import_module parsing, xml, xml:cat, xml:encoding, xml:parse.
+:- import_module parsing, xml, xml:cat, xml:encoding, xml:parse, xml:ns.
 :- import_module char, list, map, std_util, string.
 
 main -->
@@ -29,7 +29,7 @@
 
 main([]) --> [].
 main([File|Files]) -->
-    see(File, Res0),
+    see(File, Res0),
     ( { Res0 = ok } ->
            io__read_file_as_string(_, Text),
            pstate(mkEntity(Text), mkEncoding(utf8), init),
@@ -69,13 +69,20 @@
            document,
            finish(Res),
            (
-               { Res = ok(_) }
+               { Res = ok((DTD, Doc)) },
+               { nsTranslate(Doc, NsDoc) }, 
+               { New = cat:ok((DTD, NsDoc)) },
+               write(New)
+               % if don't want to turn the doc to namespace awared, 
+               % change the above three lines to  
+               % write(Res) 
            ;
-               { Res = error(Err) },
-               stderr_stream(StdErr),
-               format(StdErr, "%s: %s\n", [s(File), s(Err)])
+               { Res = error(Err) },
+               stderr_stream(StdErr),
+               format(StdErr, "%s: %s\n", [s(File), s(Err)]),
+               write(Res)
            ),
-           write(Res), nl,
+           nl,
            []
     ;
        []
Index: xml.m
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/xml/xml.m,v
retrieving revision 1.1
diff -u -r1.1 xml.m
--- xml.m       2000/09/05 22:33:59     1.1
+++ xml.m       2000/12/22 02:05:53
@@ -16,4 +16,5 @@
 :- include_module xml:dtd.
 :- include_module xml:encoding.
 :- include_module xml:parse.
+:- include_module xml:ns.

Index: xml.ns.m
===================================================================
RCS file: xml.ns.m
diff -N xml.ns.m
--- /dev/null   Wed Nov 15 09:24:47 2000
+++ xml.ns.m    Tue Jan  2 10:29:20 2001
@@ -0,0 +1,228 @@
+%---------------------------------------------------------------------------%
+% Copyright (C) 2000 The University of Melbourne.
+% This file may only be copied under the terms of the GNU Library General
+% Public License - see the file COPYING.LIB in the Mercury distribution.
+%---------------------------------------------------------------------------%
+%
+% File: xml.ns.m
+% Main author: conway at cs.mu.oz.au, inch at students.cs.mu.oz.au
+%
+% This module provides predicates to turn an xml document into a
"namespace-
+% aware" xml document.
+%
+%---------------------------------------------------------------------------%
+:- module xml:ns.
+
+:- interface.
+
+:- import_module list, array, string, std_util, io.
+:- import_module xml:doc.
+
+:- type nsDocument
+       --->    nsDoc(
+                   prestuff    :: list(ref(nsContent)),
+                   root        :: ref(nsContent),
+                   poststuff   :: list(ref(nsContent)),
+                   content     :: array(nsContent)
+               ).
+
+:- type nsContent
+       --->    nsElement(nsElement)
+       ;       pi(string, string)
+       ;       comment(string)
+       ;       data(string)
+       .
+
+:- type nsElement
+       --->    nsElement(
+                   eName       :: qName,
+                   eAttrs      :: list(nsAttribute),
+                   eContent    :: list(ref(content)),
+                   eNamespaces :: nsList       % Prefix - URI
+               ).
+
+:- type nsAttribute
+       --->    nsAttribute(
+                   aName       :: qName,
+                   aValue      :: string
+               ).
+
+:- type qName
+       --->    qName(
+                   localName   :: string,
+                   nsURI       :: string
+               ).
+
+:- type nsList == list(pair(string, string)).
+
+:- pred nsTranslate((xml:doc):document::in, nsDocument::out) is det.
+
+%---------------------------------------------------------------------------%
+:- implementation.
+%---------------------------------------------------------------------------%
+
+:- import_module int, assoc_list.
+:- import_module map.
+:- import_module xml:parse.
+
+:- type namespaces == map(string, string).
+
+nsTranslate(Doc, NsDoc) :-
+       traverse(Doc, [], NsDocContent),
+       NsDoc = nsDoc(Doc^prestuff, Doc^root, Doc^poststuff,
+                 array(NsDocContent)).
+
+:- pred traverse(document, list(nsContent), list(nsContent)).
+:- mode traverse(in, in, out) is det.
+
+traverse(Doc, Acc0, Acc) :-
+       traverse(Doc^content, map__init, "", Doc^root, Acc0, Acc).
+
+:- pred traverse(array(content), namespaces, string, ref(content),
+       list(nsContent), list(nsContent)).
+:- mode traverse(in, in, in, in, in, out) is det.
+
+traverse(ContentArray, Namespaces0, Default0, ContentRef, Acc0, Acc) :-
+       lookup(ContentArray, ContentRef, Content),
+       (
+               Content = element(Elem) ->
+
+               % examine the attributes to find any default namespaces
+               (
+                       defaultNamespace(Elem^eAttrs, Default1, Attrs0)
+               ->
+                       Default = Default1,
+                       Attrs1 = Attrs0
+               ;
+                       Default = Default0,
+                       Attrs1 = Elem^eAttrs
+               ),
+
+               % extract any namespace declaration and insert into tree
+               extractNamespaceDecls(Attrs1, NSList, Attrs2),
+               list__foldl((pred((Pref - URI)::in, NSs1::in,
+                       NSs2::out) is det :-
+                       map__set(NSs1, Pref, URI, NSs2)
+               ), NSList, Namespaces0, Namespaces),
+
+               namespaceizeName(Namespaces, Default, Elem^eName, Name),
+               map((pred(Attr0::in, Attr::out) is det :-
+                       Attr0 = attribute(AttrName0, Value),
+                       namespaceizeName(Namespaces, Default,
+                                       AttrName0, AttrName),
+                       Attr = nsAttribute(AttrName, Value)
+               ), Elem^eAttrs, Attrs),
+
+               Kids = Elem^eContent,
+               list__reverse(Kids, Kids0),
+
+               NsElem = nsElement(nsElement(Name, Attrs, Elem^eContent,
+                                       NSList)),
+               Acc1 = [NsElem|Acc0],
+               foldl(traverse, ContentArray, Namespaces, Default,
+                                      Kids0, Acc1, Acc)
+       ;
+               Acc = [convert_type(Content)| Acc0]
+       ).
+
+
+:- pred defaultNamespace(list(attribute), string, list(attribute)).
+:- mode defaultNamespace(in, out, out) is semidet.
+
+defaultNamespace([], _, _) :- fail.
+defaultNamespace([Attr|Attrs], Default, NewAttrs) :-
+       (
+               is_xmlns(Attr^aName)
+       ->
+               Default = Attr^aValue,
+               NewAttrs = Attrs
+       ;
+               Default = Default0,
+               NewAttrs = NewAttrs0,
+               defaultNamespace(Attrs, Default0, NewAttrs0)
+       ).
+
+
+:- pred extractNamespaceDecls(list(attribute), nsList, list(attribute)).
+:- mode extractNamespaceDecls(in, out, out) is det.
+
+extractNamespaceDecls([], [], []).
+extractNamespaceDecls([Attr|Attrs], NSList, NewAttrs) :-
+       split_on_colon(Attr^aName, Prefix, Suffix),
+       (
+               % eg. < book xmlns:isbn="someURI" >
+               % Prefix = xmlns
+               % Suffix = isbn
+
+               is_xmlns(Prefix) ->
+               NSList = [(Suffix - Attr^aValue) | NSList0],
+               NewAttrs = NewAttrs0
+       ;
+               NSList = NSList0,
+               NewAttrs = [Attr|NewAttrs0]
+       ),
+       extractNamespaceDecls(Attrs, NSList0, NewAttrs0).
+
+
+:- pred namespaceizeName(namespaces, string, string, qName).
+:- mode namespaceizeName(in, in, in, out) is det.
+
+namespaceizeName(Namespaces, Default, Name, QName) :-
+       split_on_colon(Name, Prefix, Suffix),
+       (
+               % for case when element name = prefix:suffix
+               map__search(Namespaces, Prefix, URI)
+       ->
+               QName = qName(Suffix, URI)
+       ;
+               % for case when attribute name = xmlns:suffix
+               is_xmlns(Prefix),
+               map__search(Namespaces, Suffix, URI)
+       ->
+               QName = qName(Suffix, URI)
+       ;
+               % for case when element name has no prefix
+               QName = qName(Suffix, Default)
+       ).
+
+
+:- pred split_on_colon(string::in, string::out, string::out) is det.
+
+split_on_colon(Name, Prefix, Suffix) :-
+       (
+           string__sub_string_search(Name, ":", Index)
+       ->
+           string__length(Name, Length),
+           string__right(Name, Length-(Index+1), Suffix),
+           string__left(Name, Index, Prefix)
+       ;
+           Suffix = Name,
+           Prefix = ""
+       ).
+
+
+:- pred is_xmlns(string::in) is semidet.
+is_xmlns("xmlns").
+
+
+:- func convert_type(content) = nsContent.
+
+convert_type(comment(S)) = comment(S).
+convert_type(data(S)) = data(S).
+convert_type(pi(S,S0)) = pi(S,S0).
+
+% XXX how to use inst such that I don't have to define the following line
+
+convert_type(element(_)) = nsElement(nsElement(qName("",""),[],[],[])).
+
+
+:- pred foldl(pred(array(content), namespaces, string, ref(content),
+       T, T), array(content), namespaces, string, list(ref(content)), T, T).
+:- mode foldl(pred(in, in, in, in, in, out) is det, in, in, in, in, in,
+       out) is det.
+
+foldl(_Pred, _, _, _, [], Acc, Acc).
+foldl(Pred, Content, NameSpaces, Default, [Ref|Refs], Acc0, Acc) :-
+       foldl(Pred, Content, NameSpaces, Default, Refs, Acc1, Acc),
+       call(Pred, Content, NameSpaces, Default, Ref, Acc0, Acc1).
+




--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list