Skip to content

Commit

Permalink
* breaking struc tags out of rule tags, adding apply tag
Browse files Browse the repository at this point in the history
* rules now apply to all elements
* adding untested alternative sss xslt (sss_alt.xsl) that uses css style selectors (probably won't ever use this)
  • Loading branch information
bwrobinett committed Sep 4, 2009
1 parent dff38fb commit 73b14b8
Show file tree
Hide file tree
Showing 7 changed files with 988 additions and 65 deletions.
1 change: 1 addition & 0 deletions Bent/structure stylesheet/expample_doc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<link rel="stylesheet" type="xml/sss" href="structure_stylesheet_example.xml"/>
</head>
<body>
<p id="xxxxxxxxx">string 0</p>
<div id="ding" class="blah" title="hello"><p>string 1</p></div>
<p><span id="dong" class="blah foo">string 2</span></p>
<p><span id="doh" class="blah">string 3</span></p>
Expand Down
28 changes: 22 additions & 6 deletions Bent/structure stylesheet/sss.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
<xsl:variable name="structure_stylesheet_filename" select="/h:html/h:head/h:link[@type='xml/sss']/@href"/>
<xsl:variable name="structure_stylesheet" select="document($structure_stylesheet_filename)/*"/>
<!--grab all structure stylesheet rules-->
<xsl:variable name="rules" select="$structure_stylesheet/s:rule/s:sel"/>
<xsl:variable name="rules" select="$structure_stylesheet/s:rule/s:match"/>
<xsl:variable name="last_rule_id" select="generate-id($rules[last()])"/>
<!--key named strucs-->
<xsl:key name="struc" match="s:struc" use="@name"/>

<!--
Identity transform (what comes in goes out)
Expand Down Expand Up @@ -50,7 +52,7 @@
-->

<!--for each element in the main doc (with class or id)-->
<xsl:template match="*[@*]">
<xsl:template match="*">
<xsl:variable name="attr_name_val_string">
<xsl:apply-templates select="@*" mode="generate_attr_name_val_string"/>
</xsl:variable>
Expand Down Expand Up @@ -160,6 +162,7 @@
</xsl:when>
<xsl:otherwise>
<!--once we've got all the matching rules, find most specific matching rule-->
<!--<h1 style="color:red;">rule gathered!</h1>-->
<xsl:call-template name="find_most_specific_rule">
<xsl:with-param name="matching_rules" select="$more_gathered_rules"/>
<xsl:with-param name="current_node" select="$current_node"/>
Expand Down Expand Up @@ -264,13 +267,20 @@
</xsl:when>
<xsl:otherwise>
<!--most specific rule found (yay!); apply it to the current node-->
<xsl:apply-templates select="$matching_rules/../s:struc" mode="structure_stylesheet">
<xsl:with-param name="current_node" select="$current_node"/>
</xsl:apply-templates>
<!--<h1 style="color:blue">most specific rule found!</h1>-->
<xsl:variable name="struc_name" select="$matching_rules/../s:apply/@struc"/>
<!--switch context to structure_stylesheet (what if there is more than one? Should work great?-->
<xsl:for-each select="$structure_stylesheet">
<!--<h2>[xx<xsl:value-of select="$struc_name"/>xx]</h2>-->
<xsl:apply-templates select="key('struc', $struc_name)" mode="structure_stylesheet">
<xsl:with-param name="current_node" select="$current_node"/>
</xsl:apply-templates>
</xsl:for-each>

<!--if no matching rules, just copy the node-->
<xsl:if test="not($matching_rules)">
<xsl:apply-templates select="$current_node" mode="structure_stylesheet"/>
<!--<h1 style="color:blue">no matching rules, just copy (<xsl:value-of select="$current_node"/>)</h1>-->
<xsl:apply-templates select="$current_node" mode="just_copy_elem"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
Expand All @@ -281,6 +291,12 @@
Templates for adding extra stucture to an element
-->

<xsl:template match="*" mode="just_copy_elem">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<xsl:template match="@*|node()" mode="structure_stylesheet">
<xsl:param name="current_node"/>
<xsl:copy>
Expand Down
265 changes: 265 additions & 0 deletions Bent/structure stylesheet/sss_alt.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="structure_stylesheet"
xmlns:h="http://www.w3.org/1999/xhtml"
>
<xsl:output method="html" indent="yes"/>

<!--grab all structure stylesheets-->
<xsl:variable name="structure_stylesheet_filename" select="/h:html/h:head/h:link[@type='xml/sss']/@href"/>
<xsl:variable name="structure_stylesheets" select="document($structure_stylesheet_filename)/*"/>
<!--grab all structure stylesheet rules-->
<xsl:variable name="rules" select="$structure_stylesheets/s:rule"/>
<xsl:variable name="sels" select="$rules/s:sel"/>
<xsl:variable name="num_sels" select="count($sels)"/>

<!--
Identity transform (what comes in goes out)
-->
<xsl:template match="/|@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<!--process all element nodes-->
<xsl:template match="*">
<!--apply rule with highest precedence-->

</xsl:template>

<!--find highest prececence rule-->

<!--gather all matching rules for a given node-->
<xsl:template name="gather_sels">
<xsl:param name="gathered_sels"/>
<xsl:param name="sel_index"/>
<xsl:param name="sel"/>
<xsl:param name="sel_string"/>
<xsl:param name="current_elem"/>
<xsl:param name="id_string" select="string(@id)"/>
<xsl:param name="tag_string" select="name()"/>
<xsl:param name="class_string" select="normalize-space(@class)"/>
<xsl:param name="attr_nodes" select="@*"/>

<!--figure out if current selector is match-->
<xsl:variable name="sel_is_match">
<xsl:call-template name="test_sel">
<xsl:with-param name="sel_string" select="$sel_string"/>
<xsl:with-param name="id_string" select="$id_string"/>
<xsl:with-param name="tag_string" select="$tag_string"/>
<xsl:with-param name="class_string" select="$class_string"/>
<xsl:with-param name="attr_nodes" select="$attr_nodes"/>
</xsl:call-template>
</xsl:variable>

<xsl:variable name="next_sel_index" select="$sel_index + 1"/>
<xsl:choose>
<xsl:when test="$next_sel_index &lt; $num_sel">
<xsl:variable name="next_sel" select="$sels[$next_sel_index]"/>
<!--add current selector to collection if it's match; look at next selector-->
<xsl:call-template name="gather_sels">
<xsl:with-param name="gathered_sels" select="$gathered_sels|sel[$sel_is_match]"/>
<xsl:with-param name="sel_index" select="$next_sel_index"/>
<xsl:with-param name="sel" select="$sels[$next_sel_index]"/>
<xsl:with-param name="sel_string" select="string($next_sel)"/>
<xsl:with-param name="current_elem" select="$current_elem"/>
<xsl:with-param name="id_string" select="$id_string"/>
<xsl:with-param name="tag_string" select="$tag_string"/>
<xsl:with-param name="class_string" select="$class_string"/>
<xsl:with-param name="attr_nodes" select="$attr_nodes"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!--all matching selector gathered; find selector with hightes precedence-->
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<!--**TODO: think about getting rid of this and just do a straight call to test_id_sel-->
<xsl:template name="test_sel">
<xsl:param name="sel_string"/>
<xsl:param name="id_string"/>
<xsl:param name="tag_string"/>
<xsl:param name="class_string"/>
<xsl:param name="attr_nodes"/>

<!--start test with id selector; if id selector is a match, this will continue on to test other selectors-->
<xsl:call-template name="test_id_sel">
<xsl:with-param name="sel_string"/>
<xsl:with-param name="id_string"/>
<xsl:with-param name="tag_string"/>
<xsl:with-param name="class_string"/>
<xsl:with-param name="attr_nodes"/>
</xsl:call-template>
</xsl:template>

<!--check if selector matches id-->
<xsl:template name="test_id_sel">
<xsl:param name="sel_string"/>
<xsl:param name="id_string"/>
<xsl:param name="tag_string"/>
<xsl:param name="class_string"/>
<xsl:param name="attr_nodes"/>

<xsl:variable name="sel_has_no_id" select="not(contains($sel_string, '#'))"/>
<!--
The second half of the if test below is pretty messy. Here's what's going on:
// reformat selector string to guarantee id is sandwiched between a "#" and a "?"
$reform_sel_string := concat(translate($sel_string, '.[', '??'), '?')
// extract id from reformated substring
$substring-before(substring-after($reform_sel_string, '#'), '?')
-->
<xsl:if test="$sel_has_no_id or $id_string = $substring-before(substring-after(concat(translate($sel_string, '.[', '??'), '?'), '#'), '?')">
<!--id sel matches; check tag sel-->
<xsl:call-template name="test_tag_sel">
<xsl:with-param name="sel_string"/>
<xsl:with-param name="tag_string"/>
<xsl:with-param name="class_string"/>
<xsl:with-param name="attr_nodes"/>
</xsl:call-template>
</xsl:if>
</xsl:template>

<!--check if selector matches tag-->
<xsl:template name="test_tag_sel">
<xsl:param name="sel_string"/>
<xsl:param name="tag_string"/>
<xsl:param name="class_string"/>
<xsl:param name="attr_nodes"/>

<xsl:variable name="reform_sel_string" select="concat(translate($sel_string, '.#[', '???'), '?')"/>
<!--check if selector has a tag-->
<xsl:variable name="sel_has_no_tag" select="starts-with($reform_sel_string, '?')"/>
<xsl:if test="$sel_has_no_tag or $tag_string = substring-before($reform_sel_string, '?'))">
<!--tag sel matches; check class sel-->
<xsl:call-template name="test_class_sel">
<xsl:with-param name="sel_string"/>
<xsl:with-param name="class_string"/>
<xsl:with-param name="attr_nodes"/>
</xsl:call-template>
</xsl:if>
</xsl:template>

<!--check if selector matches classes-->
<xsl:template name="test_class_sel">
<xsl:param name="sel_string"/>
<xsl:param name="class_string"/>
<xsl:param name="attr_nodes"/>

<xsl:variable name="sel_has_no_class" select="contains($sel_string, '.')"/>

<xsl:choose>
<xsl:when test="$sel_has_no_class">
<!--class sel matches; check attr sel-->
<xsl:call-template name="test_attr_sel">
<xsl:with-param name="sel_string"/>
<xsl:with-param name="attr_nodes"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!--
trim start of selector up to first class
replace # and ['s with ?'s
add .? to end
e.g. class1?blah?a=b].class2.class3?c].?
-->
<xsl:variable name="reform_sel_string" select="concat(translate(substring-after($sel_string, '.'), '#[', '??'), '?')"/>
<xsl:variable name="all_classes_match">
<xsl:call-template name="check_classes">
<xsl:with-param name="reform_sel_string" select="$reform_sel_string"/>
<xsl:with-param name="class_string" select="$class_string"/>
</xsl:call-template>
</xsl:variable>
<xsl:if test="$all_classes_match">
<!--all class sel match; check all attr sel-->
<xsl:call-template name="test_attr_sel">
<xsl:with-param name="sel_string"/>
<xsl:with-param name="attr_nodes"/>
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="check_classes">
<xsl:param name="reform_sel_string"/>
<xsl:param name="class_string"/>

