require 'rdf/redland' require 'rdf/redland/uri' require 'rdf/redland/stream' module Redland # The Parser class for rdf. There are currently three types of parsers # *'rdfxml'- a rdf parser # *'ntriples' a An triples parser # *'turtle' - a parser for the turtle syntax as defined in # http://www.dajobe.org/2004/01/turtle/ # *'rss-tag-soup' - a parser for all RSS flavours and some atom # *'grddl' - GRDDL # # The last two may or may not be available depending on systems. # # model = Model.new() # parser = Parser.ntriples() # parser.parse_into_model(model,'file:./ical.rdf') class Parser attr_accessor :context # create a new Parser. if no name is given, it defaults to parsing RDF/XML syntax def initialize(name='rdfxml',mime_type="application/rdf+xml",uri=nil,context=nil) @context = nil @idents = [] uri=uri.uri if uri @parser = Redland.librdf_new_parser($world.world,name,mime_type,uri) raise RedlandError.new("Parser construction failed") if !@parser ObjectSpace.define_finalizer(self,Parser.create_finalizer(@parser)) end def Parser.create_finalizer(parser) proc {|id| "Finalizer on #{id}" #$log_final.info "closing parser" Redland::librdf_free_parser(parser) } end # create a parser for the ntriples syntax def Parser.ntriples(uri=nil) return Parser.new('ntriples',"",uri) end # create a parser for the turtle syntax def Parser.turtle(uri=nil) return Parser.new('turtle',"",uri) end # create a parser for rdf syntax def Parser.raptor(uri=nil) return Parser.new('rdfxml','application/rdf+xml',uri) end # Parse the given uri with optional base_uri and return a # Stream. If block_given, yield the Statement instead # Returns nil on failure. def parse_as_stream(uri,base_uri=nil) if uri.class == String then uri = Uri.new(uri) end if base_uri.class == String then base_uri = Uri.new(base_uri) end unless base_uri my_stream = Redland::librdf_parser_parse_as_stream @parser, uri.uri, nil else my_stream = Redland::librdf_parser_parse_as_stream @parser, uri.uri ,base_uri.uri end return nil if !my_stream stream = Stream.new(my_stream,self) if !block_given? return stream else while not stream.end? yield stream.current stream.next end end end # Parse the syntax at the uri Uri with optional base # Uri base_uri into Model model. If the base_uri is # given then the content is parsed as if it was at the base_uri rather # than the uri. If the optional context is given, the statement is added to the context # # NOTE: The order of the arguments to this method is different from the C API and other language bindings. def parse_into_model(model,uri,base_uri=nil,context=@context) #puts "parse_into_model context is #{context}" if uri.class == String uri = Uri.new(uri) end if base_uri if base_uri.class == String base_uri = Uri.new(base_uri) end else base_uri=uri end if not context begin r = Redland.librdf_parser_parse_into_model(@parser,uri.uri,base_uri.uri,model.model) rescue RedlandError => err print "caught error"+ err end else #context raise RedlandError.new("Cannot make a Node from an object of #{context.class}") if not context context = Node.ensure(context) my_stream = Redland::librdf_parser_parse_as_stream(@parser,uri.uri,base_uri.uri) Redland.librdf_model_context_add_statements(model.model,context,my_stream) #self.parse_as_stream(uri,base_uri){|s| model.add_statement(s,context)} end end # Parse the syntax in string with required base Uri # base_uri # # Returns a Stream or yields Statement # if block given. Returns nil on failure. def parse_string_as_stream(string,base_uri) if base_uri.class == String then base_uri = Uri.new(base_uri) end if not base_uri then raise RedlandError("A base URI is required when parsing a string") end my_stream = Redland::librdf_parser_parse_string_as_stream(@parser,string,base_uri.uri) return nil if !my_stream stream = Stream.new(my_stream,self) return stream if !block_given? while not stream.end? yield stream.current stream.next end end # Parse the syntax in String string with required Uri # base_uri into Model model. # if context is given then the context information is stored as well # # NOTE: The order of the arguments to this method is different from the C API and other language bindings. def parse_string_into_model(model,string,base_uri=nil,context=@context) if base_uri.class == String then base_uri = Uri.new(base_uri)end if not base_uri then raise RedlandError.new("A base URI is required when parsing a string") end if not context return (Redland::librdf_parser_parse_string_into_model(@parser,string,base_uri.uri,model.model)== 0) else self.parse_string_as_stream(@parser,string,base_uri.uri){|s| model.add_statement(s,context)} end end #Get a parser feature. The feature is a Uri def feature(uri) if uri.class == String then uri = Uri.new(uri) end value = Redland::librdf_parser_get_feature(@parser,uri.uri) if value == "NULL" or value == nil return nil else return Node.new(:from_object=>value) end end # Set a parser feature. The feature is named Uri # uri and the value is a Node. def setFeature(uri,value) if uri.class == String then uri = Uri.new(uri) end if value.class == String then value = Node.new(:literal=>value) end return (Redland::librdf_parser_set_feature(@parser,uri.uri,value.node) == 0) end def add_ident(node) @idents << node end def smush_string(string,model,idents=@idents) to_change = {} temp_model = Model.new() self.parse_string_into_model(temp_model,string,'http://xml.com') idents.each do |ident| temp_model.find(nil,ident,nil){|s,p,o| old_id = s new_id = model.subject(p,o) if new_id to_change[old_id.to_s]= new_id if !to_change.key?(old_id.to_s) end } end #puts to_change temp_model.triples do |s,p,o| s = to_change[s.to_s] if to_change.key?(s.to_s) model.add(s,p,o) end end def smush_file(model,uri,base_uri=nil,context=nil,idents=@idents) to_change = {} temp_model = Model.new() self.parse_into_model(temp_model,uri,base_uri,context) idents.each do |ident| temp_model.find(nil,ident,nil){|s,p,o| old_id = s new_id = model.subject(p,o) if new_id to_change[old_id.to_s]= new_id if !to_change.key?(old_id.to_s) end } end #puts to_change temp_model.triples do |s,p,o| s = to_change[s.to_s] if to_change.key?(s.to_s) model.add(s,p,o,context) end end end # Class for parsing a file class ContextParser require 'uri' # Create a new ContextParser for a file def initialize(file) case file when String file = file.expand_path(file) raise RedlandError("File doesn't exist") unless File.file?(file) @uri == Uri.new(file) when File end @parser = Redland.librdf_new_parser($world.world,name,mime_type,@uri.uri,@uri.uri) raise RedlandError.new("Parser construction failed") if !@parser ObjectSpace.define_finalizer(self,Parser.create_finalizer(@parser)) end # Parse a file into a model (?? confirm - why doesn't it use most of it's args) def parse_into_model(model,string,base_uri) super(model,@uri,nil,@uri) end end end #module Redland #end