633 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			633 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
|   | /*  $Id$ | ||
|  | 
 | ||
|  |     Part of SWI-Prolog | ||
|  | 
 | ||
|  |     Author:        Jan Wielemaker | ||
|  |     E-mail:        J.Wielemaker@cs.vu.nl | ||
|  |     WWW:           http://www.swi-prolog.org | ||
|  |     Copyright (C): 2002-2009, University of Amsterdam | ||
|  | 
 | ||
|  |     This program 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. | ||
|  | 
 | ||
|  |     This program 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 Lesser General Public | ||
|  |     License along with this library; if not, write to the Free Software | ||
|  |     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | ||
|  | 
 | ||
|  |     As a special exception, if you link this library with other files, | ||
|  |     compiled with a Free Software compiler, to produce an executable, this | ||
|  |     library does not by itself cause the resulting executable to be covered | ||
|  |     by the GNU General Public License. This exception does not however | ||
|  |     invalidate any other reasons why the executable file might be covered by | ||
|  |     the GNU General Public License. | ||
|  | */ | ||
|  | 
 | ||
|  | :- module(rdf_parser, | ||
|  | 	  [ xml_to_plrdf/3,		% +XMLTerm, -RDFTerm, +State | ||
|  | 	    element_to_plrdf/3,		% +ContentList, -RDFTerm, +State | ||
|  | 	    make_rdf_state/3,		% +Options, -State, -RestOptions | ||
|  | 	    rdf_modify_state/3,		% +XMLAttrs, +State0, -State | ||
|  | 	    rdf_name_space/1 | ||
|  | 	  ]). | ||
|  | :- use_module(rewrite). | ||
|  | :- use_module(library(sgml)).		% xml_name/1 | ||
|  | :- use_module(library(lists)). | ||
|  | :- use_module(library(uri)). | ||
|  | :- use_module(library(record)). | ||
|  | 
 | ||
|  | :- op(500, fx, \?).			% Optional (attrs) | ||
|  | 
 | ||
|  | term_expansion(F, T) :- rew_term_expansion(F, T). | ||
|  | goal_expansion(F, T) :- rew_goal_expansion(F, T). | ||
|  | 
 | ||
|  | goal_expansion(attrs(Attrs, List), Goal) :- | ||
|  | 	translate_attrs(List, Attrs, Goal). | ||
|  | 
 | ||
|  | translate_attrs(Var, Attrs, rewrite(Var, Attrs)) :- | ||
|  | 	var(Var), !. | ||
|  | translate_attrs([], _, true) :- !. | ||
|  | translate_attrs([H], Attrs, Goal) :- !, | ||
|  | 	(   var(H) | ||
|  | 	->  Goal = rewrite(H, Attrs) | ||
|  | 	;   H = \?Optional | ||
|  | 	->  Goal = (   member(A, Attrs), | ||
|  | 	               OptRewrite | ||
|  | 		   ->  true | ||
|  | 		   ;   true | ||
|  | 		   ), | ||
|  | 	    expand_goal(rewrite(\Optional, A), OptRewrite) | ||
|  | 	;   Goal = (   member(A, Attrs), | ||
|  | 	               Rewrite | ||
|  | 		   ->  true | ||
|  | 		   ), | ||
|  | 	    expand_goal(rewrite(H, A), Rewrite) | ||
|  | 	). | ||
|  | translate_attrs([H|T], Attrs0, (G0, G1)) :- !, | ||
|  | 	(   var(H) | ||
|  | 	->  G0 = rewrite(H, Attrs0), | ||
|  | 	    Attrs1 = Attrs0 | ||
|  | 	;   H = \?Optional | ||
|  | 	->  G0 = (   select(A, Attrs0, Attrs1), | ||
|  | 	             OptRewrite | ||
|  | 		 ->  true | ||
|  | 		 ;   Attrs1 = Attrs0 | ||
|  | 		 ), | ||
|  | 	    expand_goal(rewrite(\Optional, A), OptRewrite) | ||
|  | 	;   G0 = (   select(A, Attrs0, Attrs1), | ||
|  | 	             Rewrite | ||
|  | 		 ), | ||
|  | 	    expand_goal(rewrite(H, A), Rewrite) | ||
|  | 	), | ||
|  | 	translate_attrs(T, Attrs1, G1). | ||
|  | translate_attrs(Rule, Attrs, Goal) :- | ||
|  | 	expand_goal(rewrite(Rule, Attrs), Goal). | ||
|  | 
 | ||
