This simple program copies decorates one xml file with another. Two files are input. One is the decoration for the other. It looks for lines in the decoration that contain a string like [decorated body goes here]. When it finds one, that string is replaced by the body of the other file, the decorated file. Below is the source.
# Decorate the input.
# Usage: ruby -s decoratexml.rb -with=decore.xhtml [input]
# The decore is copied to the output.
# Strings in the decore like [decorated tag goes here]
# are replaced with the tagged section of the input.
# Strings in the decore like [date goes here]
# are replaced with the current date in yyyy-mm-dd form.
# Strings in the decore like [global var goes here]
# are replaced with the value of global variable $var.
# e.g. ruby -s decoratexml.rb -var=value ...
# Strings in the decore like [env var goes here]
# are replaced with the value of environment variable $var.
# Strings in the decore like [system command goes here]
# are replaced with the stdout of running "command".
require 'rexml/document'
decore = nil
decore = $with if $with
source = STDIN
source = File.open( ARGV[0] ) if 0 < ARGV.length
if ! decore
puts "usage: ruby -s decoratexml.rb -with=decore.xhtml [input]"
exit
end
xml = REXML::Document.new(source)
#global_variables.each { |g| puts g }
#wanted = "$with"
#puts eval wanted
File.open( decore ).each { |theLine|
if ( m = /\[decorated ([^\] ]*) goes here\]/.match theLine )
selector = m[1]
if ( m2 = /([^.#]+)\.(.+)/.match selector )
tag = m2[1]
tagclass = m2[2]
ea = xml.elements.to_a( "//#{tag}[@class='#{tagclass}']" )
section = ea.first
elsif ( m2 = /([^.#]+)#(.+)/.match selector )
tag = m2[1]
tagname = m2[2]
ea = xml.elements.to_a( "//#{tag}[@name='#{tagname}']" )
if ea.size < 1
ea = xml.elements.to_a( "//#{tag}[@id='#{tagname}']" )
end
section = ea.first
else
section = xml.elements["//#{selector}"]
end
if section
puts m.pre_match +
section.text +
section.elements.each { |theElement| theElement.to_s }.join( "\n" ) +
m.post_match
else
puts theLine
end
elsif ( m = /\[date goes here\]/.match theLine )
puts m.pre_match + Time.now.strftime( "%Y-%m-%d" ) + m.post_match
elsif ( m = /\[global ([^ ]*) goes here\]/.match theLine )
g = eval "$" + m[1]
puts theLine unless g
puts m.pre_match + g + m.post_match if g
elsif ( m = /\[env ([^ ]+) goes here\]/.match theLine )
e = ENV[m[1]]
puts theLine unless e
puts m.pre_match + e + m.post_match if e
elsif ( m = /\[system (.+) goes here\]/.match theLine )
# puts m.pre_match + %x{#{m[1]}} + m.post_match
print m.pre_match
system m[1]
puts m.post_match
else
puts theLine
end
}
Look at the Makefile in this directory to see one way it can be used. We export some shell variables that are used within decoratexml.html.uc. This way all the file names appear in the Makefile and none are hidden in decoratexml.html.uc. Ubercat.rb is then applied to create decoratexml.html. At last decore.xhtml is applied by decoratexml.rb to create decoratexml.xhtml.
Notice that all pages, those being decorated and those used as decoration as well as the result, should be readily readable and understandable when viewed in a browser.
Notice also that decoration can be nested. c.f. SiteMesh
The tag in the syntax [undecorated tag goes here]
is like a CSS selector.
So I'm going to call it a "selector".
There are only a few forms it can take:
[date goes here][global var goes here][env var goes here][system cmd goes here]Helpful might be:
[filename goes here]
- abreviates [global filename goes here]
[url goes here]
- abreviates [global url goes here]
[file f goes here]
- abreviates [system cat f goes here]
Maybe the terms should be changed:
So the undecorated + the decore -> the decorated. This will allow us to refer in the decore to both the undecorated and the decorated. e.g. we might want the file name of the decorated in the footer. Hence there might be both "[undecorated body goes here]" and "[decorated filename goes here]".
Perhaps a syntax
like [undecorated attr of selector goes here]
would be useful?
Or other CSS like selector syntax like .class, tag subtag, etc.?
We could add some other stuff to make it a bit like a poor man's XSLT. Note that we want to continue the idea that every page stands on it's own, and can be reasonably viewed and understood in a web browser.
[xpath path goes here][for each [tag|xpath|global|env|] name ]
[it goes here]
[repeat][for each {one, two,
} ]
[it goes here]
[repeat] Maybe strip any mock up division
(<div class="mockup">).
This would allow web designers to put in mock text
to see how a decore might look.
http://www.BlossomAssociates.net/ubercat/decoratexml.xhtml 2007-08-27