Created
November 16, 2010 20:34
-
-
Save rjungemann/702461 to your computer and use it in GitHub Desktop.
pretty_print_xslt in Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# usage: | |
# | |
# ruby extra_steps.rb SCRIPT ROOT_URL RELATIVE_URL | |
require 'nokogiri' rescue puts "Needs nokogiri. Type in `gem install nokogiri` to install." | |
require 'erb' | |
def pretty_print_xslt | |
%{ | |
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | |
<xsl:output method="xml" encoding="ISO-8859-1"/> | |
<xsl:param name="indent-increment" select="' '"/> | |
<xsl:template name="newline"> | |
<xsl:text disable-output-escaping="yes"> | |
</xsl:text> | |
</xsl:template> | |
<xsl:template match="comment() | processing-instruction()"> | |
<xsl:param name="indent" select="''"/> | |
<xsl:call-template name="newline"/> | |
<xsl:value-of select="$indent"/> | |
<xsl:copy /> | |
</xsl:template> | |
<xsl:template match="text()"> | |
<xsl:param name="indent" select="''"/> | |
<xsl:call-template name="newline"/> | |
<xsl:value-of select="$indent"/> | |
<xsl:value-of select="normalize-space(.)"/> | |
</xsl:template> | |
<xsl:template match="text()[normalize-space(.)='']"/> | |
<xsl:template match="*"> | |
<xsl:param name="indent" select="''"/> | |
<xsl:call-template name="newline"/> | |
<xsl:value-of select="$indent"/> | |
<xsl:choose> | |
<xsl:when test="count(child::*) > 0"> | |
<xsl:copy> | |
<xsl:copy-of select="@*"/> | |
<xsl:apply-templates select="*|text()"> | |
<xsl:with-param name="indent" select="concat ($indent, $indent-increment)"/> | |
</xsl:apply-templates> | |
<xsl:call-template name="newline"/> | |
<xsl:value-of select="$indent"/> | |
</xsl:copy> | |
</xsl:when> | |
<xsl:otherwise> | |
<xsl:copy-of select="."/> | |
</xsl:otherwise> | |
</xsl:choose> | |
</xsl:template> | |
</xsl:stylesheet> | |
} | |
end | |
def default_original_script | |
%{ | |
<?xml version="1.0" encoding="utf-8"?> | |
<objects xmlns="http://www.spicefactory.org/parsley" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xmlns:log="http://www.spicefactory.org/parsley/flash/logging" | |
xsi:schemaLocation="http://www.spicefactory.org/parsley | |
http://www.spicefactory.org/parsley/schema/2.0/parsley-core.xsd | |
http://www.spicefactory.org/parsley/flash/logging | |
http://www.spicefactory.org/parsley/schema/2.0/parsley-logging-flash.xsd" | |
> | |
<!-- | |
This xml file defines the structure and flow of the module, including dialogue text, | |
audio, and animation. | |
--> | |
<object id="models" type="com.trustnode.assistant.models.MainModel"> | |
<!-- | |
DefaultOverlays can be used to place UI elements and other | |
animations that should start when the module begins. | |
--> | |
<property name="defaultOverlays"> | |
<array> | |
<object type="com.trustnode.assistant.models.Overlay"> | |
<property name="animationUrl" value="assets/animations/DEFAULT_BACKGROUND.swf"/> | |
<property name="removeAfterComplete" value="false"/> | |
<property name="removeAfterStopped" value="false"/> | |
<property name="layerName" value="backgrounds"/> | |
</object> | |
<object type="com.trustnode.assistant.models.Overlay"> | |
<property name="animationUrl" value="assets/animations/ui_original.swf"/> | |
<property name="removeAfterComplete" value="false"/> | |
<property name="removeAfterStopped" value="false"/> | |
</object> | |
</array> | |
</property> | |
<property name="steps"> | |
<array> | |
<!-- | |
This first step plays an animation and a sound, then switches to a "continue" dialog. | |
It is the most common use case for the interactive assistent. | |
The dialog stays visible until the audio completes. | |
If a dialog has not audio it will just stay, then clicking on the text will advance. | |
Note: | |
- To attach audio or animations you need to define a Dialog or preDialog | |
as Steps don't have any visual representation. | |
--> | |
<object type="com.trustnode.assistant.models.Step"> | |
<property name="id" value="1"/> | |
<property name="preDialogues"> | |
<array> | |
<object type="com.trustnode.assistant.models.Dialogue"> | |
<property name="animationUrl" value="assets/animations/harveyKeck.swf"/> | |
<property name="soundUrl" value="assets/audio/HarveyKeck.mp3"/> | |
<property name="lines"> | |
<array> | |
<object type="com.trustnode.assistant.models.Line"> | |
<property name="text"> | |
<string>Hey, I am Harvey Keck.</string> | |
</property> | |
</object> | |
</array> | |
</property> | |
</object> | |
</array> | |
</property> | |
<property name="question"> | |
<object type="com.trustnode.assistant.models.Question"> | |
<property name="form"> | |
<!-- | |
RadioForm allows one or more selectable text entries to allow | |
the user to continue or branch. | |
Use x,y properties to position the form. | |
Use the autoPosition property to automatically stack multiple responses | |
(not really shown here as there is only one response). | |
--> | |
<object type="com.trustnode.assistant.controls.RadioForm"> | |
<property name="autoPosition" value="true"/> | |
<property name="x" value="50"/> | |
<property name="y" value="0"/> | |
</object> | |
</property> | |
<property name="responses"> | |
<array> | |
<object type="com.trustnode.assistant.models.Response"> | |
<property name="text" value="Click Here too Continue. This should be multiline. Is it?"/> | |
<property name="next" value="2"/> | |
</object> | |
<object type="com.trustnode.assistant.models.Response"> | |
<property name="text" value="Click Here too Continue. This should be multiline. Is it?"/> | |
<property name="next" value="2"/> | |
</object> | |
</array> | |
</property> | |
</object> | |
</property> | |
</object> | |
<!-- | |
This second step shows how to switch animation scenes between dialogs. | |
Each animation is a root animation of a swf loaded from a local or remote url. | |
--> | |
<object type="com.trustnode.assistant.models.Step"> | |
<property name="id" value="2"/> | |
<property name="preDialogues"> | |
<array> | |
<object type="com.trustnode.assistant.models.Dialogue"> | |
<property name="animationUrl" value="assets/animations/scene1.swf"/> | |
<property name="lines"> | |
<array> | |
<object type="com.trustnode.assistant.models.Line"> | |
<property name="text"> | |
<string>Here's a dialogue that grabs an animation from an external swf.</string> | |
</property> | |
</object> | |
</array> | |
</property> | |
<!-- This dialogue causes a new set of steps to be loaded --> | |
<property name="commands"> | |
<string> | |
[ | |
[ | |
"com.trustnode.assistant.controllers.MainController", | |
"loadStepsFromUrl", | |
"assets/xml/next_steps_context.xml" | |
] | |
] | |
</string> | |
</property> | |
</object> | |
<object type="com.trustnode.assistant.models.Dialogue"> | |
<property name="animationUrl" value="assets/animations/scene2.swf"/> | |
<property name="lines"> | |
<array> | |
<object type="com.trustnode.assistant.models.Line"> | |
<property name="text"> | |
<string>Here's another dialogue with a different animation.</string> | |
</property> | |
</object> | |
</array> | |
</property> | |
</object> | |
</array> | |
</property> | |
<property name="question"> | |
<object type="com.trustnode.assistant.models.Question"> | |
<property name="animationUrl" value="assets/animations/scene2.swf|blue"/> | |
<property name="lines"> | |
<array> | |
<object type="com.trustnode.assistant.models.Line"> | |
<property name="text"> | |
<string>FINALLY! A question!</string> | |
</property> | |
</object> | |
</array> | |
</property> | |
<property name="form"> | |
<!-- | |
In this RadioForm the individual responses are positioned individually by | |
switching autoPosition off and giving "y" properties to the responses. | |
If autoPosition is set to "true" the responses will be stacked predictably. | |
You can still position them relatively. Note, that when autoPosition is on | |
any y-value supplied to a response will overwrite the default value specified | |
in config.xml. Hence, if the default value is 100 and you specify 20 for the, | |
say, second response, it might appear above the first. | |
Also, note that the question positions the form. | |
--> | |
<object type="com.trustnode.assistant.controls.RadioForm"> | |
<property name="autoPosition" value="false"/> | |
</object> | |
</property> | |
<property name="responses"> | |
<array> | |
<object type="com.trustnode.assistant.models.Response"> | |
<property name="text" value="Start from Beginning"/> | |
<property name="y" value="5"/> | |
<property name="next" value="1"/> | |
</object> | |
<object type="com.trustnode.assistant.models.Response"> | |
<property name="text" value="Go to the next step"/> | |
<property name="x" value="50"/> | |
<property name="y" value="50"/> | |
<property name="next" value="3"/> | |
</object> | |
</array> | |
</property> | |
</object> | |
</property> | |
</object> | |
<!-- | |
This simple step uses the "next" property to jump to the next step. | |
Since there is no audio in this step, the dialog stays up until you click on the text. | |
If audio would be used it would advance to the questions once the audio completes. | |
We position the responses by adding x,y-values to the form. Also, we overwrite the | |
default y-value of the responses by setting them to "0" for each element. | |
Some more recommendations for positioning responses: | |
- If you want to position individual responses, we recommend to swith autoPositioning off | |
- You can set height of first element, it will influence all subsequent | |
- If you want to position the block of responses, position the form only | |
(note that the default response y-position is used) | |
--> | |
<object type="com.trustnode.assistant.models.Step"> | |
<property name="id" value="3"/> | |
<property name="preDialogues"> | |
<array> | |
<object type="com.trustnode.assistant.models.Dialogue"> | |
<property name="animationUrl" value="assets/animations/scene3.swf"/> | |
<property name="lines"> | |
<array> | |
<object type="com.trustnode.assistant.models.Line"> | |
<property name="text"> | |
<string>Click here to continue (we have no audio, so dialog stays).</string> | |
</property> | |
</object> | |
</array> | |
</property> | |
</object> | |
</array> | |
</property> | |
<property name="question"> | |
<object type="com.trustnode.assistant.models.Question"> | |
<property name="form"> | |
<object type="com.trustnode.assistant.controls.RadioForm"> | |
<property name="autoPosition" value="true"/> | |
<property name="x" value="50"/> | |
<property name="y" value="-20"/> | |
</object> | |
</property> | |
<property name="responses"> | |
<array> | |
<object type="com.trustnode.assistant.models.Response"> | |
<property name="text" value="Play again"/> | |
<property name="y" value="0"/> | |
<property name="next" value="3"/> | |
</object> | |
<object type="com.trustnode.assistant.models.Response"> | |
<property name="text" value="Next step"/> | |
<property name="y" value="0"/> | |
<property name="next" value="4"/> | |
</object> | |
</array> | |
</property> | |
</object> | |
</property> | |
</object> | |
</array> | |
</property> | |
</object> | |
</objects> | |
} | |
end | |
def extra_steps_template | |
%{ | |
<?xml version="1.0" encoding="utf-8"?> | |
<objects xmlns="http://www.spicefactory.org/parsley" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xmlns:log="http://www.spicefactory.org/parsley/flash/logging" | |
xsi:schemaLocation="http://www.spicefactory.org/parsley | |
http://www.spicefactory.org/parsley/schema/2.0/parsley-core.xsd | |
http://www.spicefactory.org/parsley/flash/logging | |
http://www.spicefactory.org/parsley/schema/2.0/parsley-logging-flash.xsd" | |
> | |
<object type="com.trustnode.assistant.models.ExtraSteps"> | |
<property name="rootUrl"/> | |
<property name="steps"><array/></property> | |
</object> | |
</objects> | |
} | |
end | |
def join_path root_url, url | |
if( | |
url.index("http") != 0 && | |
url.index("ftp") != 0 && | |
url != "default" && | |
url != "same" && | |
url != "next" && | |
url.index("goto-") != 0 | |
) | |
File.join(root_url, url) | |
else | |
url | |
end | |
end | |
original_script = open(ARGV[0]).read rescue default_original_script | |
root_path = ARGV[0] || "../../LifeModule" | |
relative_path = ARGV[1] || "" | |
xslt = Nokogiri::XSLT(pretty_print_xslt) | |
n = Nokogiri::XML(original_script) | |
steps = n.search("object[type='com.trustnode.assistant.models.Step']") | |
elements_set = [ | |
n.search("object[type='com.trustnode.assistant.models.Dialogue']"), | |
n.search("object[type='com.trustnode.assistant.models.Question']"), | |
n.search("object[type='com.trustnode.assistant.models.Response']"), | |
n.search("object[type='com.trustnode.assistant.models.Overlay']") | |
] | |
elements_set.each do |elements| | |
elements.each do |element| | |
animation_url = element.search("property[name=animationUrl]").first | |
next unless animation_url | |
path = animation_url["value"] | |
animation_url.attribute("value").value = join_path(relative_path, path) | |
end | |
end | |
n_template = Nokogiri::XML(extra_steps_template) | |
n_template_steps_array = n_template.search("property[name=steps] > array").first | |
steps.each do |step| | |
n_template_steps_array.add_child(step.dup) | |
end | |
root_url_element = n_template.search("property[name=rootUrl]").first | |
root_url_element.set_attribute("value", root_path) | |
puts xslt.apply_to(n_template) | |
#<?xml version="1.0" encoding="ISO-8859-1"?> | |
# | |
# <?xml version="1.0" encoding="utf-8"?> | |
# <objects xmlns="http://www.spicefactory.org/parsley" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:log="http://www.spicefactory.org/parsley/flash/logging" xsi:schemaLocation="http://www.spicefactory.org/parsley http://www.spicefactory.org/parsley/schema/2.0/parsley-core.xsd http://www.spicefactory.org/parsley/flash/logging http://www.spicefactory.org/parsley/schema/2.0/parsley-logging-flash.xsd"> | |
# <object type="com.trustnode.assistant.models.ExtraSteps"> | |
# <property name="rootUrl" value="../../LifeModule"/> | |
# <property name="steps"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Step"> | |
# <property name="id" value="1"/> | |
# <property name="preDialogues"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Dialogue"> | |
# <property name="animationUrl" value="../../LifeModule/assets/animations/harveyKeck.swf"/> | |
# <property name="soundUrl" value="assets/audio/HarveyKeck.mp3"/> | |
# <property name="lines"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Line"> | |
# <property name="text"> | |
# <string>Hey, I am Harvey Keck.</string> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# <property name="question"> | |
# <object type="com.trustnode.assistant.models.Question"> | |
# <property name="form"> | |
# <object type="com.trustnode.assistant.controls.RadioForm"> | |
# <property name="autoPosition" value="true"/> | |
# <property name="x" value="50"/> | |
# <property name="y" value="0"/> | |
# </object> | |
# </property> | |
# <property name="responses"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Response"> | |
# <property name="text" value="Click Here too Continue. This should be multiline. Is it?"/> | |
# <property name="next" value="2"/> | |
# </object> | |
# <object type="com.trustnode.assistant.models.Response"> | |
# <property name="text" value="Click Here too Continue. This should be multiline. Is it?"/> | |
# <property name="next" value="2"/> | |
# </object> | |
# </array> | |
# </property> | |
# </object> | |
# </property> | |
# </object> | |
# <object type="com.trustnode.assistant.models.Step"> | |
# <property name="id" value="2"/> | |
# <property name="preDialogues"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Dialogue"> | |
# <property name="animationUrl" value="../../LifeModule/assets/animations/scene1.swf"/> | |
# <property name="lines"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Line"> | |
# <property name="text"> | |
# <string>Here's a dialogue that grabs an animation from an external swf.</string> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# <property name="commands"> | |
# <string> | |
# [ | |
# [ | |
# "com.trustnode.assistant.controllers.MainController", | |
# "loadStepsFromUrl", | |
# "assets/xml/next_steps_context.xml" | |
# ] | |
# ] | |
# </string> | |
# </property> | |
# </object> | |
# <object type="com.trustnode.assistant.models.Dialogue"> | |
# <property name="animationUrl" value="../../LifeModule/assets/animations/scene2.swf"/> | |
# <property name="lines"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Line"> | |
# <property name="text"> | |
# <string>Here's another dialogue with a different animation.</string> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# <property name="question"> | |
# <object type="com.trustnode.assistant.models.Question"> | |
# <property name="animationUrl" value="../../LifeModule/assets/animations/scene2.swf|blue"/> | |
# <property name="lines"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Line"> | |
# <property name="text"> | |
# <string>FINALLY! A question!</string> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# <property name="form"> | |
# <object type="com.trustnode.assistant.controls.RadioForm"> | |
# <property name="autoPosition" value="false"/> | |
# </object> | |
# </property> | |
# <property name="responses"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Response"> | |
# <property name="text" value="Start from Beginning"/> | |
# <property name="y" value="5"/> | |
# <property name="next" value="1"/> | |
# </object> | |
# <object type="com.trustnode.assistant.models.Response"> | |
# <property name="text" value="Go to the next step"/> | |
# <property name="x" value="50"/> | |
# <property name="y" value="50"/> | |
# <property name="next" value="3"/> | |
# </object> | |
# </array> | |
# </property> | |
# </object> | |
# </property> | |
# </object> | |
# <object type="com.trustnode.assistant.models.Step"> | |
# <property name="id" value="3"/> | |
# <property name="preDialogues"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Dialogue"> | |
# <property name="animationUrl" value="../../LifeModule/assets/animations/scene3.swf"/> | |
# <property name="lines"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Line"> | |
# <property name="text"> | |
# <string>Click here to continue (we have no audio, so dialog stays).</string> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# <property name="question"> | |
# <object type="com.trustnode.assistant.models.Question"> | |
# <property name="form"> | |
# <object type="com.trustnode.assistant.controls.RadioForm"> | |
# <property name="autoPosition" value="true"/> | |
# <property name="x" value="50"/> | |
# <property name="y" value="-20"/> | |
# </object> | |
# </property> | |
# <property name="responses"> | |
# <array> | |
# <object type="com.trustnode.assistant.models.Response"> | |
# <property name="text" value="Play again"/> | |
# <property name="y" value="0"/> | |
# <property name="next" value="3"/> | |
# </object> | |
# <object type="com.trustnode.assistant.models.Response"> | |
# <property name="text" value="Next step"/> | |
# <property name="y" value="0"/> | |
# <property name="next" value="4"/> | |
# </object> | |
# </array> | |
# </property> | |
# </object> | |
# </property> | |
# </object> | |
# </array> | |
# </property> | |
# </object> | |
# </objects> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment