diff options
Diffstat (limited to 'src/current/include/orderizer.xsl')
-rw-r--r-- | src/current/include/orderizer.xsl | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/current/include/orderizer.xsl b/src/current/include/orderizer.xsl new file mode 100644 index 0000000..170bd2b --- /dev/null +++ b/src/current/include/orderizer.xsl @@ -0,0 +1,268 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!-- + No, not "odorizer". + + This is a powerful system that takes an immensely complex (and insurmountable) + task out of the programmer's hands. In particular, the system: + + - Uses the map to recognize the order in which params appear in a UI + - Using that order, determines which fields in the UI could potentially + cause fields that appear previous to them to become invalid (e.g. hide) + due to classification criteria. + - Based on those conflicts, constructs a custom classification that ignores + only the conflicting portions, allowing a great deal of precision in + controlling field validity up to that particular point in the UI. + + The result is highly-refined, custom-generated classifications per-question + for only the criteria that are needed to ensure that fields cannot hide fields + previous to them: A task that would otherwise be prohibitively complicated (or + would otherwise have to be far too coarse) if done manually in systems with + highly sophisticated classification schemes. Furthermore, the result is wholly + deterministic. + + It should be noted that futher benefit can be realized when the map is altered + or questions in the UI are reordered; the system will simply re-calculate new + classifications that yield desirable results. +--> + +<xsl:stylesheet version="2.0" + xmlns="http://www.w3.org/1999/xhtml" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:lv="http://www.lovullo.com/rater" + xmlns:lvp="http://www.lovullo.com" + xmlns:lvm="http://www.lovullo.com/rater/map" + xmlns:lvmc="http://www.lovullo.com/rater/map/compiler" + xmlns:gc="http://www.lovullo.com/calc/global-classifier" + xmlns:c="http://www.lovullo.com/calc" + xmlns:o="http://www.lovullo.com/rater/compiler/orderizer" + xmlns:preproc="http://www.lovullo.com/rater/preproc"> + + + +<!-- + Determines param conflicts based on UI ordering +--> +<xsl:template name="o:analyze"> + <xsl:param name="class-deps" /> + <xsl:param name="ui" /> + <xsl:param name="sdmap" /> + <xsl:param name="param-classes" /> + + <xsl:variable name="rater" select="." /> + + <!-- put fields in the order that they appear in the UI --> + <!-- TODO: duplicate check (error) --> + <xsl:variable name="ordered"> + <o:ordered> + <xsl:for-each select="$ui//lvp:question"> + <xsl:variable name="id" select="@id" /> + <xsl:copy-of select="$sdmap/lvmc:map[ @from=$id ]" /> + </xsl:for-each> + </o:ordered> + </xsl:variable> + + <!-- the param-class list gives us the classes that are directly used; let's + get a list of all classes that are used by those classes as well, which + will simplify the queries to come --> + <xsl:message>[orderizer] recursively discovering param classes...</xsl:message> + <xsl:variable name="param-classes-expanded"> + <xsl:apply-templates select="$param-classes" mode="o:gen-param-reflist"> + <xsl:with-param name="class-deps" select="$class-deps" /> + </xsl:apply-templates> + </xsl:variable> + + <xsl:variable name="initial"> + <o:analysis> + <xsl:for-each select="$ordered//lvmc:*"> + <xsl:variable name="cur" select="." /> + <xsl:variable name="pref" select="@to" /> + + <!-- progress indicator --> + <xsl:message> + <xsl:text>[orderizer] checking previous UI siblings: </xsl:text> + <xsl:value-of select="@to" /> + </xsl:message> + + <!-- preceding --> + <xsl:for-each select=" + $param-classes/gc:param[ + @ref=$cur/preceding-sibling::lvmc:map/@to + ]"> + + <!-- immediate conflicts (we check these separately rather than in the + xpath above, which would be cleaner, so that they can be + processed --> + <xsl:variable name="conflicts" select=" + .//gc:class[ + @ref=$param-classes-expanded/o:param-refs/o:param[ + @ref=$pref + ]/o:class/@ref + ] + " /> + + <xsl:if test="$conflicts"> + <o:conflict ref="{@ref}" relative-to="{$pref}"> + <xsl:for-each select="$conflicts"> + <!-- record the immediate problem --> + <o:class ref="{@ref}" yields="{@yields}" /> + </xsl:for-each> + </o:conflict> + </xsl:if> + </xsl:for-each> + </xsl:for-each> + </o:analysis> + </xsl:variable> + + <xsl:apply-templates select="$initial/o:analysis" mode="o:reduce-analysis" /> +</xsl:template> + + +<xsl:template match="gc:param-classes" mode="o:gen-param-reflist" priority="5"> + <xsl:param name="class-deps" /> + + <o:param-refs> + <xsl:apply-templates select="gc:param" mode="o:gen-param-reflist"> + <xsl:with-param name="class-deps" select="$class-deps" /> + </xsl:apply-templates> + </o:param-refs> +</xsl:template> + +<xsl:template match="gc:param" mode="o:gen-param-reflist" priority="5"> + <xsl:param name="class-deps" /> + + <o:param ref="{@ref}"> + <xsl:apply-templates select="gc:class" mode="o:gen-param-reflist"> + <xsl:with-param name="class-deps" select="$class-deps" /> + </xsl:apply-templates> + </o:param> +</xsl:template> + +<xsl:template match="gc:class" mode="o:gen-param-reflist" priority="5"> + <xsl:param name="class-deps" /> + + <!-- well, this class is certainly used --> + <o:class ref="{@ref}" /> + + <xsl:variable name="ref" select="@ref" /> + + <!-- but how about things that use this class? --> + <xsl:apply-templates select="$class-deps/preproc:class[ @ref=$ref ]" + mode="o:gen-param-reflist"> + <xsl:with-param name="class-deps" select="$class-deps" /> + </xsl:apply-templates> +</xsl:template> + +<xsl:template match="preproc:class" mode="o:gen-param-reflist" priority="5"> + <xsl:param name="class-deps" /> + + <o:class ref="{@ref}" /> + + <xsl:apply-templates mode="o:gen-param-reflist"> + <xsl:with-param name="class-deps" select="$class-deps" /> + </xsl:apply-templates> +</xsl:template> + +<xsl:template match="*" mode="o:gen-param-reflist" priority="1"> + <!-- do nothing --> +</xsl:template> + + +<xsl:template match="preproc:class" mode="o:get-indirect-params" priority="5"> + <xsl:apply-templates mode="o:get-indirect-params" /> +</xsl:template> + +<xsl:template match="preproc:class-dep" mode="o:get-indirect-params" priority="5"> + <xsl:variable name="ref" select="@ref" /> + + <xsl:apply-templates + select="ancestor::preproc:class-deps/preproc:class[ @ref=$ref ]" + mode="o:get-indirect-params" /> +</xsl:template> + +<xsl:template match="preproc:rate-dep" mode="o:get-indirect-params" priority="5"> + <xsl:variable name="ref" select="@ref" /> + + <xsl:apply-templates + select="//preproc:rate-deps/preproc:rate[ @ref=$ref ]" + mode="o:get-indirect-params" /> +</xsl:template> + +<xsl:template match="preproc:param" mode="o:get-indirect-params" priority="5"> + <xsl:copy-of select="." /> +</xsl:template> + +<xsl:template match="*" mode="o:get-indirect-params" priority="1"> + <!-- do nothing --> +</xsl:template> + + +<!-- + Combines initial analysis results, merging common refs and de-duplicating + conflicts. +--> +<xsl:template match="o:analysis" mode="o:reduce-analysis"> + <!-- start by combining the contents of all unique refs --> + <xsl:variable name="combined"> + <xsl:for-each select=" + o:conflict[ + not( @ref=preceding-sibling::o:conflict/@ref ) + ] + "> + + <xsl:variable name="ref" select="@ref" /> + <xsl:variable name="dups" select=" + following-sibling::o:conflict[ @ref=$ref ] + " /> + + <o:conflict ref="{@ref}"> + <!-- add relativity nodes --> + <xsl:for-each select="$dups|."> + <o:relative-to ref="{@relative-to}" /> + </xsl:for-each> + + <!-- add class deps --> + <o:reasons> + <xsl:copy-of select="($dups|.)/o:class" /> + </o:reasons> + </o:conflict> + </xsl:for-each> + </xsl:variable> + + <!-- now, remove duplicates resulting from the above operation --> + <xsl:copy> + <xsl:copy-of select="@*" /> + + <xsl:apply-templates select="$combined/o:conflict" + mode="o:reduce-analysis" /> + </xsl:copy> +</xsl:template> + +<xsl:template match="o:conflict" mode="o:reduce-analysis"> + <xsl:copy> + <xsl:copy-of select="@*" /> + + <!-- unique relative-to nodes --> + <xsl:copy-of select=" + o:relative-to[ + not( @ref=preceding-sibling::o:relative-to/@ref ) + ] + " /> + + <xsl:apply-templates select="o:reasons" mode="o:reduce-analysis" /> + </xsl:copy> +</xsl:template> + +<xsl:template match="o:reasons" mode="o:reduce-analysis"> + <xsl:copy> + <xsl:copy-of select="@*" /> + + <!-- unique reasons --> + <xsl:copy-of select=" + o:class[ + not( @ref=preceding-sibling::o:class/@ref ) + ] + " /> + </xsl:copy> +</xsl:template> + +</xsl:stylesheet> |