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