|  | 
 | ||
|  | :- multifile rdf_name_space/1. | ||
|  | :- dynamic   rdf_name_space/1. | ||
|  | 
 | ||
|  | %%	rdf_name_space(?URL) is nondet. | ||
|  | % | ||
|  | %	True if URL must be handled  as rdf: Determines special handling | ||
|  | %	of rdf:about, rdf:resource, etc. | ||
|  | 
 | ||
|  | 
 | ||
|  | rdf_name_space('http://www.w3.org/1999/02/22-rdf-syntax-ns#'). | ||
|  | rdf_name_space('http://www.w3.org/TR/REC-rdf-syntax'). | ||
|  | 
 | ||
|  | 
 | ||
|  | :- record | ||
|  | 	rdf_state(base_uri='', | ||
|  | 		  lang='', | ||
|  | 		  ignore_lang=false, | ||
|  | 		  convert_typed_literal). | ||
|  | 
 | ||
|  | 
 | ||
|  | %%	xml_to_plrdf(+RDFElementOrObject, -RDFTerm, +State) | ||
|  | % | ||
|  | %	Translate an XML (using namespaces)  term   into  an Prolog term | ||
|  | %	representing the RDF data.  This  term   can  then  be  fed into | ||
|  | %	rdf_triples/[2,3] to create a list of   RDF triples. State is an | ||
|  | %	instance of an rdf_state record. | ||
|  | 
 | ||
|  | xml_to_plrdf(Element, RDF, State) :- | ||
|  | 	(   is_list(Element) | ||
|  | 	->  rewrite(\xml_content_objects(RDF, State), Element) | ||
|  | 	;   rewrite(\xml_objects(RDF, State), Element) | ||
|  | 	). | ||
|  | 
 | ||
|  | %%	element_to_plrdf(+DOM, -RDFTerm, +State) | ||
|  | % | ||
|  | %	Rewrite a single XML element. | ||
|  | 
 | ||
|  | element_to_plrdf(Element, RDF, State) :- | ||
|  | 	rewrite(\nodeElementList(RDF, State), [Element]). | ||
|  | 
 | ||
|  | xml_objects(Objects, Options0) ::= | ||
|  | 	E0, | ||
|  | 	{ modify_state(E0, Options0, E, Options), !, | ||
|  | 	  rewrite(\xml_objects(Objects, Options), E) | ||
|  | 	}. | ||
|  | xml_objects(Objects, Options) ::= | ||
|  | 	element((\rdf('RDF'), !), | ||
|  | 		_, | ||
|  | 		\nodeElementList(Objects, Options)), | ||
|  | 	!. | ||
|  | xml_objects(Objects, Options) ::= | ||
|  | 	element(_, _, \xml_content_objects(Objects, Options)). | ||
|  | 
 | ||
|  | xml_content_objects([], _) ::= | ||
|  | 	[]. | ||
|  | xml_content_objects([H|T], Options) ::= | ||
|  | 	[ \xml_objects(H, Options) | ||
|  | 	| \xml_content_objects(T, Options) | ||
|  | 	]. | ||
|  | 
 | ||
|  | 
 | ||
|  | nodeElementList([], _Options) ::= | ||
|  | 	[], !. | ||
|  | nodeElementList(L, Options) ::= | ||
|  | 	[ (\ws, !) | ||
|  | 	| \nodeElementList(L, Options) | ||
|  | 	]. | ||
|  | nodeElementList([H|T], Options) ::= | ||
|  | 	[ \nodeElementOrError(H, Options) | ||
|  | 	| \nodeElementList(T, Options) | ||
|  | 	]. | ||
|  | 
 | ||
