001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999,2000 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058: package org.apache.xerces.validators.common;
059:
060: import org.apache.xerces.framework.XMLContentSpec;
061: import org.apache.xerces.utils.QName;
062: import org.apache.xerces.utils.StringPool;
063: import org.apache.xerces.validators.schema.SubstitutionGroupComparator;
064: import org.apache.xerces.validators.schema.SchemaGrammar;
065:
066: /**
067: * MixedContentModel is a derivative of the abstract content model base
068: * class that handles the special case of mixed model elements. If an element
069: * is mixed model, it has PCDATA as its first possible content, followed
070: * by an alternation of the possible children. The children cannot have any
071: * numeration or order, so it must look like this:
072: * <pre>
073: * <!ELEMENT Foo ((#PCDATA|a|b|c|)*)>
074: * </pre>
075: * So, all we have to do is to keep an array of the possible children and
076: * validate by just looking up each child being validated by looking it up
077: * in the list.
078: *
079: * @version $Id: MixedContentModel.java,v 1.14 2001/07/16 21:22:16 sandygao Exp $
080: */
081: public class MixedContentModel implements XMLContentModel {
082:
083: //
084: // Data
085: //
086:
087: /** The count of possible children that we have to deal with. */
088: private int fCount;
089:
090: /** The list of possible children that we have to accept. */
091: private QName fChildren[];
092:
093: /** The type of the children to support ANY. */
094: private int fChildrenType[];
095:
096: /* this is the SubstitutionGroupComparator object */
097: private SubstitutionGroupComparator comparator = null;
098:
099: /**
100: * True if mixed content model is ordered. DTD mixed content models
101: * are <em>always</em> unordered.
102: */
103: private boolean fOrdered;
104:
105: /** Boolean to allow DTDs to validate even with namespace support. */
106: private boolean fDTD;
107:
108: //
109: // Constructors
110: //
111:
112: /**
113: * Constructs a mixed content model.
114: *
115: * @param count The child count.
116: * @param childList The list of allowed children.
117: *
118: * @exception CMException Thrown if content model can't be built.
119: */
120: public MixedContentModel(QName childList[], int childListType[],
121: int offset, int length) throws CMException {
122: this (childList, childListType, offset, length, false, false);
123: }
124:
125: /**
126: * Constructs a mixed content model.
127: *
128: * @param count The child count.
129: * @param childList The list of allowed children.
130: * @param ordered True if content must be ordered.
131: *
132: * @exception CMException Thrown if content model can't be built.
133: */
134: public MixedContentModel(QName childList[], int childListType[],
135: int offset, int length, boolean ordered) throws CMException {
136: this (childList, childListType, offset, length, ordered, false);
137: }
138:
139: /**
140: * Constructs a mixed content model.
141: *
142: * @param count The child count.
143: * @param childList The list of allowed children.
144: * @param ordered True if content must be ordered.
145: *
146: * @exception CMException Thrown if content model can't be built.
147: */
148: public MixedContentModel(QName childList[], int childListType[],
149: int offset, int length, boolean ordered, boolean dtd)
150: throws CMException {
151:
152: // Make our own copy now, which is exactly the right size
153: fCount = length;
154: fChildren = new QName[fCount];
155: fChildrenType = new int[fCount];
156: for (int i = 0; i < fCount; i++) {
157: fChildren[i] = new QName(childList[offset + i]);
158: fChildrenType[i] = childListType[offset + i];
159: }
160: fOrdered = ordered;
161:
162: fDTD = dtd;
163:
164: } // <init>(QName[],int[],int,int,boolean,boolean)
165:
166: // Unique Particle Attribution
167: public void checkUniqueParticleAttribution(SchemaGrammar gram) {
168: // rename back
169: for (int i = 0; i < fCount; i++)
170: fChildren[i].uri = gram
171: .getContentSpecOrgUri(fChildren[i].uri);
172:
173: // for mixed content model, it's only a sequence
174: // UPA checking is not necessary
175: }
176:
177: // Unique Particle Attribution
178:
179: //
180: // XMLContentModel methods
181: //
182:
183: /**
184: * Check that the specified content is valid according to this
185: * content model. This method can also be called to do 'what if'
186: * testing of content models just to see if they would be valid.
187: * <p>
188: * A value of -1 in the children array indicates a PCDATA node. All other
189: * indexes will be positive and represent child elements. The count can be
190: * zero, since some elements have the EMPTY content model and that must be
191: * confirmed.
192: *
193: * @param children The children of this element. Each integer is an index within
194: * the <code>StringPool</code> of the child element name. An index
195: * of -1 is used to indicate an occurrence of non-whitespace character
196: * data.
197: * @param offset Offset into the array where the children starts.
198: * @param length The number of entries in the <code>children</code> array.
199: *
200: * @return The value -1 if fully valid, else the 0 based index of the child
201: * that first failed. If the value returned is equal to the number
202: * of children, then the specified children are valid but additional
203: * content is required to reach a valid ending state.
204: *
205: * @exception Exception Thrown on error.
206: */
207: public int validateContent(QName children[], int offset, int length)
208: throws Exception {
209:
210: // must match order
211: if (fOrdered) {
212: int inIndex = 0;
213: for (int outIndex = 0; outIndex < length; outIndex++) {
214:
215: // ignore mixed text
216: final QName curChild = children[offset + outIndex];
217: if (curChild.localpart == -1) {
218: continue;
219: }
220:
221: // element must match
222: int type = fChildrenType[inIndex];
223: if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
224: if (fDTD) {
225: if (fChildren[inIndex].rawname != children[offset
226: + outIndex].rawname) {
227: return outIndex;
228: }
229: } else {
230: if (fChildren[inIndex].uri != children[offset
231: + outIndex].uri
232: && fChildren[inIndex].localpart != children[offset
233: + outIndex].localpart) {
234: return outIndex;
235: }
236: }
237: }
238:
239: // advance index
240: inIndex++;
241: }
242: }
243:
244: // can appear in any order
245: else {
246: for (int outIndex = 0; outIndex < length; outIndex++) {
247: // Get the current child out of the source index
248: final QName curChild = children[offset + outIndex];
249:
250: // If its PCDATA, then we just accept that
251: if (curChild.localpart == -1)
252: continue;
253:
254: // And try to find it in our list
255: int inIndex = 0;
256: for (; inIndex < fCount; inIndex++) {
257: int type = fChildrenType[inIndex];
258: if (type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
259: if (fDTD) {
260: if (curChild.rawname == fChildren[inIndex].rawname) {
261: break;
262: }
263: } else {
264: if (curChild.uri == fChildren[inIndex].uri
265: && curChild.localpart == fChildren[inIndex].localpart)
266: break;
267: }
268: }
269: }
270:
271: // We did not find this one, so the validation failed
272: if (inIndex == fCount)
273: return outIndex;
274: }
275: }
276:
277: // Everything seems to be in order, so return success
278: return -1;
279:
280: }
281:
282: public int validateContentSpecial(QName children[], int offset,
283: int length) throws Exception {
284: //TO DO here. cause Mixed Content is only for DTD, Schema is kind of different.
285: return validateContent(children, offset, length);
286: }
287:
288: public void setSubstitutionGroupComparator(
289: SubstitutionGroupComparator comparator) {
290: this .comparator = comparator;
291: }
292:
293: /**
294: * Returns information about which elements can be placed at a particular point
295: * in the passed element's content model.
296: * <p>
297: * Note that the incoming content model to test must be valid at least up to
298: * the insertion point. If not, then -1 will be returned and the info object
299: * will not have been filled in.
300: * <p>
301: * If, on return, the info.isValidEOC flag is set, then the 'insert after'
302: * element is a valid end of content. In other words, nothing needs to be
303: * inserted after it to make the parent element's content model valid.
304: *
305: * @param fullyValid Only return elements that can be inserted and still
306: * maintain the validity of subsequent elements past the
307: * insertion point (if any). If the insertion point is at
308: * the end, and this is true, then only elements that can
309: * be legal final states will be returned.
310: * @param info An object that contains the required input data for the method,
311: * and which will contain the output information if successful.
312: *
313: * @return The value -1 if fully valid, else the 0 based index of the child
314: * that first failed before the insertion point. If the value
315: * returned is equal to the number of children, then the specified
316: * children are valid but additional content is required to reach a
317: * valid ending state.
318: *
319: * @see InsertableElementsInfo
320: */
321: public int whatCanGoHere(boolean fullyValid,
322: InsertableElementsInfo info) throws Exception {
323: //
324: // For this one, having the empty slot at the insertion point is
325: // a problem. So lets compress the array down. We know that it has
326: // to have at least the empty slot at the insertion point.
327: //
328: for (int index = info.insertAt; index < info.childCount - 1; index++)
329: info.curChildren[index] = info.curChildren[index + 1];
330: info.childCount--;
331:
332: //
333: // Check the validity of the existing contents. If this is less than
334: // the insert at point, then return failure index right now
335: //
336: final int failedIndex = validateContent(info.curChildren, 0,
337: info.childCount);
338: if ((failedIndex != -1) && (failedIndex < info.insertAt))
339: return failedIndex;
340:
341: //
342: // Set any stuff we can know right off the bat for all cases. Mixed
343: // models can always hold PCData. And, since its always a repetition
344: // of a bunch of choice nodes, its always valid EOC.
345: //
346: info.canHoldPCData = true;
347: info.isValidEOC = true;
348:
349: //
350: // Set the results count member and then see if we need to reallocate
351: // the outgoing arrays.
352: //
353: info.resultsCount = fCount;
354:
355: if ((info.results == null)
356: || (info.results.length < info.resultsCount))
357: info.results = new boolean[info.resultsCount];
358:
359: if ((info.possibleChildren == null)
360: || (info.possibleChildren.length < info.resultsCount)) {
361: info.possibleChildren = new QName[info.resultsCount];
362: for (int i = 0; i < info.possibleChildren.length; i++) {
363: info.possibleChildren[i] = new QName();
364: }
365: }
366:
367: //
368: // If the fully valid parameter is set, then whether any child can
369: // go here is dependent upon the content model having been valid all
370: // the way to the end. If its not, nothing we put here is going to
371: // make it happy. If it was ok, then nothing we put here is ever going
372: // make it bad.
373: //
374: // So set up a boolean that can be used to set every possible child's
375: // insertable status below.
376: //
377: boolean bStatus = true;
378: if (fullyValid && (failedIndex < info.childCount))
379: bStatus = false;
380:
381: //
382: // Fill in the possible children array, from our array. And set the
383: // boolean flag for each one to true because any of them can go
384: // anywhere.
385: //
386: for (int index = 0; index < fCount; index++) {
387: info.possibleChildren[index].setValues(fChildren[index]);
388: info.results[index] = bStatus;
389: }
390:
391: return -1;
392: }
393:
394: public ContentLeafNameTypeVector getContentLeafNameTypeVector() {
395: return null;
396: }
397:
398: } // class MixedContentModel
|