<!--one of these substrings will be empty, the other will be the current class-->
<xsl:variable name="current_class" select="concat(
substring-before(substring-before($reform_sel_string, '.'), '?'),
substring-before(substring-before($reform_sel_string, '?'), '.')
)"/>

<!--check if elem class contains current class selector-->
<xsl:if select="contains($class_string, $current_class)">
<xsl:variable name="next_reform_sel_string" select="$substring-after($reform_sel_string, '.')"/>
<xsl:choose>
<!--see if there are any classes left to check-->
<xsl:when test="$next_reform_sel_string">
<xsl:call-template name="check_classes">
<xsl:with-param name="reform_sel_string" select="$next_reform_sel_string"/>
<xsl:with-param name="class_string" select="$class_string"/>
</xsl:call-template>
</xsl:when>
<!--all class selectors match!-->
<xsl:otherwise>true</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>

<xsl:template name="test_attr_sel">
<xsl:param name="sel_string"/>
<xsl:param name="attr_nodes"/>

<xsl:variable name="sel_has_no_attr" select="not(contains($sel_string, '['))"/>
<xsl:choose>
<!--entire selector matches!!!-->
<xsl:when test="sel_has_no_attr">true</xsl:when>
<!--check for attr match-->
<xsl:otherwise>
<xsl:call-template name="check_attr">
<xsl:with-param name="reform_sel_string" select="substring-after($sel_string, '[')"/>
<xsl:with-param name="attr_nodes" select="$attr_nodes"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:call-template name="check_attr">
<xsl:param name="reform_sel_string"/>
<xsl:param name="attr_nodes"/>

