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 
  22 package com.sun.org.apache.xerces.internal.xpointer;
  23 
  24 import com.sun.org.apache.xerces.internal.impl.Constants;
  25 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  26 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  27 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  28 import com.sun.org.apache.xerces.internal.xni.QName;
  29 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  30 import com.sun.org.apache.xerces.internal.xni.XNIException;
  31 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  32 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  33 
  34 /**
  35  * <p>
  36  * Implements the XPointerPart interface and handles processing of
  37  * ShortHand Pointers.  It identifies at most one element in the
  38  * resource's information set; specifically, the first one (if any)
  39  * in document order that has a matching NCName as an identifier.
  40  * </p>
  41  *
  42  */
  43 final class ShortHandPointer implements XPointerPart {
  44 
  45     // The name of the ShortHand pointer
  46     private String fShortHandPointer;
  47 
  48     // The name of the ShortHand pointer
  49     private boolean fIsFragmentResolved = false;
  50 
  51     // SymbolTable
  52     private SymbolTable fSymbolTable;
  53 
  54     //
  55     // Constructors
  56     //
  57     public ShortHandPointer() {
  58     }
  59 
  60     public ShortHandPointer(SymbolTable symbolTable) {
  61         fSymbolTable = symbolTable;
  62     }
  63 
  64     /**
  65      * The XPointerProcessor takes care of this.  Simply set the ShortHand Pointer here.
  66      *
  67      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#parseXPointer(java.lang.String)
  68      */
  69     public void parseXPointer(String part) throws XNIException {
  70         fShortHandPointer = part;
  71         // reset fIsFragmentResolved
  72         fIsFragmentResolved = false;
  73     }
  74 
  75     /**
  76      * Resolves the XPointer ShortHand pointer based on the rules defined in
  77      * Section 3.2 of the XPointer Framework Recommendation.
  78      * Note that in the current implementation only supports DTD determined ID's.
  79      *
  80      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#resolveXPointer(com.sun.org.apache.xerces.internal.xni.QName, com.sun.org.apache.xerces.internal.xni.XMLAttributes, com.sun.org.apache.xerces.internal.xni.Augmentations, int event)
  81      */
  82     int fMatchingChildCount = 0;
  83     public boolean resolveXPointer(QName element, XMLAttributes attributes,
  84             Augmentations augs, int event) throws XNIException {
  85 
  86         // reset fIsFragmentResolved
  87         if (fMatchingChildCount == 0) {
  88             fIsFragmentResolved = false;
  89         }
  90 
  91         // On startElement or emptyElement, if no matching elements or parent
  92         // elements were found, check for a matching idenfitier.
  93         if (event == XPointerPart.EVENT_ELEMENT_START) {
  94             if (fMatchingChildCount == 0) {
  95                 fIsFragmentResolved = hasMatchingIdentifier(element, attributes, augs,
  96                     event);
  97             }
  98             if (fIsFragmentResolved) {
  99                fMatchingChildCount++;
 100             }
 101         } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) {
 102             if (fMatchingChildCount == 0) {
 103                 fIsFragmentResolved = hasMatchingIdentifier(element, attributes, augs,
 104                     event);
 105             }
 106         }
 107         else {
 108             // On endElement, decrease the matching child count if the child or
 109             // its parent was resolved.
 110             if (fIsFragmentResolved) {
 111                 fMatchingChildCount--;
 112             }
 113         }
 114 
 115         return fIsFragmentResolved ;
 116     }
 117 
 118     /**
 119      *
 120      * @param element
 121      * @param attributes
 122      * @param augs
 123      * @param event
 124      * @return
 125      * @throws XNIException
 126      */
 127     private boolean hasMatchingIdentifier(QName element,
 128             XMLAttributes attributes, Augmentations augs, int event)
 129     throws XNIException {
 130         String normalizedValue = null;
 131 
 132         // The identifiers of an element are determined by the
 133         // ShortHand Pointer as follows:
 134 
 135         if (attributes != null) {
 136             for (int i = 0; i < attributes.getLength(); i++) {
 137 
 138                 // 1. If an element information item has an attribute information item
 139                 // among its [attributes] that is a schema-determined ID, then it is
 140                 // identified by the value of that attribute information item's
 141                 // [schema normalized value] property;
 142                 normalizedValue = getSchemaDeterminedID(attributes, i);
 143                 if (normalizedValue != null) {
 144                     break;
 145                 }
 146 
 147                 // 2. If an element information item has an element information item among
 148                 // its [children] that is a schema-determined ID, then it is identified by
 149                 // the value of that element information item's [schema normalized value] property;
 150                 // ???
 151                 normalizedValue = getChildrenSchemaDeterminedID(attributes, i);
 152                 if (normalizedValue != null) {
 153                     break;
 154                 }
 155 
 156                 // 3. If an element information item has an attribute information item among
 157                 // its [attributes] that is a DTD-determined ID, then it is identified by the
 158                 // value of that attribute information item's [normalized value] property.
 159                 // An attribute information item is a DTD-determined ID if and only if it has
 160                 // a [type definition] property whose value is equal to ID.
 161                 normalizedValue = getDTDDeterminedID(attributes, i);
 162                 if (normalizedValue != null) {
 163                     break;
 164                 }
 165                 // 4. No externally determined ID's
 166             }
 167         }
 168 
 169         if (normalizedValue != null
 170                 && normalizedValue.equals(fShortHandPointer)) {
 171             return true;
 172         }
 173 
 174         return false;
 175     }
 176 
 177     /**
 178      * Rerturns the DTD determine-ID
 179      *
 180      * @param attributes
 181      * @param index
 182      * @return String
 183      * @throws XNIException
 184      */
 185     public String getDTDDeterminedID(XMLAttributes attributes, int index)
 186     throws XNIException {
 187 
 188         if (attributes.getType(index).equals("ID")) {
 189             return attributes.getValue(index);
 190         }
 191         return null;
 192     }
 193 
 194     /**
 195      * Returns the schema-determined-ID.
 196      *
 197      *
 198      * @param attributes
 199      * @param index
 200      * @return A String containing the schema-determined ID.
 201      * @throws XNIException
 202      */
 203     public String getSchemaDeterminedID(XMLAttributes attributes, int index)
 204     throws XNIException {
 205         Augmentations augs = attributes.getAugmentations(index);
 206         AttributePSVI attrPSVI = (AttributePSVI) augs
 207         .getItem(Constants.ATTRIBUTE_PSVI);
 208 
 209         if (attrPSVI != null) {
 210             // An element or attribute information item is a schema-determined
 211             // ID if and only if one of the following is true:]
 212 
 213             // 1. It has a [member type definition] or [type definition] property
 214             // whose value in turn has [name] equal to ID and [target namespace]
 215             // equal to http://www.w3.org/2001/XMLSchema;
 216 
 217             // 2. It has a [base type definition] whose value has that [name] and [target namespace];
 218 
 219             // 3. It has a [base type definition] whose value has a [base type definition]
 220             // whose value has that [name] and [target namespace], and so on following
 221             // the [base type definition] property recursively;
 222 
 223             XSTypeDefinition typeDef = attrPSVI.getMemberTypeDefinition();
 224             if (typeDef != null) {
 225                 typeDef = attrPSVI.getTypeDefinition();
 226             }
 227 
 228             //
 229             if (typeDef != null && ((XSSimpleType) typeDef).isIDType()) {
 230                 return attrPSVI.getSchemaNormalizedValue();
 231             }
 232 
 233             // 4 & 5 NA
 234         }
 235 
 236         return null;
 237     }
 238 
 239     /**
 240      * Not quite sure how this can be correctly implemented.
 241      *
 242      * @param attributes
 243      * @param index
 244      * @return String - We return null since we currenly do not supprt this.
 245      * @throws XNIException
 246      */
 247     public String getChildrenSchemaDeterminedID(XMLAttributes attributes,
 248             int index) throws XNIException {
 249         return null;
 250     }
 251 
 252     /**
 253      *
 254      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#isFragmentResolved()
 255      */
 256     public boolean isFragmentResolved() {
 257         return fIsFragmentResolved;
 258     }
 259 
 260     /**
 261      *
 262      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#isChildFragmentResolved()
 263      */
 264     public boolean isChildFragmentResolved() {
 265         return fIsFragmentResolved && ( fMatchingChildCount >  0);
 266     }
 267 
 268     /**
 269      * Returns the name of the ShortHand pointer
 270      *
 271      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeName()
 272      */
 273     public String getSchemeName() {
 274         return fShortHandPointer;
 275     }
 276 
 277     /**
 278      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeData()
 279      */
 280     public String getSchemeData() {
 281         return null;
 282     }
 283 
 284     /**
 285      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeName(java.lang.String)
 286      */
 287     public void setSchemeName(String schemeName) {
 288         fShortHandPointer = schemeName;
 289     }
 290 
 291     /**
 292      * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeData(java.lang.String)
 293      */
 294     public void setSchemeData(String schemeData) {
 295         // NA
 296     }
 297 }