@@ -116,7 +116,14 @@ def initialize(url, **options, &block)
116
116
# Close the http connection when object is deallocated
117
117
def self . finalize ( klass )
118
118
proc do
119
- klass . shutdown if klass . respond_to? ( :shutdown )
119
+ if klass . respond_to? ( :shutdown )
120
+ begin
121
+ # Attempt asynchronous shutdown
122
+ Thread . new { klass . shutdown }
123
+ rescue ThreadError
124
+ klass . shutdown
125
+ end
126
+ end
120
127
end
121
128
end
122
129
@@ -423,7 +430,13 @@ def self.parse_json_bindings(json, nodes = {})
423
430
end
424
431
RDF ::Query ::Solution . new ( row )
425
432
end
426
- RDF ::Query ::Solutions . new ( solutions )
433
+ solns = RDF ::Query ::Solutions . new ( solutions )
434
+
435
+ # Set variable names explicitly
436
+ if json . fetch ( 'head' , { } ) . has_key? ( 'vars' )
437
+ solns . variable_names = json [ 'head' ] [ 'vars' ] . map ( &:to_sym )
438
+ end
439
+ solns
427
440
end
428
441
end
429
442
@@ -484,20 +497,23 @@ def self.parse_tsv_bindings(tsv, nodes = {})
484
497
vars = tsv . shift . map { |h | h . sub ( /^\? / , '' ) }
485
498
solutions = RDF ::Query ::Solutions . new
486
499
tsv . each do |row |
500
+ # Flesh out columns which may be missing
501
+ vars . each_with_index do |_ , i |
502
+ row [ i ] ||= ""
503
+ end
487
504
solution = RDF ::Query ::Solution . new
488
505
row . each_with_index do |v , i |
489
- if !v . empty?
490
- term = RDF ::NTriples . unserialize ( v ) || case v
491
- when /^\d +\. \d *[eE][+-]?[0-9]+$/ then RDF ::Literal ::Double . new ( v )
492
- when /^\d *\. \d +[eE][+-]?[0-9]+$/ then RDF ::Literal ::Double . new ( v )
493
- when /^\d *\. \d +$/ then RDF ::Literal ::Decimal . new ( v )
494
- when /^\d +$/ then RDF ::Literal ::Integer . new ( v )
495
- else
496
- RDF ::Literal ( v )
497
- end
498
- nodes [ term . id ] = term if term . is_a? RDF ::Node
499
- solution [ vars [ i ] . to_sym ] = term
506
+ term = case v
507
+ when "" then RDF ::Literal ( "" )
508
+ when /^\d +\. \d *[eE][+-]?[0-9]+$/ then RDF ::Literal ::Double . new ( v )
509
+ when /^\d *\. \d +[eE][+-]?[0-9]+$/ then RDF ::Literal ::Double . new ( v )
510
+ when /^\d *\. \d +$/ then RDF ::Literal ::Decimal . new ( v )
511
+ when /^\d +$/ then RDF ::Literal ::Integer . new ( v )
512
+ else
513
+ RDF ::NTriples . unserialize ( v ) || RDF ::Literal ( v )
500
514
end
515
+ nodes [ term . id ] = term if term . is_a? RDF ::Node
516
+ solution [ vars [ i ] . to_sym ] = term
501
517
end
502
518
solutions << solution
503
519
end
@@ -506,45 +522,57 @@ def self.parse_tsv_bindings(tsv, nodes = {})
506
522
507
523
##
508
524
# @param [String, IO, Nokogiri::XML::Node, REXML::Element] xml
525
+ # @param [Symbol] library (:nokogiri)
526
+ # One of :nokogiri or :rexml.
509
527
# @return [<RDF::Query::Solutions>]
510
528
# @see https://www.w3.org/TR/rdf-sparql-json-res/#results
511
- def self . parse_xml_bindings ( xml , nodes = { } )
529
+ def self . parse_xml_bindings ( xml , nodes = { } , library : :nokogiri )
512
530
xml . force_encoding ( ::Encoding ::UTF_8 ) if xml . respond_to? ( :force_encoding )
513
531
514
- if defined? ( ::Nokogiri )
532
+ if defined? ( ::Nokogiri ) && library == :nokogiri
515
533
xml = Nokogiri ::XML ( xml ) . root unless xml . is_a? ( Nokogiri ::XML ::Document )
516
534
case
517
- when boolean = xml . xpath ( "//sparql:boolean" , XMLNS ) [ 0 ]
518
- boolean . text == 'true'
519
- when results = xml . xpath ( "//sparql:results" , XMLNS ) [ 0 ]
520
- solutions = results . elements . map do |result |
521
- row = { }
522
- result . elements . each do |binding |
523
- name = binding . attr ( 'name' ) . to_sym
524
- value = binding . elements . first
525
- row [ name ] = parse_xml_value ( value , nodes )
526
- end
527
- RDF ::Query ::Solution . new ( row )
535
+ when boolean = xml . xpath ( "//sparql:boolean" , XMLNS ) [ 0 ]
536
+ boolean . text == 'true'
537
+ when results = xml . xpath ( "//sparql:results" , XMLNS ) [ 0 ]
538
+ solutions = results . elements . map do |result |
539
+ row = { }
540
+ result . elements . each do |binding |
541
+ name = binding . attr ( 'name' ) . to_sym
542
+ value = binding . elements . first
543
+ row [ name ] = parse_xml_value ( value , nodes )
528
544
end
529
- RDF ::Query ::Solutions . new ( solutions )
545
+ RDF ::Query ::Solution . new ( row )
546
+ end
547
+ solns = RDF ::Query ::Solutions . new ( solutions )
548
+
549
+ # Set variable names explicitly
550
+ var_names = xml . xpath ( "//sparql:head/sparql:variable/@name" , XMLNS )
551
+ solns . variable_names = var_names . map ( &:to_s )
552
+ solns
530
553
end
531
554
else
532
555
# REXML
533
556
xml = REXML ::Document . new ( xml ) . root unless xml . is_a? ( REXML ::Element )
534
557
case
535
- when boolean = xml . elements [ 'boolean' ]
536
- boolean . text == 'true'
537
- when results = xml . elements [ 'results' ]
538
- solutions = results . elements . map do |result |
539
- row = { }
540
- result . elements . each do |binding |
541
- name = binding . attributes [ 'name' ] . to_sym
542
- value = binding . select { |node | node . kind_of? ( ::REXML ::Element ) } . first
543
- row [ name ] = parse_xml_value ( value , nodes )
544
- end
545
- RDF ::Query ::Solution . new ( row )
558
+ when boolean = xml . elements [ 'boolean' ]
559
+ boolean . text == 'true'
560
+ when results = xml . elements [ 'results' ]
561
+ solutions = results . elements . map do |result |
562
+ row = { }
563
+ result . elements . each do |binding |
564
+ name = binding . attributes [ 'name' ] . to_sym
565
+ value = binding . select { |node | node . kind_of? ( ::REXML ::Element ) } . first
566
+ row [ name ] = parse_xml_value ( value , nodes )
546
567
end
547
- RDF ::Query ::Solutions . new ( solutions )
568
+ RDF ::Query ::Solution . new ( row )
569
+ end
570
+ solns = RDF ::Query ::Solutions . new ( solutions )
571
+
572
+ # Set variable names explicitly
573
+ var_names = xml . elements [ 'head' ] . elements . map { |e | e . attributes [ 'name' ] }
574
+ solns . variable_names = var_names . map ( &:to_sym )
575
+ solns
548
576
end
549
577
end
550
578
end
@@ -578,7 +606,7 @@ def self.parse_xml_value(value, nodes = {})
578
606
# @return [RDF::Enumerable]
579
607
def parse_rdf_serialization ( response , **options )
580
608
options = { content_type : response . content_type } unless options [ :content_type ]
581
- if reader = RDF ::Reader . for ( options )
609
+ if reader = RDF ::Reader . for ( ** options )
582
610
reader . new ( response . body )
583
611
else
584
612
raise RDF ::ReaderError , "no RDF reader was found for #{ options } ."
0 commit comments