[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