Kouhei Sutou
null+****@clear*****
Wed Sep 27 11:40:40 JST 2017
Kouhei Sutou 2017-09-27 11:40:40 +0900 (Wed, 27 Sep 2017) New Revision: fe10be1e44fab03d6f12f607f48b6376bb7bb426 https://github.com/ranguba/groonga-client/commit/fe10be1e44fab03d6f12f607f48b6376bb7bb426 Message: select: support XML output Added files: test/response/test-select-xml.rb Modified files: lib/groonga/client/response/base.rb lib/groonga/client/response/select.rb test/response/helper.rb Modified: lib/groonga/client/response/base.rb (+3 -11) =================================================================== --- lib/groonga/client/response/base.rb 2017-08-21 10:06:44 +0900 (fe1d7c4) +++ lib/groonga/client/response/base.rb 2017-09-27 11:40:40 +0900 (d123778) @@ -93,18 +93,10 @@ module Groonga private def parse_xml(response) - # FIXME: Use more fast XML parser - # Extract as a class document = REXML::Document.new(response) - root_element = document.root - if root_element.name == "RESULT" - result_element = root_element - header = parse_xml_header(result_element) - body = parse_xml_body(result_element.elements[1]) - else - header = nil - body = parse_xml_body(root_element) - end + result_element = document.root + header = parse_xml_header(result_element) + body = parse_xml_body(result_element.elements[1]) [header, body] end Modified: lib/groonga/client/response/select.rb (+78 -0) =================================================================== --- lib/groonga/client/response/select.rb 2017-08-21 10:06:44 +0900 (af4a714) +++ lib/groonga/client/response/select.rb 2017-09-27 11:40:40 +0900 (72b8e07) @@ -24,6 +24,84 @@ module Groonga class Select < Base Response.register("select", self) + class << self + private + def parse_xml(response) + document = REXML::Document.new(response) + return super if document.root.name == "RESULT" + + result_page = document.elements["SEGMENTS/SEGMENT/RESULTPAGE"] + result_set = result_page.elements["RESULTSET"] + n_hits, columns, records = parse_xml_result_set(result_set) + + navigation_entry = result_page.elements["NAVIGATIONENTRY"] + drilldowns = parse_xml_navigation_entry(navigation_entry) + + header = nil + body = [ + [ + [n_hits], + columns, + *records, + ], + *drilldowns, + ] + [header, body] + end + + def parse_xml_result_set(result_set) + n_hits = Integer(result_set.attributes["NHITS"]) + + columns = [] + records = [] + result_set.each_element("HIT") do |hit| + if columns.empty? + hit.each_element("FIELD") do |field| + name = field.attributes["NAME"] + columns << [name, "ShortText"] + end + end + record = [] + hit.each_element("FIELD") do |field| + record << field.text + end + records << record + end + + [n_hits, columns, records] + end + + def parse_xml_navigation_entry(navigation_entry) + return [] if navigation_entry.nil? + + drilldowns = [] + navigation_entry.each_element("NAVIGATIONELEMENTS") do |elements| + n_hits = Integer(elements.attributes["COUNT"]) + columns = [] + drilldown = [] + elements.each_element("NAVIGATIONELEMENT") do |element| + if columns.empty? + element.attributes.each do |name, value| + columns << [name, "ShortText"] + end + end + + drilldown << element.attributes.collect do |_, value| + value + end + end + + drilldowns << [ + [n_hits], + columns, + *drilldown, + ] + end + + drilldowns + end + end + include Enumerable # @return [Integer] The number of records that match againt Modified: test/response/helper.rb (+11 -2) =================================================================== --- test/response/helper.rb 2017-08-21 10:06:44 +0900 (967fd0a) +++ test/response/helper.rb 2017-09-27 11:40:40 +0900 (4116433) @@ -16,9 +16,18 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA module TestResponseHelper - def parse_raw_response(command_name, raw_response) + def parse_raw_response_raw(command_name, pair_arguments, raw_response) command_class = Groonga::Command.find(command_name) - command = command_class.new(command_name, {}) + command = command_class.new(command_name, pair_arguments) Groonga::Client::Response.parse(command, raw_response) end + + def parse_raw_response(command_name, raw_response) + parse_raw_response_raw(command_name, {}, raw_response) + end + + def parse_raw_xml_response(command_name, raw_response) + parse_raw_response_raw(command_name, {"output_type" => "xml"}, + raw_response) + end end Added: test/response/test-select-xml.rb (+105 -0) 100644 =================================================================== --- /dev/null +++ test/response/test-select-xml.rb 2017-09-27 11:40:40 +0900 (d656aa5) @@ -0,0 +1,105 @@ +# Copyright (C) 2017 Kouhei Sutou <kou �� clear-code.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +require "response/helper" + +class TestResponseSelectXML < Test::Unit::TestCase + include TestResponseHelper + + def drilldown(key, n_hits, records) + Groonga::Client::Response::Select::Drilldown.new(key, n_hits, records) + end + + def test_basic + raw_response = <<-XML +<?xml version="1.0" encoding="utf-8"?> +<SEGMENTS> +<SEGMENT> +<RESULTPAGE> +<RESULTSET OFFSET="0" LIMIT="1" NHITS="100"> +<HIT NO="1"> +<FIELD NAME="_id">1</FIELD> +</HIT> +</RESULTSET> +</RESULTPAGE> +</SEGMENT> +</SEGMENTS> + XML + + response = parse_raw_xml_response("select", raw_response) + assert_equal({ + :return_code => 0, + :start_time => Time.at(0), + :elapsed_time => 0.0, + :records => [{"_id" => "1"}], + }, + { + :return_code => response.return_code, + :start_time => response.start_time, + :elapsed_time => response.elapsed_time, + :records => response.records, + }) + end + + def test_drilldown + raw_response = <<-XML +<?xml version="1.0" encoding="utf-8"?> +<SEGMENTS> +<SEGMENT> +<RESULTPAGE> +<RESULTSET OFFSET="0" LIMIT="0" NHITS="100"> +</RESULTSET> +<NAVIGATIONENTRY> +<NAVIGATIONELEMENTS COUNT="7"> +<NAVIGATIONELEMENT _key="2.2.0" _nsubrecs="18044" /> +<NAVIGATIONELEMENT _key="2.3.0" _nsubrecs="18115" /> +<NAVIGATIONELEMENT _key="2.4.0" _nsubrecs="14594" /> +</NAVIGATIONELEMENTS> +</NAVIGATIONENTRY> +</RESULTPAGE> +</SEGMENT> +</SEGMENTS> + XML + + response = parse_raw_response_raw("select", + { + "drilldown" => "version", + "output_type" => "xml", + }, + raw_response) + drilldown_records = [ + {"_key" => "2.2.0", "_nsubrecs" => "18044"}, + {"_key" => "2.3.0", "_nsubrecs" => "18115"}, + {"_key" => "2.4.0", "_nsubrecs" => "14594"}, + ] + assert_equal({ + :return_code => 0, + :start_time => Time.at(0), + :elapsed_time => 0.0, + :records => [], + :drilldowns => [ + drilldown("version", 7, drilldown_records), + ], + }, + { + :return_code => response.return_code, + :start_time => response.start_time, + :elapsed_time => response.elapsed_time, + :records => response.records, + :drilldowns => response.drilldowns, + }) + end +end -------------- next part -------------- HTML����������������������������... URL: https://lists.osdn.me/mailman/archives/groonga-commit/attachments/20170927/d6c70de3/attachment-0001.htm