<xsl:variable name="current_attr_name" select="substring-before(translate($sel_string, '=', ']'), ']')"/>
<xsl:variable name="current_attr_val" select="substring-before(substring-after($sel_string, '='), ']')"/>
<xsl:variable name="attr_has_val" select="contains($sel_string, '=')"/>

<!--
check if elem attr match current attr selector
first line checks for name only selector match, e.g. [name]
second line checks for name and value selector match, e.g. [name=val]
-->
<xsl:if select="
not($attr_has_val) and $attr_nodes[name() = $current_attr_name] or
$attr_has_val and $attr_nodes[name() = $current_attr_name and . = $current_attr_val]
">
<xsl:variable name="next_reform_sel_string" select="$substring-after($reform_sel_string, '[')"/>
<xsl:choose>
<!--see if there are any classes left to check-->
<xsl:when test="$next_reform_sel_string">
<xsl:call-template name="check_attr">
<xsl:with-param name="reform_sel_string" select="$next_reform_sel_string"/>
<xsl:with-param name="attr_nodes" select="$attr_nodes"/>
</xsl:call-template>
</xsl:when>
<!--entire selector matches!-->
<xsl:otherwise>true</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:call-template>

</xsl:stylesheet>
Loading

0 comments on commit 73b14b8

Please sign in to comment.