|  | nodeElementOrError(H, Options) ::= | ||
|  | 	\nodeElement(H, Options), !. | ||
|  | nodeElementOrError(unparsed(Data), _Options) ::= | ||
|  | 	Data. | ||
|  | 
 | ||
|  | nodeElement(description(Type, About, Properties), Options) ::= | ||
|  | 	\description(Type, About, Properties, Options). | ||
|  | 
 | ||
|  | 
 | ||
|  | 		 /******************************* | ||
|  | 		 *	    DESCRIPTION		* | ||
|  | 		 *******************************/ | ||
|  | 
 | ||
|  | description(Type, About, Properties, Options0) ::= | ||
|  | 	E0, | ||
|  | 	{ modify_state(E0, Options0, E, Options), !, | ||
|  | 	  rewrite(\description(Type, About, Properties, Options), E) | ||
|  | 	}. | ||
|  | description(description, About, Properties, Options) ::= | ||
|  | 	element(\rdf('Description'), | ||
|  | 		\attrs([ \?idAboutAttr(About, Options) | ||
|  | 		       | \propAttrs(PropAttrs, Options) | ||
|  | 		       ]), | ||
|  | 		\propertyElts(PropElts, Options)), | ||
|  | 	{ !, append(PropAttrs, PropElts, Properties) | ||
|  | 	}. | ||
|  | description(Type, About, Properties, Options) ::= | ||
|  | 	element(\name_uri(Type, Options), | ||
|  | 		\attrs([ \?idAboutAttr(About, Options) | ||
|  | 		       | \propAttrs(PropAttrs, Options) | ||
|  | 		       ]), | ||
|  | 		\propertyElts(PropElts, Options)), | ||
|  | 	{ append(PropAttrs, PropElts, Properties) | ||
|  | 	}. | ||
|  | 
 | ||
|  | propAttrs([], _) ::= | ||
|  | 	[], !. | ||
|  | propAttrs([H|T], Options) ::= | ||
|  | 	[ \propAttr(H, Options) | ||
|  | 	| \propAttrs(T, Options) | ||
|  | 	]. | ||
|  | 
 | ||
|  | propAttr(rdf:type = URI, Options) ::= | ||
|  | 	\rdf_or_unqualified(type) = \value_uri(URI, Options), !. | ||
|  | propAttr(Name = Literal, Options) ::= | ||
|  | 	Name = Value, | ||
|  | 	{ mkliteral(Value, Literal, Options) | ||
|  | 	}. | ||
|  | 
 | ||
|  | propertyElts([], _) ::= | ||
|  | 	[], !. | ||
|  | propertyElts(Elts, Options) ::= | ||
|  | 	[ (\ws, !) | ||
|  | 	| \propertyElts(Elts, Options) | ||
|  | 	]. | ||
|  | propertyElts([H|T], Options) ::= | ||
|  | 	[ \propertyElt(H, Options) | ||
|  | 	| \propertyElts(T, Options) | ||
|  | 	]. | ||
|  | 
 | ||
|  | propertyElt(E, Options) ::= | ||
|  | 	\propertyElt(Id, Name, Value, Options), | ||
|  | 	{ mkprop(Name, Value, Prop), | ||
|  | 	  (   var(Id) | ||
|  | 	  ->  E = Prop | ||
|  | 	  ;   E = id(Id, Prop) | ||
|  | 	  ) | ||
|  | 	}. | ||
|  | 
 | ||
|  | mkprop(NS:Local, Value, rdf:Local = Value) :- | ||
|  | 	rdf_name_space(NS), !. | ||
|  | mkprop(Name, Value, Name = Value). | ||
|  | 
 | ||
|  | 
 | ||
