001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.impl.dtd.models;
019:
020: import org.apache.xerces.xni.QName;
021:
022: import org.apache.xerces.impl.dtd.XMLContentSpec;
023:
024: /**
025: * SimpleContentModel is a derivative of the abstract content model base
026: * class that handles a small set of simple content models that are just
027: * way overkill to give the DFA treatment.
028: * <p>
029: * This class handles the following scenarios:
030: * <ul>
031: * <li> a
032: * <li> a?
033: * <li> a*
034: * <li> a+
035: * <li> a,b
036: * <li> a|b
037: * </ul>
038: * <p>
039: * These all involve a unary operation with one element type, or a binary
040: * operation with two elements. These are very simple and can be checked
041: * in a simple way without a DFA and without the overhead of setting up a
042: * DFA for such a simple check.
043: *
044: * @xerces.internal
045: *
046: * @version $Id: SimpleContentModel.java 572057 2007-09-02 18:03:20Z mrglavas $
047: */
048: public class SimpleContentModel implements ContentModelValidator {
049:
050: //
051: // Constants
052: //
053:
054: /** CHOICE */
055: public static final short CHOICE = -1;
056:
057: /** SEQUENCE */
058: public static final short SEQUENCE = -1;
059:
060: //
061: // Data
062: //
063:
064: /**
065: * The element decl pool indices of the first (and optional second)
066: * child node. The operation code tells us whether the second child
067: * is used or not.
068: */
069: private final QName fFirstChild = new QName();
070:
071: /**
072: * The element decl pool indices of the first (and optional second)
073: * child node. The operation code tells us whether the second child
074: * is used or not.
075: */
076: private final QName fSecondChild = new QName();
077:
078: /**
079: * The operation that this object represents. Since this class only
080: * does simple contents, there is only ever a single operation
081: * involved (i.e. the children of the operation are always one or
082: * two leafs.) This is one of the XMLDTDParams.CONTENTSPECNODE_XXX values.
083: */
084: private final int fOperator;
085:
086: /* this is the EquivClassComparator object */
087: //private EquivClassComparator comparator = null;
088:
089: //
090: // Constructors
091: //
092: /**
093: * Constructs a simple content model.
094: *
095: * @param operator The content model operator.
096: * @param firstChild qualified name of the first child
097: * @param secondChild qualified name of the second child
098: *
099: */
100: public SimpleContentModel(short operator, QName firstChild,
101: QName secondChild) {
102: //
103: // Store away the children and operation. This is all we need to
104: // do the content model check.
105: //
106: // The operation is one of the ContentSpecNode.NODE_XXX values!
107: //
108: fFirstChild.setValues(firstChild);
109: if (secondChild != null) {
110: fSecondChild.setValues(secondChild);
111: } else {
112: fSecondChild.clear();
113: }
114: fOperator = operator;
115: }
116:
117: //
118: // ContentModelValidator methods
119: //
120:
121: /**
122: * Check that the specified content is valid according to this
123: * content model. This method can also be called to do 'what if'
124: * testing of content models just to see if they would be valid.
125: * <p>
126: * A value of -1 in the children array indicates a PCDATA node. All other
127: * indexes will be positive and represent child elements. The count can be
128: * zero, since some elements have the EMPTY content model and that must be
129: * confirmed.
130: *
131: * @param children The children of this element. Each integer is an index within
132: * the <code>StringPool</code> of the child element name. An index
133: * of -1 is used to indicate an occurrence of non-whitespace character
134: * data.
135: * @param offset Offset into the array where the children starts.
136: * @param length The number of entries in the <code>children</code> array.
137: *
138: * @return The value -1 if fully valid, else the 0 based index of the child
139: * that first failed. If the value returned is equal to the number
140: * of children, then the specified children are valid but additional
141: * content is required to reach a valid ending state.
142: *
143: */
144: public int validate(QName[] children, int offset, int length) {
145:
146: //
147: // According to the type of operation, we do the correct type of
148: // content check.
149: //
150: switch (fOperator) {
151: case XMLContentSpec.CONTENTSPECNODE_LEAF:
152: // If there is not a child, then report an error at index 0
153: if (length == 0)
154: return 0;
155:
156: // If the 0th child is not the right kind, report an error at 0
157: if (children[offset].rawname != fFirstChild.rawname) {
158: return 0;
159: }
160:
161: // If more than one child, report an error at index 1
162: if (length > 1)
163: return 1;
164: break;
165:
166: case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE:
167: //
168: // If there is one child, make sure its the right type. If not,
169: // then its an error at index 0.
170: //
171: if (length == 1) {
172: if (children[offset].rawname != fFirstChild.rawname) {
173: return 0;
174: }
175: }
176:
177: //
178: // If the child count is greater than one, then obviously
179: // bad, so report an error at index 1.
180: //
181: if (length > 1)
182: return 1;
183: break;
184:
185: case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE:
186: //
187: // If the child count is zero, that's fine. If its more than
188: // zero, then make sure that all children are of the element
189: // type that we stored. If not, report the index of the first
190: // failed one.
191: //
192: if (length > 0) {
193: for (int index = 0; index < length; index++) {
194: if (children[offset + index].rawname != fFirstChild.rawname) {
195: return index;
196: }
197: }
198: }
199: break;
200:
201: case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE:
202: //
203: // If the child count is zero, that's an error so report
204: // an error at index 0.
205: //
206: if (length == 0)
207: return 0;
208:
209: //
210: // Otherwise we have to check them all to make sure that they
211: // are of the correct child type. If not, then report the index
212: // of the first one that is not.
213: //
214: for (int index = 0; index < length; index++) {
215: if (children[offset + index].rawname != fFirstChild.rawname) {
216: return index;
217: }
218: }
219: break;
220:
221: case XMLContentSpec.CONTENTSPECNODE_CHOICE:
222: //
223: // There must be one and only one child, so if the element count
224: // is zero, return an error at index 0.
225: //
226: if (length == 0)
227: return 0;
228:
229: // If the zeroth element isn't one of our choices, error at 0
230: if ((children[offset].rawname != fFirstChild.rawname)
231: && (children[offset].rawname != fSecondChild.rawname)) {
232: return 0;
233: }
234:
235: // If there is more than one element, then an error at 1
236: if (length > 1)
237: return 1;
238: break;
239:
240: case XMLContentSpec.CONTENTSPECNODE_SEQ:
241: //
242: // There must be two children and they must be the two values
243: // we stored, in the stored order.
244: //
245: if (length == 2) {
246: if (children[offset].rawname != fFirstChild.rawname) {
247: return 0;
248: }
249: if (children[offset + 1].rawname != fSecondChild.rawname) {
250: return 1;
251: }
252: } else {
253: if (length > 2) {
254: return 2;
255: }
256:
257: return length;
258: }
259:
260: break;
261:
262: default:
263: throw new RuntimeException("ImplementationMessages.VAL_CST");
264: }
265:
266: // We survived, so return success status
267: return -1;
268: } // validate
269:
270: } // class SimpleContentModel
|