[Cluster-devel] [PATCH 2/2] rgmanager: ra2rng.xsl et al.: enforce "forbid child" from RA metadata

Jan Pokorný jpokorny at redhat.com
Mon Dec 16 12:38:22 UTC 2013


As with previous change, the reflection of this change is yet to come
to cluster.git (ccs_update_schema script) via a separate patch.

Note that this effectively adds requirement for xmllint/libxml2, but
it is required by xsltproc/libxslt already anyway.

Also note that this provision to schema generation will not work
properly until libxslt bugfix [1] is propagated to the target
deployment.

[1] https://mail.gnome.org/archives/xslt/2013-December/msg00001.html

Signed-off-by: Jan Pokorný <jpokorny at redhat.com>
---
 rgmanager/src/resources/Makefile.am            |  15 +-
 rgmanager/src/resources/ra2rng-postprocess.xsl | 265 +++++++++++++++++++++++++
 rgmanager/src/resources/ra2rng.xsl             |  12 ++
 3 files changed, 287 insertions(+), 5 deletions(-)
 create mode 100644 rgmanager/src/resources/ra2rng-postprocess.xsl

diff --git a/rgmanager/src/resources/Makefile.am b/rgmanager/src/resources/Makefile.am
index caeb947..00435f7 100644
--- a/rgmanager/src/resources/Makefile.am
+++ b/rgmanager/src/resources/Makefile.am
@@ -105,12 +105,17 @@ ras-validation: $(RESOURCES) $(TARGET) $(DTD)
 resources.rng: $(RESOURCES) $(TARGET) utils/config-utils.sh
 resources.rng: $(XSL) $(RESRNG)
 	rm -f resources.rng
-	cat resources.rng.head >> resources.rng
 	@echo Generating per-resource RelaxNG information...
-	@for f in $(RESOURCES) $(TARGET); do \
-		echo "    ./$$f"; \
-		bash ./$$f meta-data | xsltproc ra2rng.xsl - >> resources.rng; \
-	done
+	cat resources.rng.head >> resources.rng
+	@{ echo '<rha:wrap xmlns:rha="http://redhat.com/~pkennedy/annotation_namespace/cluster_conf_annot_namespace">'; \
+	   for f in $(RESOURCES) $(TARGET); do \
+	      echo "    ./$$f" >&2; \
+	      bash ./$$f meta-data  | xsltproc ra2rng.xsl -; \
+	   done; \
+	   echo '</rha:wrap>'; } \
+	   | xsltproc ra2rng-postprocess.xsl - \
+	   | xmllint --xpath '/*[local-name() = "wrap"]/node()' - \
+	   >> resources.rng
 	cat resources.rng.mid >> resources.rng
 	cat resources.rng.tail >> resources.rng
 