|  | propertyElt(Id, Name, Value, Options0) ::= | ||
|  | 	E0, | ||
|  | 	{ modify_state(E0, Options0, E, Options), !, | ||
|  | 	  rewrite(\propertyElt(Id, Name, Value, Options), E) | ||
|  | 	}. | ||
|  | propertyElt(Id, Name, Value, Options) ::= | ||
|  | 	\literalPropertyElt(Id, Name, Value, Options), !. | ||
|  | 					% 5.14 emptyPropertyElt | ||
|  | propertyElt(Id, Name, Value, Options) ::= | ||
|  | 	element(Name, A, \all_ws), | ||
|  | 	{ !, | ||
|  | 	  rewrite(\emptyPropertyElt(Id, Value, Options), A) | ||
|  | 	}. | ||
|  | 
 | ||
|  | propertyElt(_, Name, description(description, Id, Properties), Options) ::= | ||
|  | 	element(Name, | ||
|  | 		\attrs([ \parseResource, | ||
|  | 			 \?idAboutAttr(Id, Options) | ||
|  | 		       ]), | ||
|  | 		\propertyElts(Properties, Options)), | ||
|  | 	!. | ||
|  | propertyElt(_, Name, Literal, Options) ::= | ||
|  | 	element(Name, | ||
|  | 		\attrs([ \parseLiteral | ||
|  | 		       ]), | ||
|  | 		Content), | ||
|  | 	{ !, | ||
|  | 	  literal_value(Content, Literal, Options) | ||
|  | 	}. | ||
|  | propertyElt(Id, Name, collection(Elements), Options) ::= | ||
|  | 	element(Name, | ||
|  | 		\attrs([ \parseCollection, | ||
|  | 			 \?idAttr(Id, Options) | ||
|  | 		       ]), | ||
|  | 		\nodeElementList(Elements, Options)). | ||
|  | propertyElt(Id, Name, Literal, Options) ::= | ||
|  | 	element(Name, | ||
|  | 		\attrs([ \?idAttr(Id, Options) | ||
|  | 		       ]), | ||
|  | 		[ Value ]), | ||
|  | 	{ atom(Value), !, | ||
|  | 	  mkliteral(Value, Literal, Options) | ||
|  | 	}. | ||
|  | propertyElt(Id, Name, Value, Options) ::= | ||
|  | 	element(Name, | ||
|  | 		\attrs([ \?idAttr(Id, Options) | ||
|  | 		       ]), | ||
|  | 		\an_rdf_object(Value, Options)), !. | ||
|  | propertyElt(Id, Name, unparsed(Value), Options) ::= | ||
|  | 	element(Name, | ||
|  | 		\attrs([ \?idAttr(Id, Options) | ||
|  | 		       ]), | ||
|  | 		Value). | ||
|  | 
 | ||
|  | literalPropertyElt(Id, Name, Literal, Options) ::= | ||
|  | 	element(Name, | ||
|  | 		\attrs([ \typeAttr(Type, Options), | ||
|  | 			 \?idAttr(Id, Options) | ||
|  | 		       ]), | ||
|  | 		Content), | ||
|  | 	{ typed_literal(Type, Content, Literal, Options) | ||
|  | 	}. | ||
|  | 
 | ||
|  | emptyPropertyElt(Id, Literal, Options) ::= | ||
|  | 	\attrs([ \?idAttr(Id, Options), | ||
|  | 		 \?parseLiteral | ||
|  | 	       | \noMoreAttrs | ||
|  | 	       ]), | ||
|  | 	{ !, | ||
|  | 	  mkliteral('', Literal, Options) | ||
|  | 	}. | ||
|  | emptyPropertyElt(Id, | ||
|  | 		 description(description, About, Properties), | ||
|  | 		 Options) ::= | ||
|  | 	\attrs([ \?idAttr(Id, Options), | ||
|  | 		 \?aboutResourceEmptyElt(About, Options), | ||
|  | 		 \?parseResource | ||
|  | 	       | \propAttrs(Properties, Options) | ||
|  | 	       ]), !. | ||
|  | 
 | ||
