Class: Splunk::ResultsListener
- Inherits:
-
Object
- Object
- Splunk::ResultsListener
- Defined in:
- lib/splunk-sdk-ruby/resultsreader.rb
Overview
ResultsListener
is the SAX event handler for ResultsReader
.
The authors of Nokogiri decided to make their SAX interface slightly incompatible with that of REXML. For example, REXML uses tag_start and passes attributes as a dictionary, while Nokogiri calls the same thing start_element, and passes attributes as an association list.
This is a classic finite state machine parser. The ‘@states` variable contains a hash with the states as its values. Each hash contains functions giving the behavior of the state machine in that state. The actual methods on the function dispatch to these functions based upon the current state (as stored in `@state`).
The parser initially runs until it has determined if the results are a preview, then calls Fiber.yield
to return it. Then it continues and tries to yield a field order, and then any results. (It will always yield a field order, even if it is empty). At the end of a results set, it yields :end_of_results_set
.
Instance Method Summary collapse
-
#attlistdecl(element_name, attributes, raw_content) ⇒ Object
Unused methods in REXML.
- #cdata(content) ⇒ Object
-
#cdata_block(string) ⇒ Object
Unused methods in Nokogiri.
- #characters(text) ⇒ Object
- #comment(comment) ⇒ Object
- #doctype(name, pub_sys, long_name, uri) ⇒ Object
- #doctype_end ⇒ Object
- #elementdecl(content) ⇒ Object
- #end_document ⇒ Object
- #end_element(name) ⇒ Object
- #end_element_namespace(name, prefix = nil, uri = nil) ⇒ Object
- #entity(content) ⇒ Object
- #entitydecl(content) ⇒ Object
- #error(string) ⇒ Object
-
#initialize ⇒ ResultsListener
constructor
:nodoc:.
- #instruction(name, instruction) ⇒ Object
- #notationdecl(content) ⇒ Object
- #start_document ⇒ Object
-
#start_element(name, attributes) ⇒ Object
Nokogiri methods - all dispatch to the REXML methods.
- #start_element_namespace(name, attributes = [], prefix = nil, uri = nil, ns = []) ⇒ Object
- #tag_end(name) ⇒ Object
-
#tag_start(name, attributes) ⇒ Object
REXML methods - all dispatch is done here.
- #text(text) ⇒ Object
- #warning(string) ⇒ Object
- #xmldecl(version, encoding, standalone) ⇒ Object
Constructor Details
#initialize ⇒ ResultsListener
:nodoc:
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 272 def initialize() # @fields holds the accumulated list of fields from the fieldOrder # element. If there has been no accumulation, it is set to # :no_fieldOrder_found. For empty results sets, there is often no # fieldOrder element, but we still want to yield an empty Array at the # right point, so if we reach the end of a results element and @fields # is still :no_fieldOrder_found, we yield an empty array at that point. @fields = :no_fieldOrder_found @concatenate = false @is_preview = nil @state = :base @states = { # Toplevel state. :base => { :start_element => lambda do |name, attributes| if name == "results" if !@concatenate @is_preview = attributes["preview"] == "1" Fiber.yield(@is_preview) end elsif name == "fieldOrder" if !@concatenate @state = :field_order @fields = [] end elsif name == "result" @state = :result @current_offset = Integer(attributes["offset"]) @current_result = Event.new() end end, :end_element => lambda do |name| if name == "results" and !@concatenate Fiber.yield([]) if @fields == :no_fieldOrder_found if !@is_preview # Start concatenating events @concatenate = true else # Reset the fieldOrder @fields = :no_fieldOrder_found Fiber.yield(:end_of_results_set) end end end }, # Inside a `fieldOrder` element. Recognizes only # the `field` element, and returns to the `:base` state # when it encounters `</fieldOrder>`. :field_order => { :start_element => lambda do |name, attributes| if name == "field" @state = :field_order_field end end, :end_element => lambda do |name| if name == "fieldOrder" @state = :base Fiber.yield(@fields) end end }, # When the parser in `:field_order` state encounters # a `field` element, it jumps to this state to record it. # When `</field>` is encountered, jumps back to `:field_order`. :field_order_field => { :characters => lambda do |text| @fields << text.strip end, :end_element => lambda do |name| if name == "field" @state = :field_order end end }, # When the parser has hit the `result` element, it jumps here. # When this state hits `</result>`, it calls `Fiber.yield` to # send the completed result back, and, when the fiber is # resumed, jumps back to the `:base` state. :result => { :start_element => lambda do |name, attributes| if name == "field" @current_field = attributes["k"] @current_value = nil elsif name == "text" || name == "v" @state = :field_values @current_text = "" s = ["v"] + attributes.map do |entry| key, value = entry # Nokogiri and REXML both drop the namespaces of attributes, # and there is no way to recover them. To reconstruct the # XML (since we can't get at its raw form) we put in the # one instance of a namespace on an attribute that shows up # in what Splunk returns. Yes, this is a terribly, ugly # kludge. if key == "space" prefixed_key = "xml:space" else prefixed_key = key end "#{prefixed_key}=\"#{value}\"" end @current_xml = "<" + s.join(" ") + ">" end end, :end_element => lambda do |name| if name == "result" Fiber.yield @current_result @current_result = nil @current_offset = nil @state = :base elsif name == "field" if @current_result.has_key?(@current_field) if @current_result[@current_field].is_a?(Array) @current_result[@current_field] << @current_value elsif @current_result[@current_field] != nil @current_result[@current_field] = [@current_result[@current_field], @current_value] end else @current_result[@current_field] = @current_value end if @current_field == "_raw" @current_result.raw_xml = @current_xml end @current_field = nil @current_value = nil end end }, # Parse the values inside a results field. :field_values => { :end_element => lambda do |name| if name == "text" || name == "v" if @current_value == nil @current_value = @current_text elsif @current_value.is_a?(Array) @current_value << @current_text else @current_value = [@current_value, @current_text] end if name == "v" @current_xml << "</v>" end @current_text = nil @state = :result elsif name == "sg" # <sg> is emitted to delimit text that should be displayed # highlighted. We preserve it in field values. @current_xml << "</sg>" end end, :start_element => lambda do |name, attributes| if name == "sg" s = ["sg"] + attributes.sort.map do |entry| key, value = entry "#{key}=\"#{value}\"" end text = "<" + s.join(" ") + ">" @current_xml << text end end, :characters => lambda do |text| @current_text << text @current_xml << Splunk::escape_string(text) end } } end |
Instance Method Details
#attlistdecl(element_name, attributes, raw_content) ⇒ Object
Unused methods in REXML
505 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 505 def attlistdecl(element_name, attributes, raw_content) end |
#cdata(content) ⇒ Object
506 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 506 def cdata(content) end |
#cdata_block(string) ⇒ Object
Unused methods in Nokogiri
496 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 496 def cdata_block(string) end |
#characters(text) ⇒ Object
471 472 473 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 471 def characters(text) text(text) end |
#comment(comment) ⇒ Object
497 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 497 def comment(string) end |
#doctype(name, pub_sys, long_name, uri) ⇒ Object
508 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 508 def doctype(name, pub_sys, long_name, uri) end |
#doctype_end ⇒ Object
509 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 509 def doctype_end() end |
#elementdecl(content) ⇒ Object
510 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 510 def elementdecl(content) end |
#end_document ⇒ Object
498 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 498 def end_document() end |
#end_element(name) ⇒ Object
463 464 465 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 463 def end_element(name) tag_end(name) end |
#end_element_namespace(name, prefix = nil, uri = nil) ⇒ Object
467 468 469 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 467 def end_element_namespace(name, prefix = nil, uri = nil) end_element(name) end |
#entity(content) ⇒ Object
511 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 511 def entity(content) end |
#entitydecl(content) ⇒ Object
512 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 512 def entitydecl(content) end |
#error(string) ⇒ Object
499 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 499 def error(string) end |
#instruction(name, instruction) ⇒ Object
513 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 513 def instruction(name, instruction) end |
#notationdecl(content) ⇒ Object
514 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 514 def notationdecl(content) end |
#start_document ⇒ Object
500 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 500 def start_document() end |
#start_element(name, attributes) ⇒ Object
Nokogiri methods - all dispatch to the REXML methods.
446 447 448 449 450 451 452 453 454 455 456 457 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 446 def start_element(name, attributes) # attributes is an association list. Turn it into a hash # that tag_start can use. attribute_dict = {} attributes.each do |attribute| key = attribute.localname value = attribute.value attribute_dict[key] = value end tag_start(name, attribute_dict) end |
#start_element_namespace(name, attributes = [], prefix = nil, uri = nil, ns = []) ⇒ Object
459 460 461 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 459 def start_element_namespace(name, attributes=[], prefix=nil, uri=nil, ns=[]) start_element(name, attributes) end |
#tag_end(name) ⇒ Object
483 484 485 486 487 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 483 def tag_end(name) if @states[@state].has_key?(:end_element) @states[@state][:end_element].call(name) end end |
#tag_start(name, attributes) ⇒ Object
REXML methods - all dispatch is done here
476 477 478 479 480 481 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 476 def tag_start(name, attributes) # attributes is a hash. if @states[@state].has_key?(:start_element) @states[@state][:start_element].call(name, attributes) end end |
#text(text) ⇒ Object
489 490 491 492 493 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 489 def text(text) if @states[@state].has_key?(:characters) @states[@state][:characters].call(text) end end |
#warning(string) ⇒ Object
501 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 501 def warning(string) end |
#xmldecl(version, encoding, standalone) ⇒ Object
515 |
# File 'lib/splunk-sdk-ruby/resultsreader.rb', line 515 def xmldecl(version, encoding, standalone) end |