1/* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5/* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22package com.sun.org.apache.xerces.internal.impl.xs.identity; 23 24import com.sun.org.apache.xerces.internal.impl.xpath.XPathException; 25import com.sun.org.apache.xerces.internal.impl.xs.util.ShortListImpl; 26import com.sun.org.apache.xerces.internal.util.SymbolTable; 27import com.sun.org.apache.xerces.internal.util.XMLChar; 28import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 29import com.sun.org.apache.xerces.internal.xs.ShortList; 30import com.sun.org.apache.xerces.internal.xs.XSComplexTypeDefinition; 31import com.sun.org.apache.xerces.internal.xs.XSConstants; 32import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition; 33 34/** 35 * Schema identity constraint field. 36 * 37 * @xerces.internal 38 * 39 * @author Andy Clark, IBM 40 */ 41public class Field { 42 43 // 44 // Data 45 // 46 47 /** Field XPath. */ 48 protected final Field.XPath fXPath; 49 50 51 /** Identity constraint. */ 52 protected final IdentityConstraint fIdentityConstraint; 53 54 // 55 // Constructors 56 // 57 58 /** Constructs a field. */ 59 public Field(Field.XPath xpath, 60 IdentityConstraint identityConstraint) { 61 fXPath = xpath; 62 fIdentityConstraint = identityConstraint; 63 } // <init>(Field.XPath,IdentityConstraint) 64 65 // 66 // Public methods 67 // 68 69 /** Returns the field XPath. */ 70 public com.sun.org.apache.xerces.internal.impl.xpath.XPath getXPath() { 71 return fXPath; 72 } // getXPath():org.apache.xerces.impl.v1.schema.identity.XPath 73 74 /** Returns the identity constraint. */ 75 public IdentityConstraint getIdentityConstraint() { 76 return fIdentityConstraint; 77 } // getIdentityConstraint():IdentityConstraint 78 79 // factory method 80 81 /** Creates a field matcher. */ 82 public XPathMatcher createMatcher(ValueStore store) { 83 return new Field.Matcher(fXPath, store); 84 } // createMatcher(ValueStore):XPathMatcher 85 86 // 87 // Object methods 88 // 89 90 /** Returns a string representation of this object. */ 91 public String toString() { 92 return fXPath.toString(); 93 } // toString():String 94 95 // 96 // Classes 97 // 98 99 /** 100 * Field XPath. 101 * 102 * @author Andy Clark, IBM 103 */ 104 public static class XPath 105 extends com.sun.org.apache.xerces.internal.impl.xpath.XPath { 106 107 // 108 // Constructors 109 // 110 111 /** Constructs a field XPath expression. */ 112 public XPath(String xpath, 113 SymbolTable symbolTable, 114 NamespaceContext context) throws XPathException { 115 super(fixupXPath(xpath), symbolTable, context); 116 117 // verify that only one attribute is selected per branch 118 for (int i=0;i<fLocationPaths.length;i++) { 119 for(int j=0; j<fLocationPaths[i].steps.length; j++) { 120 com.sun.org.apache.xerces.internal.impl.xpath.XPath.Axis axis = 121 fLocationPaths[i].steps[j].axis; 122 if (axis.type == XPath.Axis.ATTRIBUTE && 123 (j < fLocationPaths[i].steps.length-1)) { 124 throw new XPathException("c-fields-xpaths"); 125 } 126 } 127 } 128 } // <init>(String,SymbolTable,NamespacesContext) 129 130 /** Fixup XPath expression. Avoid creating a new String if possible. */ 131 private static String fixupXPath(String xpath) { 132 133 final int end = xpath.length(); 134 int offset = 0; 135 boolean whitespace = true; 136 char c; 137 138 // NOTE: We have to prefix the field XPath with "./" in 139 // order to handle selectors such as "@attr" that 140 // select the attribute because the fields could be 141 // relative to the selector element. -Ac 142 // Unless xpath starts with a descendant node -Achille Fokoue 143 // ... or a / or a . - NG 144 for (; offset < end; ++offset) { 145 c = xpath.charAt(offset); 146 if (whitespace) { 147 if (!XMLChar.isSpace(c)) { 148 if (c == '.' || c == '/') { 149 whitespace = false; 150 } 151 else if (c != '|') { 152 return fixupXPath2(xpath, offset, end); 153 } 154 } 155 } 156 else if (c == '|') { 157 whitespace = true; 158 } 159 } 160 return xpath; 161 162 } // fixupXPath(String):String 163 164 private static String fixupXPath2(String xpath, int offset, final int end) { 165 166 StringBuffer buffer = new StringBuffer(end + 2); 167 for (int i = 0; i < offset; ++i) { 168 buffer.append(xpath.charAt(i)); 169 } 170 buffer.append("./"); 171 172 boolean whitespace = false; 173 char c; 174 175 for (; offset < end; ++offset) { 176 c = xpath.charAt(offset); 177 if (whitespace) { 178 if (!XMLChar.isSpace(c)) { 179 if (c == '.' || c == '/') { 180 whitespace = false; 181 } 182 else if (c != '|') { 183 buffer.append("./"); 184 whitespace = false; 185 } 186 } 187 } 188 else if (c == '|') { 189 whitespace = true; 190 } 191 buffer.append(c); 192 } 193 return buffer.toString(); 194 195 } // fixupXPath2(String, int, int):String 196 197 } // class XPath 198 199 /** 200 * Field matcher. 201 * 202 * @author Andy Clark, IBM 203 */ 204 protected class Matcher 205 extends XPathMatcher { 206 207 // 208 // Data 209 // 210 211 /** Value store for data values. */ 212 protected final ValueStore fStore; 213 214 /** A flag indicating whether the field is allowed to match a value. */ 215 protected boolean fMayMatch = true; 216 217 // 218 // Constructors 219 // 220 221 /** Constructs a field matcher. */ 222 public Matcher(Field.XPath xpath, ValueStore store) { 223 super(xpath); 224 fStore = store; 225 } // <init>(Field.XPath,ValueStore) 226 227 // 228 // XPathHandler methods 229 // 230 231 /** 232 * This method is called when the XPath handler matches the 233 * XPath expression. 234 */ 235 protected void matched(Object actualValue, short valueType, ShortList itemValueType, boolean isNil) { 236 super.matched(actualValue, valueType, itemValueType, isNil); 237 if(isNil && (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY)) { 238 String code = "KeyMatchesNillable"; 239 fStore.reportError(code, 240 new Object[]{fIdentityConstraint.getElementName(), fIdentityConstraint.getIdentityConstraintName()}); 241 } 242 fStore.addValue(Field.this, fMayMatch, actualValue, convertToPrimitiveKind(valueType), convertToPrimitiveKind(itemValueType)); 243 // once we've stored the value for this field, we set the mayMatch 244 // member to false so that in the same scope, we don't match any more 245 // values (and throw an error instead). 246 fMayMatch = false; 247 } // matched(String) 248 249 private short convertToPrimitiveKind(short valueType) { 250 /** Primitive datatypes. */ 251 if (valueType <= XSConstants.NOTATION_DT) { 252 return valueType; 253 } 254 /** Types derived from string. */ 255 if (valueType <= XSConstants.ENTITY_DT) { 256 return XSConstants.STRING_DT; 257 } 258 /** Types derived from decimal. */ 259 if (valueType <= XSConstants.POSITIVEINTEGER_DT) { 260 return XSConstants.DECIMAL_DT; 261 } 262 /** Other types. */ 263 return valueType; 264 } 265 266 private ShortList convertToPrimitiveKind(ShortList itemValueType) { 267 if (itemValueType != null) { 268 int i; 269 final int length = itemValueType.getLength(); 270 for (i = 0; i < length; ++i) { 271 short type = itemValueType.item(i); 272 if (type != convertToPrimitiveKind(type)) { 273 break; 274 } 275 } 276 if (i != length) { 277 final short [] arr = new short[length]; 278 for (int j = 0; j < i; ++j) { 279 arr[j] = itemValueType.item(j); 280 } 281 for(; i < length; ++i) { 282 arr[i] = convertToPrimitiveKind(itemValueType.item(i)); 283 } 284 return new ShortListImpl(arr, arr.length); 285 } 286 } 287 return itemValueType; 288 } 289 290 protected void handleContent(XSTypeDefinition type, boolean nillable, Object actualValue, short valueType, ShortList itemValueType) { 291 if (type == null || 292 type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE && 293 ((XSComplexTypeDefinition) type).getContentType() 294 != XSComplexTypeDefinition.CONTENTTYPE_SIMPLE) { 295 296 // the content must be simpleType content 297 fStore.reportError( "cvc-id.3", new Object[] { 298 fIdentityConstraint.getName(), 299 fIdentityConstraint.getElementName()}); 300 301 } 302 fMatchedString = actualValue; 303 matched(fMatchedString, valueType, itemValueType, nillable); 304 } // handleContent(XSElementDecl, String) 305 306 } // class Matcher 307 308} // class Field 309