mrglavas    2003/10/10 11:25:40

  Modified:    java/src/org/apache/xerces/util XMLAttributesImpl.java
               java/src/org/apache/xerces/impl/dtd XMLNSDTDValidator.java
                        XML11NSDTDValidator.java
               java/src/org/apache/xerces/impl
                        XML11NSDocumentScannerImpl.java
                        XMLNSDocumentScannerImpl.java
                        XMLNamespaceBinder.java
  Log:
  Improved processing of attribute lists both small and large
  in many ways. Take advantage of the SymbolTable and
  always use reference comparison when checking names.
  
  Revision  Changes    Path
  1.21      +438 -55   
xml-xerces/java/src/org/apache/xerces/util/XMLAttributesImpl.java
  
  Index: XMLAttributesImpl.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/util/XMLAttributesImpl.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- XMLAttributesImpl.java    8 May 2003 20:12:00 -0000       1.20
  +++ XMLAttributesImpl.java    10 Oct 2003 18:25:40 -0000      1.21
  @@ -76,6 +76,7 @@
    *
    * @author Andy Clark, IBM 
    * @author Elena Litani, IBM
  + * @author Michael Glavassevich, IBM
    *
    * @version $Id$
    */
  @@ -83,6 +84,19 @@
       implements XMLAttributes {
   
       //
  +    // Constants
  +    //
  +    
  +    /** Default table size. */
  +    protected static final int TABLE_SIZE = 101;
  +    
  +    /** 
  +     * Threshold at which an instance is treated
  +     * as a large attribute list.
  +     */
  +    protected static final int SIZE_LIMIT = 20;
  +    
  +    //
       // Data
       //
   
  @@ -93,18 +107,42 @@
   
       // data
   
  +    /** 
  +     * Usage count for the attribute table view. 
  +     * Incremented each time all attributes are removed
  +     * when the attribute table view is in use.
  +     */
  +    protected int fLargeCount = 1;
  +    
       /** Attribute count. */
       protected int fLength;
   
       /** Attribute information. */
       protected Attribute[] fAttributes = new Attribute[4];
  -
  -    /** Augmentations information for each attribute 
  -        number of augmentations is equal to the number of attributes
  -    */
  -    // XMLAttributes has no knowledge if any augmentations
  -    //          we attached to Augmentations.
  -    protected Augmentations[] fAugmentations = new AugmentationsImpl[4];
  +    
  +    /** 
  +     * Hashtable of attribute information. 
  +     * Provides an alternate view of the attribute specification. 
  +     */
  +    protected Attribute[] fAttributeTableView;
  +    
  +    /**
  +     * Tracks whether each chain in the hash table is stale
  +     * with respect to the current state of this object.
  +     * A chain is stale if its state is not the same as the number
  +     * of times the attribute table view has been used.
  +     */
  +    protected int[] fAttributeTableViewChainState;
  +    
  +    /**
  +     * Actual number of buckets in the table view.
  +     */
  +    protected int fTableViewBuckets;
  +    
  +    /**
  +     * Indicates whether the table view contains consistent data.
  +     */
  +    protected boolean fIsTableViewConsistent;
   
       //
       // Constructors
  @@ -112,9 +150,16 @@
   
       /** Default constructor. */
       public XMLAttributesImpl() {
  +        this(TABLE_SIZE);
  +    }
  +    
  +    /**
  +     * @param tableSize initial size of table view
  +     */
  +    public XMLAttributesImpl(int tableSize) {
  +        fTableViewBuckets = tableSize;
           for (int i = 0; i < fAttributes.length; i++) {
               fAttributes[i] = new Attribute();
  -            fAugmentations[i] = new AugmentationsImpl();
           }
       } // <init>()
   
  @@ -150,8 +195,8 @@
        * exists, the old values for the attribute are replaced by the new
        * values.
        * 
  -     * @param attrName  The attribute name.
  -     * @param attrType  The attribute type. The type name is determined by
  +     * @param name  The attribute name.
  +     * @param type  The attribute type. The type name is determined by
        *                  the type specified for this attribute in the DTD.
        *                  For example: "CDATA", "ID", "NMTOKEN", etc. However,
        *                  attributes of type enumeration will have the type
  @@ -159,7 +204,7 @@
        *                  the enumeration values prefixed by an open 
        *                  parenthesis and suffixed by a close parenthesis.
        *                  For example: "(true|false)".
  -     * @param attrValue The attribute value.
  +     * @param value The attribute value.
        * 
        * @return Returns the attribute index.
        *
  @@ -168,29 +213,95 @@
        */
       public int addAttribute(QName name, String type, String value) {
   
  -        // find attribute; create, if necessary
  -        int index = name.uri != null && !name.uri.equals("")
  -                  ? getIndex(name.uri, name.localpart)
  -                  : getIndex(name.rawname);
  -        if (index == -1) {
  -            index = fLength;
  -            if (fLength++ == fAttributes.length) {
  -                Attribute[] attributes = new Attribute[fAttributes.length + 4];
  -                Augmentations[] augs = new AugmentationsImpl[fAttributes.length +4];
  -                System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
  -                System.arraycopy(fAugmentations, 0, augs, 0, fAttributes.length);
  -                for (int i = fAttributes.length; i < attributes.length; i++) {
  -                    attributes[i] = new Attribute();
  -                    augs[i] = new AugmentationsImpl();
  +        int index;
  +        if (fLength < SIZE_LIMIT) {
  +            index = name.uri != null && !name.uri.equals("") 
  +                ? getIndexFast(name.uri, name.localpart)
  +                : getIndexFast(name.rawname);
  +
  +            if (index == -1) {
  +                index = fLength;
  +                if (fLength++ == fAttributes.length) {
  +                    Attribute[] attributes = new Attribute[fAttributes.length + 4];
  +                    System.arraycopy(fAttributes, 0, attributes, 0, 
fAttributes.length);
  +                    for (int i = fAttributes.length; i < attributes.length; i++) {
  +                        attributes[i] = new Attribute();
  +                    }
  +                    fAttributes = attributes;
                   }
  -                fAttributes = attributes;
  -                fAugmentations = augs;
               }
           }
  +        else if (name.uri == null || 
  +            name.uri.length() == 0 || 
  +            (index = getIndexFast(name.uri, name.localpart)) == -1) {
  +            
  +            /**
  +             * If attributes were removed from the list after the table
  +             * becomes in use this isn't reflected in the table view. It's
  +             * assumed that once a user starts removing attributes they're 
  +             * not likely to add more. We only make the view consistent if
  +             * the user of this class adds attributes, removes them, and
  +             * then adds more.
  +             */
  +            if (!fIsTableViewConsistent || fLength == SIZE_LIMIT) {
  +                prepareAndPopulateTableView();
  +                fIsTableViewConsistent = true;
  +            }
   
  -        // clear augmentations
  -        fAugmentations[index].removeAllItems();
  -
  +            int bucket = getTableViewBucket(name.rawname); 
  +             
  +            // The chain is stale. 
  +            // This must be a unique attribute.
  +            if (fAttributeTableViewChainState[bucket] != fLargeCount) {
  +                index = fLength;
  +                if (fLength++ == fAttributes.length) {
  +                    Attribute[] attributes = new Attribute[fAttributes.length << 1];
  +                    System.arraycopy(fAttributes, 0, attributes, 0, 
fAttributes.length);
  +                    for (int i = fAttributes.length; i < attributes.length; i++) {
  +                        attributes[i] = new Attribute();
  +                    }
  +                    fAttributes = attributes;
  +                }
  +                     
  +                // Update table view.
  +                fAttributeTableViewChainState[bucket] = fLargeCount;
  +                fAttributes[index].next = null;
  +                fAttributeTableView[bucket] = fAttributes[index];
  +            }
  +            // This chain is active. 
  +            // We need to check if any of the attributes has the same rawname.
  +            else {
  +                // Search the table.
  +                Attribute found = fAttributeTableView[bucket];
  +                while (found != null) {
  +                    if (found.name.rawname == name.rawname) {
  +                        break;
  +                    }
  +                    found = found.next;
  +                }
  +                // This attribute is unique.
  +                if (found == null) {
  +                    index = fLength;
  +                    if (fLength++ == fAttributes.length) {
  +                        Attribute[] attributes = new Attribute[fAttributes.length 
<< 1];
  +                        System.arraycopy(fAttributes, 0, attributes, 0, 
fAttributes.length);
  +                        for (int i = fAttributes.length; i < attributes.length; 
i++) {
  +                            attributes[i] = new Attribute();
  +                        }
  +                        fAttributes = attributes;
  +                    }
  +                
  +                    // Update table view
  +                    fAttributes[index].next = fAttributeTableView[bucket];
  +                    fAttributeTableView[bucket] = fAttributes[index];
  +                }
  +                // Duplicate. We still need to find the index.
  +                else {
  +                    index = getIndexFast(name.rawname);
  +                }
  +            }
  +        }          
  +        
           // set values
           Attribute attribute = fAttributes[index];
           attribute.name.setValues(name);
  @@ -198,8 +309,10 @@
           attribute.value = value;
           attribute.nonNormalizedValue = value;
           attribute.specified = false;
  +            
  +        // clear augmentations
  +        attribute.augs.removeAllItems();
   
  -        // return
           return index;
   
       } // addAttribute(QName,String,XMLString)
  @@ -221,20 +334,14 @@
        * @param attrIndex The attribute index.
        */
       public void removeAttributeAt(int attrIndex) {
  +        fIsTableViewConsistent = false;
           if (attrIndex < fLength - 1) {
               Attribute removedAttr = fAttributes[attrIndex];
  -            Augmentations removedAug = fAugmentations[attrIndex];
               System.arraycopy(fAttributes, attrIndex + 1,
  -                             fAttributes, attrIndex, fLength - attrIndex - 1);
  -
  -            System.arraycopy(fAugmentations, attrIndex + 1,
  -                 fAugmentations, attrIndex, fLength - attrIndex - 1);
  -
  +                fAttributes, attrIndex, fLength - attrIndex - 1);
               // Make the discarded Attribute object available for re-use
               // by tucking it after the Attributes that are still in use
               fAttributes[fLength-1] = removedAttr;
  -
  -            fAugmentations[fLength-1] = removedAug;
           }
           fLength--;
       } // removeAttributeAt(int)
  @@ -379,11 +486,7 @@
           if (index < 0 || index >= fLength) {
               return null;
           }
  -        String type = fAttributes[index].type;
  -        if(type.indexOf('(') == 0 && type.lastIndexOf(')') == type.length()-1) {
  -            return "NMTOKEN";
  -        }
  -        return type;
  +        return getReportableType(fAttributes[index].type);
       } // getType(int):String
   
       /**
  @@ -399,7 +502,7 @@
        */
       public String getType(String qname) {
           int index = getIndex(qname);
  -        return index != -1 ? getType(index): null;
  +        return index != -1 ? getReportableType(fAttributes[index].type) : null;
       } // getType(String):String
   
       /**
  @@ -564,7 +667,7 @@
               return null;
           }
           int index = getIndex(uri, localName);
  -        return index != -1 ? getType(index) : null;
  +        return index != -1 ? getReportableType(fAttributes[index].type) : null;
       } // getType(String,String):String
   
       /**
  @@ -622,8 +725,7 @@
        */
       public Augmentations getAugmentations (String uri, String localName) {
           int index = getIndex(uri, localName);
  -
  -        return index != -1 ? fAugmentations[index] : null;
  +        return index != -1 ? fAttributes[index].augs : null;
       }
   
       /**
  @@ -637,11 +739,9 @@
        */
       public Augmentations getAugmentations(String qName){
           int index = getIndex(qName);
  -        return index != -1 ? fAugmentations[index] : null;
  +        return index != -1 ? fAttributes[index].augs : null;
       }
   
  -
  -
       /**
        * Look up an augmentations by attributes index.
        * 
  @@ -652,7 +752,7 @@
           if (attributeIndex < 0 || attributeIndex >= fLength) {
               return null;
           }
  -        return fAugmentations[attributeIndex];
  +        return fAttributes[attributeIndex].augs;
       }
   
       /**
  @@ -662,7 +762,7 @@
        * @param augs      The augmentations.
        */
       public void setAugmentations(int attrIndex, Augmentations augs) {
  -        fAugmentations[attrIndex] = augs;
  +        fAttributes[attrIndex].augs = augs;
       }
   
       /**
  @@ -687,7 +787,7 @@
       }
       public boolean getSchemaId(String qname) {
           int index = getIndex(qname);
  -        return index != -1 ? fAttributes[index].schemaId : false;
  +        return index != -1 ? fAttributes[index].schemaId : false; 
       } // getType(String):String
       public boolean getSchemaId(String uri, String localName) {
           if (!fNamespaces) {
  @@ -696,6 +796,277 @@
           int index = getIndex(uri, localName);
           return index != -1 ? fAttributes[index].schemaId : false;
       } // getType(String,String):String
  +    
  +    /**
  +     * Look up the index of an attribute by XML 1.0 qualified name.
  +     * <p>
  +     * <strong>Note:</strong> 
  +     * This method uses reference comparison, and thus should
  +     * only be used internally. We cannot use this method in any
  +     * code exposed to users as they may not pass in unique strings.
  +     *
  +     * @param qName The qualified (prefixed) name.
  +     * @return The index of the attribute, or -1 if it does not
  +     *         appear in the list.
  +     */
  +    public int getIndexFast(String qName) {
  +        for (int i = 0; i < fLength; ++i) {
  +            Attribute attribute = fAttributes[i];
  +            if (attribute.name.rawname == qName) {
  +                return i;
  +            }
  +        }
  +        return -1;
  +    } // getIndexFast(String):int
  +    
  +    /**
  +     * Adds an attribute. The attribute's non-normalized value of the
  +     * attribute will have the same value as the attribute value until
  +     * set using the <code>setNonNormalizedValue</code> method. Also,
  +     * the added attribute will be marked as specified in the XML instance
  +     * document unless set otherwise using the <code>setSpecified</code>
  +     * method.
  +     * <p>
  +     * This method differs from <code>addAttribute</code> in that it
  +     * does not check if an attribute of the same name already exists
  +     * in the list before adding it. In order to improve performance
  +     * of namespace processing, this method allows uniqueness checks
  +     * to be deferred until all the namespace information is available
  +     * after the entire attribute specification has been read.
  +     * <p>
  +     * <strong>Caution:</strong> If this method is called it should
  +     * not be mixed with calls to <code>addAttribute</code> unless
  +     * it has been determined that all the attribute names are unique.
  +     * 
  +     * @param name the attribute name
  +     * @param type the attribute type
  +     * @param value the attribute value
  +     * 
  +     * @see #setNonNormalizedValue
  +     * @see #setSpecified
  +     * @see #checkDuplicatesNS
  +     */
  +    public void addAttributeNS(QName name, String type, String value) {
  +        int index = fLength;
  +        if (fLength++ == fAttributes.length) {
  +            Attribute[] attributes;
  +            if (fLength < SIZE_LIMIT) {
  +                attributes = new Attribute[fAttributes.length + 4];
  +            }
  +            else {
  +                attributes = new Attribute[fAttributes.length << 1];
  +            }
  +            System.arraycopy(fAttributes, 0, attributes, 0, fAttributes.length);
  +            for (int i = fAttributes.length; i < attributes.length; i++) {
  +                attributes[i] = new Attribute();
  +            }
  +            fAttributes = attributes;
  +        }
  +        
  +        // set values
  +        Attribute attribute = fAttributes[index];
  +        attribute.name.setValues(name);
  +        attribute.type = type;
  +        attribute.value = value;
  +        attribute.nonNormalizedValue = value;
  +        attribute.specified = false;
  +            
  +        // clear augmentations
  +        attribute.augs.removeAllItems();
  +    }
  +    
  +    /**
  +     * Checks for duplicate expanded names (local part and namespace name
  +     * pairs) in the attribute specification. If a duplicate is found its
  +     * name is returned.
  +     * <p>
  +     * This should be called once all the in-scope namespaces for the element
  +     * enclosing these attributes is known, and after all the attributes
  +     * have gone through namespace binding.
  +     * 
  +     * @return the name of a duplicate attribute found in the search,
  +     * otherwise null.
  +     */
  +    public QName checkDuplicatesNS() {
  +        // If the list is small check for duplicates using pairwise comparison.
  +        if (fLength <= SIZE_LIMIT) {
  +            for (int i = 0; i < fLength - 1; ++i) {
  +             Attribute att1 = fAttributes[i];
  +                for (int j = i + 1; j < fLength; ++j) {
  +                    Attribute att2 = fAttributes[j];
  +                    if (att1.name.localpart == att2.name.localpart &&
  +                        att1.name.uri == att2.name.uri) {
  +                        return att2.name;            
  +                    }
  +                }
  +            }
  +     }
  +     // If the list is large check duplicates using a hash table.
  +     else {
  +            // We don't want this table view to be read if someone calls 
  +            // addAttribute so we invalidate it up front.
  +            fIsTableViewConsistent = false;
  +
  +            prepareTableView();
  +
  +            Attribute attr;
  +            int bucket;
  +
  +            for (int i = fLength - 1; i >= 0; --i) {
  +                attr = fAttributes[i];
  +                bucket = getTableViewBucket(attr.name.localpart, attr.name.uri);
  +                
  +                // The chain is stale. 
  +                // This must be a unique attribute.
  +                if (fAttributeTableViewChainState[bucket] != fLargeCount) {
  +                    fAttributeTableViewChainState[bucket] = fLargeCount;
  +                    attr.next = null;
  +                    fAttributeTableView[bucket] = attr;
  +                } 
  +                // This chain is active. 
  +                // We need to check if any of the attributes has the same name.
  +                else {
  +                    // Search the table.
  +                    Attribute found = fAttributeTableView[bucket];
  +                    while (found != null) {
  +                        if (found.name.localpart == attr.name.localpart &&
  +                            found.name.uri == attr.name.uri) {
  +                            return attr.name;
  +                        }
  +                        found = found.next;
  +                    }
  +                    
  +                    // Update table view
  +                    attr.next = fAttributeTableView[bucket];
  +                    fAttributeTableView[bucket] = attr;
  +                }
  +            }
  +     }
  +     return null;
  +    }
  +    
  +    /**
  +     * Look up the index of an attribute by Namespace name.
  +     * <p>
  +     * <strong>Note:</strong> 
  +     * This method uses reference comparison, and thus should
  +     * only be used internally. We cannot use this method in any
  +     * code exposed to users as they may not pass in unique strings.
  +     *
  +     * @param uri The Namespace URI, or null if
  +     *        the name has no Namespace URI.
  +     * @param localName The attribute's local name.
  +     * @return The index of the attribute, or -1 if it does not
  +     *         appear in the list.
  +     */
  +    public int getIndexFast(String uri, String localPart) {
  +        for (int i = 0; i < fLength; ++i) {
  +            Attribute attribute = fAttributes[i];
  +            if (attribute.name.localpart == localPart && 
  +                attribute.name.uri == uri) {
  +                return i;
  +            }
  +        }
  +        return -1;
  +    } // getIndexFast(String,String):int
  +
  +    /**
  +     * Returns the value passed in or NMTOKEN if it's an enumerated type.
  +     * 
  +     * @param type attribute type
  +     * @return the value passed in or NMTOKEN if it's an enumerated type.
  +     */
  +    protected String getReportableType(String type) {
  +        if (type.indexOf('(') == 0 && type.lastIndexOf(')') == type.length()-1) {
  +            return "NMTOKEN";
  +        }
  +        return type;
  +    }
  +     
  +    /**
  +     * Returns the position in the table view 
  +     * where the given attribute name would be hashed.
  +     * 
  +     * @param qname the attribute name
  +     * @return the position in the table view where the given attribute
  +     * would be hashed
  +     */
  +    protected int getTableViewBucket(String qname) {
  +        return (qname.hashCode() & 0x7FFFFFFF) % fTableViewBuckets;
  +    }
  +    
  +    /**
  +     * Returns the position in the table view
  +     * where the given attribute name would be hashed.
  +     * 
  +     * @param localpart the local part of the attribute
  +     * @param uri the namespace name of the attribute
  +     * @return the position in the table view where the given attribute
  +     * would be hashed
  +     */
  +    protected int getTableViewBucket(String localpart, String uri) {
  +        if (uri == null) {
  +            return (localpart.hashCode() & 0x7FFFFFFF) % fTableViewBuckets;
  +        }
  +        else {
  +            return ((localpart.hashCode() + uri.hashCode()) 
  +               & 0x7FFFFFFF) % fTableViewBuckets;
  +        }
  +    }
  +     
  +    /**
  +     * Purges all elements from the table view.
  +     */
  +    protected void cleanTableView() {
  +        if (++fLargeCount < 0) {
  +            // Overflow. We actually need to visit the chain state array.
  +            if (fAttributeTableViewChainState != null) {
  +                for (int i = fTableViewBuckets - 1; i >= 0; --i) {
  +                    fAttributeTableViewChainState[i] = 0;
  +                } 
  +            }
  +            fLargeCount = 1;
  +        }
  +    }
  +    
  +    /**
  +     * Prepares the table view of the attributes list for use.
  +     */
  +    protected void prepareTableView() {
  +        if (fAttributeTableView == null) {
  +            fAttributeTableView = new Attribute[fTableViewBuckets];
  +            fAttributeTableViewChainState = new int[fTableViewBuckets];
  +        }
  +        else {
  +            cleanTableView();
  +        }
  +    }
  +    
  +    /**
  +     * Prepares the table view of the attributes list for use,
  +     * and populates it with the attributes which have been
  +     * previously read.
  +     */
  +    protected void prepareAndPopulateTableView() {
  +        prepareTableView();
  +        // Need to populate the hash table with the attributes we've scanned so far.
  +        Attribute attr;
  +        int bucket;
  +        for (int i = 0; i < fLength; ++i) {
  +            attr = fAttributes[i];
  +            bucket = getTableViewBucket(attr.name.rawname);
  +            if (fAttributeTableViewChainState[bucket] != fLargeCount) {
  +                fAttributeTableViewChainState[bucket] = fLargeCount;
  +                attr.next = null;
  +                fAttributeTableView[bucket] = attr;
  +            } 
  +            else {
  +                // Update table view
  +                attr.next = fAttributeTableView[bucket];
  +                fAttributeTableView[bucket] = attr;
  +            }
  +        }
  +    }
   
       //
       // Classes
  @@ -731,6 +1102,18 @@
   
           /** Schema ID type. */
           public boolean schemaId;
  +        
  +        /** 
  +         * Augmentations information for this attribute.
  +         * XMLAttributes has no knowledge if any augmentations
  +         * were attached to Augmentations.
  +         */
  +        public Augmentations augs = new AugmentationsImpl();
  +        
  +        // Additional data for attribute table view
  +        
  +        /** Pointer to the next attribute in the chain. **/
  +        public Attribute next;
           
       } // class Attribute
   
  
  
  
  1.7       +5 -2      
xml-xerces/java/src/org/apache/xerces/impl/dtd/XMLNSDTDValidator.java
  
  Index: XMLNSDTDValidator.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/dtd/XMLNSDTDValidator.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- XMLNSDTDValidator.java    29 May 2003 13:25:42 -0000      1.6
  +++ XMLNSDTDValidator.java    10 Oct 2003 18:25:40 -0000      1.7
  @@ -222,8 +222,11 @@
           // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
           int attrCount = attributes.getLength();
           for (int i = 0; i < attrCount - 1; i++) {
  -            String alocalpart = attributes.getLocalName(i);
               String auri = attributes.getURI(i);
  +            if (auri == null || auri == NamespaceContext.XMLNS_URI) {
  +                continue;
  +            }
  +            String alocalpart = attributes.getLocalName(i);
               for (int j = i + 1; j < attrCount; j++) {
                   String blocalpart = attributes.getLocalName(j);
                   String buri = attributes.getURI(j);
  
  
  
  1.2       +5 -2      
xml-xerces/java/src/org/apache/xerces/impl/dtd/XML11NSDTDValidator.java
  
  Index: XML11NSDTDValidator.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/dtd/XML11NSDTDValidator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- XML11NSDTDValidator.java  2 Oct 2003 18:18:15 -0000       1.1
  +++ XML11NSDTDValidator.java  10 Oct 2003 18:25:40 -0000      1.2
  @@ -215,8 +215,11 @@
           // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
           int attrCount = attributes.getLength();
           for (int i = 0; i < attrCount - 1; i++) {
  -            String alocalpart = attributes.getLocalName(i);
               String auri = attributes.getURI(i);
  +            if (auri == null || auri == NamespaceContext.XMLNS_URI) {
  +                continue;
  +            }
  +            String alocalpart = attributes.getLocalName(i);
               for (int j = i + 1; j < attrCount; j++) {
                   String blocalpart = attributes.getLocalName(j);
                   String buri = attributes.getURI(j);
  
  
  
  1.3       +43 -49    
xml-xerces/java/src/org/apache/xerces/impl/XML11NSDocumentScannerImpl.java
  
  Index: XML11NSDocumentScannerImpl.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/XML11NSDocumentScannerImpl.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- XML11NSDocumentScannerImpl.java   2 Oct 2003 18:24:15 -0000       1.2
  +++ XML11NSDocumentScannerImpl.java   10 Oct 2003 18:25:40 -0000      1.3
  @@ -116,10 +116,6 @@
        */
       protected boolean fPerformValidation;
   
  -    protected String[] fUri = new String[4];
  -    protected String[] fLocalpart = new String[4];
  -    protected int fLength = 0;
  -
       // private data
       //
   
  @@ -257,7 +253,6 @@
   
               // bind attributes (xmlns are already bound bellow)
               int length = fAttributes.getLength();
  -            fLength = 0; //initialize structure
               for (int i = 0; i < length; i++) {
                   fAttributes.getName(i, fAttributeQName);
   
  @@ -270,7 +265,6 @@
                   //
                   if (fAttributeQName.uri != null
                       && fAttributeQName.uri == uri) {
  -                    checkDuplicates(fAttributeQName, fAttributes);
                       continue;
                   }
                   if (aprefix != XMLSymbols.EMPTY_STRING) {
  @@ -286,7 +280,30 @@
                               XMLErrorReporter.SEVERITY_FATAL_ERROR);
                       }
                       fAttributes.setURI(i, uri);
  -                    checkDuplicates(fAttributeQName, fAttributes);
  +                }
  +            }
  +
  +            if (length > 1) {
  +                QName name = fAttributes.checkDuplicatesNS();
  +                if (name != null) {
  +                    if (name.uri != null) {
  +                        fErrorReporter.reportError(
  +                            XMLMessageFormatter.XMLNS_DOMAIN,
  +                            "AttributeNSNotUnique",
  +                            new Object[] {
  +                                fElementQName.rawname,
  +                                name.localpart,
  +                                name.uri },
  +                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
  +                    } else {
  +                        fErrorReporter.reportError(
  +                            XMLMessageFormatter.XMLNS_DOMAIN,
  +                            "AttributeNotUnique",
  +                            new Object[] {
  +                                fElementQName.rawname,
  +                                name.rawname },
  +                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
  +                    }
                   }
               }
           }
  @@ -323,40 +340,6 @@
   
       } // scanStartElement():boolean
   
  -    private final void checkDuplicates(
  -        QName qname,
  -        XMLAttributesImpl attributes) {
  -
  -        // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
  -        // search if such attribute already exists
  -        for (int i = 0; i < fLength; i++) {
  -            if (qname.uri == fUri[i]
  -                && fLocalpart[i].equals(qname.localpart)) {
  -                fErrorReporter.reportError(
  -                    XMLMessageFormatter.XMLNS_DOMAIN,
  -                    "AttributeNSNotUnique",
  -                    new Object[] {
  -                        fElementQName.rawname,
  -                        qname.rawname,
  -                        qname.uri },
  -                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
  -            }
  -        }
  -        int index = fLength;
  -        if (fLength++ == fUri.length) {
  -            String[] uris = new String[fUri.length + 4];
  -            String[] lps = new String[fUri.length + 4];
  -            System.arraycopy(fUri, 0, uris, 0, fUri.length);
  -            System.arraycopy(fLocalpart, 0, lps, 0, fLocalpart.length);
  -            fUri = uris;
  -            fLocalpart = lps;
  -
  -        }
  -
  -        fUri[index] = qname.uri;
  -        fLocalpart[index] = qname.localpart;
  -    }
  -
       /**
       * Scans an attribute.
       * <p>
  @@ -395,15 +378,26 @@
   
           // content
           int oldLen = attributes.getLength();
  -        attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
   
  -        // WFC: Unique Att Spec
  -        if (oldLen == attributes.getLength()) {
  -            reportFatalError(
  -                "AttributeNotUnique",
  -                new Object[] {
  -                    fCurrentElement.rawname,
  -                    fAttributeQName.rawname });
  +        if (fBindNamespaces) {
  +            attributes.addAttributeNS(
  +                fAttributeQName,
  +                XMLSymbols.fCDATASymbol,
  +                null);
  +        } else {
  +            attributes.addAttribute(
  +                fAttributeQName,
  +                XMLSymbols.fCDATASymbol,
  +                null);
  +
  +            // WFC: Unique Att Spec
  +            if (oldLen == attributes.getLength()) {
  +                reportFatalError(
  +                    "AttributeNotUnique",
  +                    new Object[] {
  +                        fCurrentElement.rawname,
  +                        fAttributeQName.rawname });
  +            }
           }
   
           //REVISIT: one more case needs to be included: external PE and standalone 
is no
  
  
  
  1.17      +40 -16    
xml-xerces/java/src/org/apache/xerces/impl/XMLNSDocumentScannerImpl.java
  
  Index: XMLNSDocumentScannerImpl.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/XMLNSDocumentScannerImpl.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- XMLNSDocumentScannerImpl.java     2 Sep 2003 07:06:14 -0000       1.16
  +++ XMLNSDocumentScannerImpl.java     10 Oct 2003 18:25:40 -0000      1.17
  @@ -112,9 +112,9 @@
         *   scanner if DTD grammar is missing.*/
       protected boolean fPerformValidation;
   
  -    protected String[] fUri= new String[4];
  -    protected String[] fLocalpart = new String[4];
  -    protected int fLength = 0;
  +    // protected String[] fUri= new String[4];
  +    // protected String[] fLocalpart = new String[4];
  +    // protected int fLength = 0;
   
   
       // private data
  @@ -248,7 +248,7 @@
   
               // bind attributes (xmlns are already bound bellow)
               int length = fAttributes.getLength();
  -            fLength = 0; //initialize structure
  +            // fLength = 0; //initialize structure
               for (int i = 0; i < length; i++) {
                   fAttributes.getName(i, fAttributeQName);
   
  @@ -258,7 +258,7 @@
                   // REVISIT: try removing the first "if" and see if it is faster.
                   //
                   if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
  -                    checkDuplicates(fAttributeQName, fAttributes);
  +                    // checkDuplicates(fAttributeQName, fAttributes);
                       continue;
                   }
                   if (aprefix != XMLSymbols.EMPTY_STRING) {
  @@ -270,7 +270,25 @@
                                                      
XMLErrorReporter.SEVERITY_FATAL_ERROR);
                       }
                       fAttributes.setURI(i, uri);
  -                    checkDuplicates(fAttributeQName, fAttributes);
  +                    // checkDuplicates(fAttributeQName, fAttributes);
  +                }
  +            }
  +            
  +            if (length > 1) {
  +                QName name = fAttributes.checkDuplicatesNS();
  +                if (name != null) {
  +                    if (name.uri != null) {
  +                        fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  +                                                   "AttributeNSNotUnique",
  +                                                   new 
Object[]{fElementQName.rawname, name.localpart, name.uri},
  +                                                   
XMLErrorReporter.SEVERITY_FATAL_ERROR);
  +                    }
  +                    else {
  +                        fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  +                                                   "AttributeNotUnique",
  +                                                   new 
Object[]{fElementQName.rawname, name.rawname}, 
  +                                                   
XMLErrorReporter.SEVERITY_FATAL_ERROR);
  +                    }
                   }
               }
           }
  @@ -306,7 +324,7 @@
   
       } // scanStartElement():boolean
   
  -    private final void checkDuplicates(QName qname, XMLAttributesImpl attributes){
  +    /** private final void checkDuplicates(QName qname, XMLAttributesImpl 
attributes){
   
           // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
           // search if such attribute already exists
  @@ -331,7 +349,7 @@
   
           fUri[index] = qname.uri;
           fLocalpart[index] = qname.localpart;
  -    }
  +    } **/
   
   
   
  @@ -370,13 +388,19 @@
   
           // content
           int oldLen = attributes.getLength();
  -        attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
  -
  -        // WFC: Unique Att Spec
  -        if (oldLen == attributes.getLength()) {
  -            reportFatalError("AttributeNotUnique",
  -                             new Object[]{fCurrentElement.rawname,
  +        
  +        if (fBindNamespaces) {
  +            attributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, 
null);
  +        }
  +        else {
  +            attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
  +             
  +            // WFC: Unique Att Spec
  +            if (oldLen == attributes.getLength()) {
  +                reportFatalError("AttributeNotUnique",
  +                                 new Object[]{fCurrentElement.rawname,
                                    fAttributeQName.rawname});
  +            }
           }
   
           //REVISIT: one more case needs to be included: external PE and standalone 
is no
  @@ -393,7 +417,7 @@
   
           // record namespace declarations if any.
           if (fBindNamespaces) {
  -
  +            
               String localpart = fAttributeQName.localpart;
               String prefix = fAttributeQName.prefix != null
                               ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
  
  
  
  1.30      +5 -2      
xml-xerces/java/src/org/apache/xerces/impl/XMLNamespaceBinder.java
  
  Index: XMLNamespaceBinder.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/XMLNamespaceBinder.java,v
  retrieving revision 1.29
  retrieving revision 1.30
  diff -u -r1.29 -r1.30
  --- XMLNamespaceBinder.java   29 May 2003 13:25:41 -0000      1.29
  +++ XMLNamespaceBinder.java   10 Oct 2003 18:25:40 -0000      1.30
  @@ -824,8 +824,11 @@
           // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
           int attrCount = attributes.getLength();
           for (int i = 0; i < attrCount - 1; i++) {
  -            String alocalpart = attributes.getLocalName(i);
               String auri = attributes.getURI(i);
  +            if (auri == null || auri == NamespaceContext.XMLNS_URI) {
  +                continue;
  +            }
  +            String alocalpart = attributes.getLocalName(i);
               for (int j = i + 1; j < attrCount; j++) {
                   String blocalpart = attributes.getLocalName(j);
                   String buri = attributes.getURI(j);
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to