|  | aboutResourceEmptyElt(about(URI), Options) ::= | ||
|  | 	\resourceAttr(URI, Options), !. | ||
|  | aboutResourceEmptyElt(node(URI), _Options) ::= | ||
|  | 	\nodeIDAttr(URI). | ||
|  | 
 | ||
|  | %%	literal_value(+In, -Value, +Options) | ||
|  | % | ||
|  | %	Create the literal value for rdf:parseType="Literal" attributes. | ||
|  | %	The content is the Prolog XML DOM tree for the literal. | ||
|  | % | ||
|  | %	@tbd	Note that the specs demand a canonical textual representation | ||
|  | %		of the XML data as a Unicode string.  For now the user can | ||
|  | %		achieve this using the convert_typed_literal hook. | ||
|  | 
 | ||
|  | literal_value(Value, literal(type(rdf:'XMLLiteral', Value)), _). | ||
|  | 
 | ||
|  | %%	mkliteral(+Atom, -Object, +Options) | ||
|  | % | ||
|  | %	Translate attribute value Atom into an RDF object using the | ||
|  | %	lang(Lang) option from Options. | ||
|  | 
 | ||
|  | mkliteral(Text, literal(Val), Options) :- | ||
|  | 	atom(Text), | ||
|  | 	(   rdf_state_lang(Options, Lang), | ||
|  | 	    Lang \== '' | ||
|  | 	->  Val = lang(Lang, Text) | ||
|  | 	;   Val = Text | ||
|  | 	). | ||
|  | 
 | ||
|  | %%	typed_literal(+Type, +Content, -Literal, +Options) | ||
|  | % | ||
|  | %	Handle a literal attribute with rdf:datatype=Type qualifier. NB: | ||
|  | %	possibly  it  is  faster  to  use  a  global  variable  for  the | ||
|  | %	conversion hook. | ||
|  | 
 | ||
|  | typed_literal(Type, Content, literal(Object), Options) :- | ||
|  | 	rdf_state_convert_typed_literal(Options, Convert), | ||
|  | 	nonvar(Convert), !, | ||
|  | 	(   catch(call(Convert, Type, Content, Object), E, true) | ||
|  | 	->  (   var(E) | ||
|  | 	    ->	true | ||
|  | 	    ;	Object = E | ||
|  | 	    ) | ||
|  | 	;   Object = error(cannot_convert(Type, Content), _) | ||
|  | 	). | ||
|  | typed_literal(Type, [], literal(type(Type, '')), _Options) :- !. | ||
|  | typed_literal(Type, [Text], literal(type(Type, Text)), _Options) :- !. | ||
|  | typed_literal(Type, Content, literal(type(Type, Content)), _Options). | ||
|  | 
 | ||
|  | 
 | ||
|  | idAboutAttr(id(Id), Options) ::= | ||
|  | 	\idAttr(Id, Options), !. | ||
|  | idAboutAttr(about(About), Options) ::= | ||
|  | 	\aboutAttr(About, Options), !. | ||
|  | idAboutAttr(node(About), _Options) ::= | ||
|  | 	\nodeIDAttr(About), !. | ||
|  | 
 | ||
|  | %%	an_rdf_object(-Object, +OptionsURI) | ||
|  | % | ||
|  | %	Deals with an object, but there may be spaces around.  I'm still | ||
|  | %	not sure where to deal with these.  Best is to ask the XML parser | ||
|  | %	to get rid of them, So most likely this code will change if this | ||
|  | %	happens. | ||
|  | 
 | ||
|  | an_rdf_object(Object, Options) ::= | ||
|  | 	[ \nodeElement(Object, Options) | ||
|  | 	], !. | ||
|  | an_rdf_object(Object, Options) ::= | ||
|  | 	[ (\ws, !) | ||
|  | 	| \an_rdf_object(Object, Options) | ||
|  | 	]. | ||
|  | an_rdf_object(Object, Options) ::= | ||
|  | 	[ \nodeElement(Object, Options), | ||
|  | 	  \ws | ||
|  | 	], !. | ||
|  | 
 | ||
