Robert Klemme
3/9/2005 11:01:00 AM
"Luke Graham" <spoooq@gmail.com> schrieb im Newsbeitrag
news:c6afaed00503090200647c0c30@mail.gmail.com...
> Hi list,
>
> I was wondering if anyone would have some insight into a problem Ive
got.
>
> Im taking an xml document (looks very much like a w3c schema with some
> extra attributes) and transforming it into c++ code. The method I use
looks
> something like...
>
> def recurse(file, func, element)
> case func
> when "declare"
> file << element.attributes["type"] << element.attributes["name"]
> when "instantiate"
> file << element.attributes["name"] << " = new " <<
element.attributes["type"]
> do wierd stuff based on type and state
> end
> element.each_child { |c|
> recurse file, func, c
> }
> end
>
> headerfile << "some template"
> doc.each_child { |c|
> recurse headerfile, "declare", c
> }
> headerfile << "some more template"
>
> cppfile << "some template"
> doc.each_child { |c|
> recurse cppfile, "instantiate", c
> }
> cppfile << "some more template"
>
> (I know doc can only have one child but I use the xpath bit of rexml,
> like doc.elements.each("/*/foo"), just couldnt be bothered typing it)
>
> Needless to say, recurse is now ~500 lines, and has more than a few
> oddities like a begin-ensure block, special cases that dont recurse,
> about 4 places where it calls itself, some of which dont use the
> same function they were passed, lots of places that do strange things
> to the state and so on.
>
> Id like to get the logic out of the recurse statement for three reasons.
> First of all, Im starting recurse up more times than Ive shown
> above, because I have four separate sets of header/cpp templates,
> not to mention I would like to add other templates that arent c++ code.
> It would be good to know that each case could be handled safely
> without interfering with each others output and special cases.
> Secondly, someone else would like to write their own templated
> code, and their required output would be different. Thirdly, recurse is
> simply becoming scary.
>
> Can anyone suggest a good way to get the c++-producing code out
> of recurse and into some sort of template language, or into functions
> that get passed into simplified recurse? I figured those functions
> would need to return functions (usually themselves) to simulate
> some state changes, ala...
>
> def recurse(file, func, element)
> file << func.call "pre", element
> element.each_child { |c|
> recurse file, func.call("getfunc",element), c
> }
> file << func.call "post", element
> end
>
> Or would I be better doing this...
>
> def sampleDeclare(file, element)
> ...
> end
> def startDeclare(file, element)
> file << "pre declare"
> element.each_child { |c|
> sampleDeclare.call file, c # choose different funcs based on
state
> }
> file << "post declare"
> end
> startDeclare headerfile, doc.root
>
> I think that dragging state around might get hard after a while tho and
> the recursion would be specified many times.
>
> Sorry for the long post and thanks for reading this far!
Sounds like a use case for the visitor pattern. The traversal is already
implemented in REXML so you don't need to do it yourself. Just write a
visitor class that is notified of each node visited and can act
accordingly. Rough outline:
class Visitor
def initialize(dom)
@dom=dom
@visitors = {"foo" => lambda {|n| ... }, "bar" => lambda {|n|...}}
end
def visit_all() @dom.each("xpath") {|n| @visitors[n.name].call(n)}
# other methods for dealing with nodes...
end
Kind regards
robert