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

Jan Pokorný jpokorny at redhat.com
Mon Dec 16 12:58:35 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.

There is a new file included in "DIST", ra2rng-postprocess.xsl, that
is to be appended  to a pipe with original ra2rng.xsl (both with xsltproc
as an effective actor, indeed), that in turn now requires some extra
decoration as can be found also in the respective Makefile.am.

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            |  17 +-
 rgmanager/src/resources/ra2rng-postprocess.xsl | 265 +++++++++++++++++++++++++
 rgmanager/src/resources/ra2rng.xsl             |  12 ++
 3 files changed, 288 insertions(+), 6 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..af350a9 100644
--- a/rgmanager/src/resources/Makefile.am
+++ b/rgmanager/src/resources/Makefile.am
@@ -41,7 +41,7 @@ HELPERS			= ocf-shellfuncs svclib_nfslock \
 
 DTD			= ra-api-1-modified.dtd
 
-XSL			= ra2man.xsl ra2ref.xsl ra2rng.xsl
+XSL			= ra2man.xsl ra2ref.xsl ra2rng.xsl ra2rng-postprocess.xsl
 
 RESRNG			= resources.rng.head resources.rng.mid resources.rng.tail
 
@@ -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