|  | ws ::= | ||
|  | 	A, | ||
|  | 	{ atom(A), | ||
|  | 	  atom_chars(A, Chars), | ||
|  | 	  all_blank(Chars), ! | ||
|  | 	}. | ||
|  | ws ::= | ||
|  | 	pi(_). | ||
|  | 
 | ||
|  | all_ws ::= | ||
|  | 	[], !. | ||
|  | all_ws ::= | ||
|  | 	[\ws | \all_ws]. | ||
|  | 
 | ||
|  | all_blank([]). | ||
|  | all_blank([H|T]) :- | ||
|  | 	char_type(H, space),		% SWI-Prolog specific | ||
|  | 	all_blank(T). | ||
|  | 
 | ||
|  | 
 | ||
|  | 		 /******************************* | ||
|  | 		 *	   RDF ATTRIBUTES	* | ||
|  | 		 *******************************/ | ||
|  | 
 | ||
|  | idAttr(Id, Options) ::= | ||
|  | 	\rdf_or_unqualified('ID') = \uniqueid(Id, Options). | ||
|  | 
 | ||
|  | aboutAttr(About, Options) ::= | ||
|  | 	\rdf_or_unqualified(about) = \value_uri(About, Options). | ||
|  | 
 | ||
|  | nodeIDAttr(About) ::= | ||
|  | 	\rdf_or_unqualified(nodeID) = About. | ||
|  | 
 | ||
|  | resourceAttr(URI, Options) ::= | ||
|  | 	\rdf_or_unqualified(resource) = \value_uri(URI, Options). | ||
|  | 
 | ||
|  | typeAttr(Type, Options) ::= | ||
|  | 	\rdf_or_unqualified(datatype) = \value_uri(Type, Options). | ||
|  | 
 | ||
|  | name_uri(URI, Options) ::= | ||
|  | 	NS:Local, | ||
|  | 	{   !, atom_concat(NS, Local, A), | ||
|  | 	    rewrite(\value_uri(URI, Options), A) | ||
|  | 	}. | ||
|  | name_uri(URI, Options) ::= | ||
|  | 	\value_uri(URI, Options). | ||
|  | 
 | ||
|  | value_uri(URI, Options) ::= | ||
|  | 	A, | ||
|  | 	{   rdf_state_base_uri(Options, Base), | ||
|  | 	    uri_normalized_iri(A, Base, URI) | ||
|  | 	}. | ||
|  | 
 | ||
|  | 
 | ||
|  | globalid(Id, Options) ::= | ||
|  | 	A, | ||
|  | 	{   make_globalid(A, Options, Id) | ||
|  | 	}. | ||
|  | 
 | ||
|  | uniqueid(Id, Options) ::= | ||
|  | 	A, | ||
|  | 	{   unique_xml_name(A, HashID), | ||
|  | 	    make_globalid(HashID, Options, Id) | ||
|  | 	}. | ||
|  | 
 | ||
