This is my
Ruby class which takes the output from the
User Search XML Ticker, and creates from it an array of E2XMLTickerParser::Writeup
objects, each of which contains the requisite info E2 gives you about your
nodes.
Basic operation is quite simple. You create a new parser by calling E2XMLTickerParser.new, then call its "parse" method with a signal argument of the XML ticker output (a String). After this is done, the parser object will contain an experience method which returns total XP, and the parser's writeups method will return the Array of E2XMLTickerParser::Writeup objects.
Each of these Writeup objects responds to the methods: name, node_id, reputation, createtime, cooled, parent_e2node and cooledby_user. These methods each will return what you expect them to, in native Ruby object format rather than simply the text output E2 generates. For example, createtime will be a Time object, reputation an Integer, and cooled will be true/false.
Here's the parser's implementation itself! It requires, of course, Ruby 1.6 or later and XML::Parser (the Ruby expat bindings).
#!/usr/local/bin/ruby
# Copyright (c) 2001 Brian Fundakowski Feldman
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
require 'xmlparser'
class E2XMLTickerParser < XML::Parser
class Writeup
[:node_id, :reputation, :createtime, :cooled, :parent_e2node,
:cooledby_user, :name].each {|member|
attr_reader(member)
}
def node_id=(val)
@node_id = Integer(val)
end
def reputation=(val)
@reputation = Integer(val)
end
def parent_e2node=(val)
@parent_e2node = Integer(val)
end
def createtime=(val)
time =
/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/.match(val)
unless time
raise 'invalid "createtime": #{val}'
end
@createtime = Time.utc(*time[1..6].collect {|t| t.to_i})
end
def cooled=(val)
@cooled = Integer(val) != 0
end
def cooledby_user=(val)
@cooledby_user = if val.empty? then nil else val end
end
def name=(val)
@name = val
end
def [](element)
method(element).call
end
def []=(element, val)
method("#{element}=").call(val)
end
end
attr_reader :experience
attr_reader :writeups
def initialize
@writeups = []
@context = [[nil, nil]]
end
## visitors for each Element
@@tagdeps = {
"USERSEARCH" => nil,
"INFO" => "USERSEARCH",
"writeup" => "USERSEARCH"
}
def startElement(tag, args)
# assertions regarding tag nesting
if !@@tagdeps.has_key?(tag) || @@tagdeps[tag] != @context[-1][0]
raise "invalid E2 XML Ticker (#{tag} in #{@context[-1][0]}"
end
@context.push([tag, args])
# lazy-parse "writeup", but not "INFO"
if tag == "INFO"
@experience = Integer(args["experience"])
end
end
def endElement(tag)
@context.pop
end
## visitor for "text"
def default(text)
if @context[-1][0] == "writeup"
wu = Writeup.new
wu.name = text
@context[-1][1].each {|key, val|
wu[key] = val
}
@writeups.push(wu)
end
end
end