diff --git a/rgmanager/src/resources/ra2rng-postprocess.xsl b/rgmanager/src/resources/ra2rng-postprocess.xsl
new file mode 100644
index 0000000..066efb3
--- /dev/null
+++ b/rgmanager/src/resources/ra2rng-postprocess.xsl
@@ -0,0 +1,265 @@
+<xsl:stylesheet version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:int="__internal__"
+    xmlns:rha="http://redhat.com/~pkennedy/annotation_namespace/cluster_conf_annot_namespace"
+    exclude-result-prefixes="int">
+
+<xsl:param name="global-init-indent" select="'  '"/>
+<xsl:param name="global-indent" select="'  '"/>
+<xsl:param name="global-radefine-all" select="'CHILDREN'"/>
+<xsl:param name="global-radefine-except"
+           select="concat($global-radefine-all, '-EXCEPT-')"/>
+
+
+<!--
+  helper definitions
+  -->
+
+<xsl:variable name="SP" select="' '"/>
+<xsl:variable name="NL" select="'&#xA;'"/>
+<xsl:variable name="NLNL" select="'&#xA;&#xA;'"/>
+
+<!-- NOTES:
+     - radefine
+       := define[element]
+     - restrictingradefine
+       := define[element and rha:restriction]
+          and in this context also:  ^- and @rha:type = 'forbid-childelem'
+          NOTE: element is currently insignificant, as currently
+                it is implied by the other constraints
+     - forbidchildradefine
+       := radefines forbidden to be referred to from restrictingradefines
+          (as per particular RAs metadada and in turn intermediate
+           rha:restriction annotation)
+     - forbidstring
+       := for restrictingradefine denotes concatenation of respective
+          forbidchildradefines' (ordered!) names (see limitation below
+          and also refer to get-forbidstring named template)
+     - revmap
+       := map using 'key' xslt facility defined reversely, but
+          serving for lookups as implied by the particular name
+          (i.e., not viceversa, "rev" part is already applied)
+     - limitation: 5+ forbidchildradefines per restrictingradefine
+                   (currently 5 atmost, and can be scaled further
+                    by brainless extension of concat's if needed)
+  -->
+<xsl:key name="revmap-forbidstring-to-restrictingradefines"
+         match="define[rha:restriction[
+                    @rha:type = 'forbid-childelem'
+                ]]"
+         use="concat(
+                  rha:restriction[
+                      @rha:type = 'forbid-childelem'
+                  ][1]/@rha:value,
+                  rha:restriction[
+                      @rha:type = 'forbid-childelem'
+                  ][2]/@rha:value,
+                  rha:restriction[
+                      @rha:type = 'forbid-childelem'
+                  ][3]/@rha:value,
+                  rha:restriction[
+                      @rha:type = 'forbid-childelem'
+                  ][4]/@rha:value
+              )"/>
+
+<!-- xsl:key name="revmap-forbidchildradefine-to-restrictingradefines"
+         match="define[rha:restriction[
+                    @rha:type = 'forbid-childelem'
+                ]]"
+         use="//define[
+                  /element/@name = current()/rha:restriction[
+                      @rha:type = 'forbid-childelem'
+                  ]@rha:value
+              ]"/-->
+
+<xsl:key name="revmap-radefine-to-forbidchildradefines"
+         match="define[
+                    element/@name
+                ]"
+         use="//define[rha:restriction[
+                  @rha:type = 'forbid-childelem'
+                  and
+                  @rha:value = current()/element/@name
+              ]]"/>
+
+<xsl:template name="get-forbidstring">
+    <xsl:param name="radefine"/>
+    <xsl:value-of select="concat(
+                              $radefine/rha:restriction[
+                                  @rha:type = 'forbid-childelem'
+                              ][1]/@rha:value,
+                              $radefine/rha:restriction[
+                                  @rha:type = 'forbid-childelem'
+                              ][2]/@rha:value,
+                              $radefine/rha:restriction[
+                                  @rha:type = 'forbid-childelem'
+                              ][3]/@rha:value,
+                              $radefine/rha:restriction[
+                                  @rha:type = 'forbid-childelem'
+                              ][4]/@rha:value
+                          )"/>
+</xsl:template>
+
+<xsl:variable name="all-radefines"
+              select="//define[
+                        element/@name
+                      ]"/>
+
+<xsl:variable name="all-restrictingradefines"
+              select="$all-radefines[rha:restriction[
+                          @rha:type = 'forbid-childelem'
+                      ]]"/>
+
+
+<!--
+  proceed
+  -->
+
+<!-- start with and use identity by default... -->
+
+<xsl:template match="@*|node()">
+    <xsl:copy>
+        <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+</xsl:template>
+
+<!-- ...unless a special case of restrictingradefine, which needs
+     $global-radefine-all reference rewritten to custom
+     $global-radefine-except$forbidstring... -->
+
+<xsl:template match="@*|node()" mode="rewrite">
+    <xsl:copy>
+        <xsl:apply-templates select="@*|node()" mode="rewrite"/>
+    </xsl:copy>
+</xsl:template>
+
+<xsl:template match="ref/@name[. = 'CHILDREN']"
+              mode="rewrite">
+    <!-- NOTE: forbidstring evaluated anew as we do a traversal-based
+               template application rather than procedural one
+               (as there is generally not a direct link parent-child) -->
+    <xsl:variable name="forbidstring">
+        <xsl:call-template name="get-forbidstring">
+            <xsl:with-param name="radefine"
+                            select="ancestor::define[last()]"/>
+        </xsl:call-template>
+    </xsl:variable>
+    <xsl:attribute name="{name()}">
+        <xsl:value-of select="concat($global-radefine-except,
+                                     $forbidstring)"/>
+    </xsl:attribute>
+</xsl:template>
+
+<!-- ... which is triggered amongst others in the following core logic
+     matching any radefine -->
+
+<xsl:template match="define[
+                        element/@name
+                     ]">
+    <xsl:variable name="forbidstring">
+        <xsl:call-template name="get-forbidstring">
+            <xsl:with-param name="radefine"
+                            select="."/>
+        </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="self" select="."/>
+
+    <!-- identity modulo rha:restriction + rewrite or not as per above -->
+    <xsl:copy>
+        <xsl:choose>
+            <xsl:when test="$forbidstring != ''">
+                <xsl:apply-templates select="@*|*[
+                                                 name() != 'rha:restriction'
+                                             ]|processing-instruction()|comment()"
+                                     mode="rewrite"/>
+            </xsl:when>
+            <xsl:otherwise>
+                <xsl:apply-templates select="@*|*[
+                                                 name() != 'rha:restriction'
+                                             ]|processing-instruction()|comment()"/>
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:copy>
+
+    <!-- if we know that $global-radefine-except$forbidstring is not
+         defined by us (set of all radefines is set of all
+         restrictingradefines for this very $forbidstring) AND it is
+         the first restrictingradefine for particular forbidchildradefines
+         (virtually an ordered set, as concatenation keeps ordering),
+         define empty $global-radefine-except$forbidstring symbol, just
+         for the sake of being defined at all (otherwise it couldn't be
+         resolved when no such forbidchildradefine existed) -->
+    <xsl:if test="$forbidstring != ''
+                  and
+                  count(
+                      key(
+                          'revmap-radefine-to-forbidchildradefines',
+                          key(
+                              'revmap-forbidstring-to-restrictingradefines',
+                              $forbidstring
+                          )[1]
+                      )
+                  ) = count($all-radefines)
+                  and
+                  generate-id(
+                      key(
+                          'revmap-forbidstring-to-restrictingradefines',
+                          $forbidstring
+                      )
+                  ) = generate-id()">
+        <xsl:value-of select="concat($NL, $global-init-indent)"/>
+        <xsl:element name="define">
+            <xsl:attribute name="name">
+                <xsl:value-of select="concat($global-radefine-except,
+                                             $forbidstring)"/>
+            </xsl:attribute>
+            <xsl:attribute name="combine">
+                <xsl:value-of select="'choice'"/>
+            </xsl:attribute>
+        </xsl:element>
+    </xsl:if>
+
+    <!-- state the membership of the current radefine in all various
+         $global-radefine-except$forbidstring'ish sets by the means of
+         "combining definition" feature of Relax NG (similar to what is
+         already done with $global-radefine-all themselves) -->
+    <xsl:for-each select="$all-restrictingradefines">
+        <!-- $forbidstring use here always a bug, but cannot be redefined -->
+        <xsl:variable name="forbidstring-other">
+            <xsl:call-template name="get-forbidstring">
+                <xsl:with-param name="radefine"
+                                select="."/>
+            </xsl:call-template>
+        </xsl:variable>
+        <!-- access via the first item below is because this is the only
+             guaranteed to exist -->
+        <xsl:if test="not(
+                          key(
+                              'revmap-radefine-to-forbidchildradefines',
+                              key(
+                                  'revmap-forbidstring-to-restrictingradefines',
+                                  $forbidstring-other
+                              )[1]
+                          )[generate-id() = generate-id($self)]
+                      )">
+            <xsl:value-of select="concat($NL, $global-init-indent)"/>
+            <xsl:element name="define">
+                <xsl:attribute name="name">
+                    <xsl:value-of select="concat($global-radefine-except,
+                                                 $forbidstring-other)"/>
+                </xsl:attribute>
+                <xsl:attribute name="combine">
+                    <xsl:value-of select="'choice'"/>
+                </xsl:attribute>
+                <xsl:element name="ref">
+                    <xsl:attribute name="name">
+                            <xsl:value-of select="$self/@name"/>
+                    </xsl:attribute>
+                </xsl:element>
+            </xsl:element>
+        </xsl:if>
+    </xsl:for-each>
+
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/rgmanager/src/resources/ra2rng.xsl b/rgmanager/src/resources/ra2rng.xsl
index 5b9a307..71df682 100644
--- a/rgmanager/src/resources/ra2rng.xsl
+++ b/rgmanager/src/resources/ra2rng.xsl
@@ -489,6 +489,18 @@
     </xsl:call-template>
     <xsl:value-of select="$NL"/>
 
+        <xsl:for-each select="special[@tag='rgmanager']/child[@forbid='1']">
+            <xsl:call-template name="tag">
+                <xsl:with-param name="name" select="'rha:restriction'"/>
+                <xsl:with-param name="attrs" select="concat(
+                    'rha:type=',  $Q, 'forbid-childelem', $Q, $SP,
+                    'rha:value=', $Q, @type,              $Q)"/>
+                <xsl:with-param name="indented"
+                                select="$global-init-indent"/>
+            </xsl:call-template>
+            <xsl:value-of select="$NL"/>
+        </xsl:for-each>
+
         <!-- element name=... rha:description=... (start) -->
         <xsl:call-template name="tag-start">
             <xsl:with-param name="name" select="'element'"/>
-- 
1.8.1.4




More information about the Cluster-devel mailing list