|  | unique_xml_name(Name, HashID) :- | ||
|  | 	atom_concat(#, Name, HashID), | ||
|  | 	(   xml_name(Name) | ||
|  | 	->  true | ||
|  | 	;   print_message(warning, rdf(not_a_name(Name))) | ||
|  | 	). | ||
|  | 
 | ||
|  | make_globalid(In, Options, Id) :- | ||
|  | 	rdf_state_base_uri(Options, Base), | ||
|  | 	uri_normalized_iri(In, Base, Id). | ||
|  | 
 | ||
|  | parseLiteral    ::= \rdf_or_unqualified(parseType) = 'Literal'. | ||
|  | parseResource   ::= \rdf_or_unqualified(parseType) = 'Resource'. | ||
|  | parseCollection ::= \rdf_or_unqualified(parseType) = 'Collection'. | ||
|  | 
 | ||
|  | 
 | ||
|  | 		 /******************************* | ||
|  | 		 *	     PRIMITIVES		* | ||
|  | 		 *******************************/ | ||
|  | 
 | ||
|  | rdf(Tag) ::= | ||
|  | 	NS:Tag, | ||
|  | 	{ rdf_name_space(NS), ! | ||
|  | 	}. | ||
|  | 
 | ||
|  | rdf_or_unqualified(Tag) ::= | ||
|  | 	Tag. | ||
|  | rdf_or_unqualified(Tag) ::= | ||
|  | 	NS:Tag, | ||
|  | 	{ rdf_name_space(NS), ! | ||
|  | 	}. | ||
|  | 
 | ||
|  | 
 | ||
|  | 		 /******************************* | ||
|  | 		 *	       BASICS		* | ||
|  | 		 *******************************/ | ||
|  | 
 | ||
|  | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
|  | This code is translated by the  goal_expansion/2   rule  at the start of | ||
|  | this file. We leave the original code for reference. | ||
|  | 
 | ||
|  | attrs(Bag) ::= | ||
|  | 	L0, | ||
|  | 	{ do_attrs(Bag, L0) | ||
|  | 	}. | ||
|  | 
 | ||
|  | do_attrs([], _) :- !. | ||
|  | do_attrs([\?H|T], L0) :- !,		% optional | ||
|  | 	(   select(X, L0, L), | ||
|  | 	    rewrite(\H, X) | ||
|  | 	->  true | ||
|  | 	;   L = L0 | ||
|  | 	), | ||
|  | 	do_attrs(T, L). | ||
|  | do_attrs([H|T], L0) :- | ||
|  | 	select(X, L0, L), | ||
|  | 	rewrite(H, X), !, | ||
|  | 	do_attrs(T, L). | ||
|  | do_attrs(C, L) :- | ||
|  | 	rewrite(C, L). | ||
|  | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
|  | 
 | ||
|  | %	\noMoreAttrs | ||
|  | % | ||
|  | %	Check attribute-list is empty.  Reserved xml: attributes are | ||
|  | %	excluded from this test. | ||
|  | 
 | ||
|  | noMoreAttrs ::= | ||
|  | 	[], !. | ||
|  | noMoreAttrs ::= | ||
|  | 	[ xml:_=_ | ||
|  | 	| \noMoreAttrs | ||
|  | 	]. | ||
|  | 
 | ||
|  | %%	modify_state(+Element0, +Options0, -Element, -Options) is semidet. | ||
|  | % | ||
|  | %	If Element0 contains xml:base = Base, strip it from the | ||
|  | %	attributes list and update base_uri(_) in the Options | ||
|  | % | ||
|  | %	It Element0 contains xml:lang = Lang, strip it from the | ||
|  | %	attributes list and update lang(_) in the Options | ||
|  | % | ||
|  | %	Remove all xmlns=_, xmlns:_=_ and xml:_=_.  Only succeed | ||
|  | %	if something changed. | ||
|  | 
 | ||
|  | modify_state(element(Name, Attrs0, Content), Options0, | ||
|  | 	     element(Name, Attrs,  Content), Options) :- | ||
|  | 	modify_a_state(Attrs0, Options0, Attrs, Options), | ||
|  | 	Attrs0 \== Attrs. | ||
|  | 
 | ||
|  | rdf_modify_state(Attributes, State0, State) :- | ||
|  | 	modify_a_state(Attributes, State0, _, State). | ||
|  | 
 | ||
|  | 
 | ||
|  | modify_a_state([], Options, [], Options). | ||
|  | modify_a_state([Name=Value|T0], Options0, T, Options) :- | ||
|  | 	modify_a(Name, Value, Options0, Options1), !, | ||
|  | 	modify_a_state(T0, Options1, T, Options). | ||
|  | modify_a_state([H|T0], Options0, [H|T], Options) :- | ||
|  | 	modify_a_state(T0, Options0, T, Options). | ||
|  | 
 | ||
|  | 
 | ||
|  | modify_a(xml:base, Base1, Options0, Options) :- !, | ||
|  | 	rdf_state_base_uri(Options0, Base0), | ||
|  | 	remove_fragment(Base1, Base2), | ||
|  | 	uri_normalized_iri(Base2, Base0, Base), | ||
|  | 	set_base_uri_of_rdf_state(Base, Options0, Options). | ||
|  | modify_a(xml:lang, Lang, Options0, Options) :- !, | ||
|  | 	rdf_state_ignore_lang(Options0, false), !, | ||
|  | 	set_lang_of_rdf_state(Lang, Options0, Options). | ||
|  | modify_a(xmlns, _, Options, Options). | ||
|  | modify_a(xmlns:_, _, Options, Options). | ||
|  | modify_a(xml:_, _, Options, Options). | ||
|  | 
 | ||
|  | 
 | ||
|  | %%	remove_fragment(+URI, -WithoutFragment) | ||
|  | % | ||
|  | %	When handling xml:base, we must delete the possible fragment. | ||
|  | 
 | ||
|  | remove_fragment(URI, Plain) :- | ||
|  | 	sub_atom(URI, B, _, _, #), !, | ||
|  | 	sub_atom(URI, 0, B, _, Plain). | ||
|  | remove_fragment(URI, URI). | ||
|  | 
 | ||
|  | 
 | ||
|  | 		 /******************************* | ||
|  | 		 *     HELP PCE-EMACS A BIT	* | ||
|  | 		 *******************************/ | ||
|  | 
 | ||
|  | :- multifile | ||
|  | 	emacs_prolog_colours:term_colours/2, | ||
|  | 	emacs_prolog_colours:goal_classification/2. | ||
|  | 
 | ||
|  | expand(c(X), _, X) :- !. | ||
|  | expand(In,   Pattern, Colours) :- | ||
|  | 	compound(In), !, | ||
|  | 	In =.. [F|Args], | ||
|  | 	expand_list(Args, PatternArgs, ColourArgs), | ||
|  | 	Pattern =.. [F|PatternArgs], | ||
|  | 	Colours = functor(F) - ColourArgs. | ||
|  | expand(X, X, classify). | ||
|  | 
 | ||
|  | expand_list([], [], []). | ||
|  | expand_list([H|T], [PH|PT], [CH|CT]) :- | ||
|  | 	expand(H, PH, CH), | ||
|  | 	expand_list(T, PT, CT). | ||
|  | 
 | ||
|  | :- discontiguous | ||
|  | 	term_expansion/2. | ||
|  | 
 | ||
|  | term_expansion(term_colours(C), | ||
|  | 	       emacs_prolog_colours:term_colours(Pattern, Colours)) :- | ||
|  | 	expand(C, Pattern, Colours). | ||
|  | 
 | ||
|  | term_colours((c(head(+(1))) ::= c(match), {c(body)})). | ||
|  | term_colours((c(head(+(1))) ::= c(match))). | ||
|  | 
 | ||
|  | emacs_prolog_colours:goal_classification(\_, expanded). | ||
|  | 
 | ||
|  | :- dynamic | ||
|  | 	prolog:meta_goal/2. | ||
|  | :- multifile | ||
|  | 	prolog:meta_goal/2, | ||
|  | 	prolog:called_by/2. | ||
|  | 
 | ||
|  | prolog:meta_goal(rewrite(A, _), [A]). | ||
|  | prolog:meta_goal(\A,		[A+1]). | ||
|  | 
 | ||
|  | prolog:called_by(attrs(Attrs, _Term), Called) :- | ||
|  | 	findall(G+1, sub_term(\?G, Attrs), Called, Tail), | ||
|  | 	findall(G+1, sub_term(\G, Attrs), Tail). | ||
|  | 
 | ||
|  | 
 |