lib/ruby_speech/nlsml/document.rb
require 'delegate'
module RubySpeech
module NLSML
class Document < SimpleDelegator
def initialize(xml)
result = xml.respond_to?(:root) ? xml.root : xml
unless result.namespace
result.default_namespace = NLSML_NAMESPACE
result = Nokogiri::XML.parse(xml.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
end
super result
end
def grammar
self['grammar']
end
def interpretations
interpretation_nodes.map do |interpretation|
interpretation_hash_for_interpretation interpretation
end
end
def best_interpretation
interpretation_hash_for_interpretation interpretation_nodes.first
end
def match?
interpretation_nodes.count > 0 && !nomatch? && !noinput?
end
def ==(other)
to_xml == other.to_xml
end
def noinput?
noinput_elements.any?
end
def to_xml
document.to_xml
end
private
def nomatch?
nomatch_elements.count >= input_elements.count
end
def nomatch_elements
xpath 'ns:interpretation/ns:input/ns:nomatch', 'ns' => NLSML_NAMESPACE
end
def noinput_elements
xpath 'ns:interpretation/ns:input/ns:noinput', 'ns' => NLSML_NAMESPACE
end
def input_elements
xpath 'ns:interpretation/ns:input', 'ns' => NLSML_NAMESPACE
end
def input_hash_for_interpretation(interpretation)
input_element = interpretation.at_xpath 'ns:input', 'ns' => NLSML_NAMESPACE
return unless input_element
{ content: input_element.content }.tap do |h|
h[:mode] = input_element['mode'].to_sym if input_element['mode']
end
end
def instance_hash_for_interpretation(interpretation)
instances = instance_elements interpretation
return unless instances.any?
element_children_key_value instances.first
end
def instances_collection_for_interpretation(interpretation)
instances = instance_elements interpretation
instances.map do |instance|
element_children_key_value instance
end
end
def instance_elements(interpretation)
interpretation.xpath 'ns:instance', 'ns' => NLSML_NAMESPACE
end
def element_children_key_value(element)
return element.children.first.content if element.children.first.is_a?(Nokogiri::XML::Text)
element.children.inject({}) do |acc, child|
acc[child.node_name.to_sym] = case child.children.count
when 0
child.content
when 1
if child.children.first.is_a?(Nokogiri::XML::Text)
child.children.first.content
else
element_children_key_value child
end
else
element_children_key_value child
end
acc
end
end
def interpretation_hash_for_interpretation(interpretation)
{
confidence: interpretation['confidence'].to_f,
input: input_hash_for_interpretation(interpretation),
instance: instance_hash_for_interpretation(interpretation),
instances: instances_collection_for_interpretation(interpretation)
}
end
def interpretation_nodes
nodes = xpath 'ns:interpretation', 'ns' => NLSML_NAMESPACE
nodes.sort_by { |int| -int[:confidence].to_f }
end
end
end
end