1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Implementing RELAX NG simplification</title>
</head>
<body>
<h1>Implementing RELAX NG simplification</h1>
<h2>Simplifying <code>grammar</code>, <code>define</code> and
<code>ref</code></h2>
<p>This section sketches how to handle the simplification of
<code>grammar</code>, <code>define</code> and <code>ref</code>
described in sections 4.18 and 4.19 of the RELAX NG specification.</p>
<h3>Initial parse</h3>
<p>The result of the initial parse of the full syntax is a Pattern
object representing the schema; this differs from the simple syntax
pattern in that it contains an additional kind of Pattern, namely a
RefPattern. A RefPattern is a Pattern containing a reference to
another Pattern.</p>
<p>During parsing maintain a current Grammar object. A Grammar object
contains</p>
<ul>
<li>a reference to the start pattern</li>
<li>a map from NCNames to RefPatterns</li>
<li>a reference to a parent grammar</li>
</ul>
<p>When you see a <code><grammar></code> start-tag, create a new
Grammar object that becomes the new current Grammar. Initially the
map is empty, the start pattern is null, and the parent Grammar is the
old current Grammar.</p>
<p>When you see a <code>define</code> element, look up the name in the
current Grammar's map. If it doesn't exist, add a new RefPattern
referring to the body of the definition. If it does exist, then check
with the RefPattern's pattern reference is null; it is is null, then
change it to refer to the body of the definition; if it's not null,
then we have a duplicate definition.</p>
<p>Handle <code><start></code> similarly to
<code><define></code>.</p>
<p>When you see a <code><ref></code> element, lookup the name in
the current Grammar's map. If it doesn't exist, add a new RefPattern
with a null pattern reference to the map. In either case, return that
RefPattern as the result of parsing the <code><ref></code>
element.</p>
<p>When you see a <code><parentRef></code> do the same as
<code><ref></code> except use the parent Grammar's map.</p>
<p>At the <code><grammar></code> end-tag, check that the start
of the current grammar is non-null. Also walk the map to check that
all RefPatterns have non-null pattern references. Return the start
pattern as the result of parsing the <code><grammar></code>
element.</p>
<h3>Checking for illegal recursion</h3>
<p>The next task is to check that there is no illegal recursion. For
this it is convenient to add a <code>checkRecursionDepth</code> field
to the PatternRef object. This should be initialized to -1. Define a
<code>checkRecursion(int depth)</code> method on Patterns. By default
this simply calls <code>checkRecursion</code> with the same argument
on all subpatterns. For an ElementPattern it calls
<code>checkRecursion(depth + 1)</code>. For a PatternRef pattern it
does this:</p>
<pre>
checkRecursion(int depth) {
if (checkRecursionDepth == -1) {
checkRecursionDepth = depth;
referencedPattern.checkRecursion(depth);
checkRecursionDepth = -2;
}
else if (depth == checkRecursionDepth)
error("illegal recursion");
}
</pre>
<p>To check for illegal recursions, call
<code>checkRecursion(0)</code> on the pattern for the schema as a
whole.</p>
<h3>Expanding references</h3>
<p>After determining that there is no illegal recursion, the next
stage is to eliminate RefPatterns. Do this with an
<code>expand()</code> method on Patterns. It is convenient to add a
<code>boolean</code> expanded field to ElementPattern; this is
initialized to false. For an ElementPattern the code for expand is</p>
<pre>
Pattern expand() {
if (!expanded) {
expanded = true;
content = expand(content);
}
return this;
}
</pre>
<p>For a RefPattern it would be simply</p>
<pre>
Pattern expand() {
return referencedPattern.expand();
}
</pre>
<p>For a Text/DataPattern etc it would be simply</p>
<pre>
Pattern expand() {
return this;
}
</pre>
<p>For a Choice it would be</p>
<pre>
Pattern expand() {
return makeChoice(operand1.expand(), operand2.expand());
}
</pre>
<h2>Handling <code>include</code> and <code>combine</code></h2>
<p>See the following <a
href="http://lists.oasis-open.org/archives/relax-ng/200106/msg00058.html"
>message</a> from Kohsuke Kawaguchi.</p>
<address>
<a href="mailto:jjc@jclark.com">James Clark</a>
</address>
</body>
</html>
|