Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.7.1
    • Fix Version/s: None
    • Component/s: XInclude 1.0
    • Labels:
    • Environment:
      All

      Description

      Hi,

      The XInclude ID support should handle xml:id. This is useful for instance with DocBook or TEI that use Relax NG schemas for validation and also need XInclude support.
      Here it is a patch that adds support for handling xml:id attributes as attributes of ID type.

      Index: C:/george/workspace/xerces/src/org/apache/xerces/xpointer/ShortHandPointer.java
      ===================================================================
      — C:/george/workspace/xerces/src/org/apache/xerces/xpointer/ShortHandPointer.java (revision 344362)
      +++ C:/george/workspace/xerces/src/org/apache/xerces/xpointer/ShortHandPointer.java (working copy)
      @@ -162,6 +162,17 @@
      }
      }

      + if (normalizedValue == null && attributes != null) {
      + // Try to see if we can get an xml:id
      + for (int i = 0; i < attributes.getLength(); i++) {
      + if ("xml".equals(attributes.getPrefix) &&
      + "id".equals(attributes.getLocalName))

      { + normalizedValue = attributes.getValue(i); + break; + }

      + }
      + }
      +
      if (normalizedValue != null
      && normalizedValue.equals(fShortHandPointer)) {
      return true;

      Best Regards,
      George

      1. XmlIDhandler(v1.0).zip
        28 kB
        Ishara Karunarathna
      2. xmlIDHandler.zip
        21 kB
        Ishara Karunarathna

        Activity

        George Cristian Bina created issue -
        Hide
        Michael Glavassevich added a comment -

        [[Recording a comment I sent in an e-mail back in December]]

        I see how the patch gets the job done for some cases though I'm not sure whether a conforming XInclude processor should be doing this by default. That aside, since it isn't performing the processing steps required by the xml:id spec [1] you can't really call this support for xml:id and in general it will miss values because they haven't been fully normalized.

        xml:id processing is logically a separate processing layer from XInclude, schema validation, etc... I understand the usefulness of xml:id in an XInclude context but this attribute has broader usage. When Xerces eventually does support xml:id I feel it should be independent of the other components in the pipeline.

        [1] http://www.w3.org/TR/xml-id/#processing

        Show
        Michael Glavassevich added a comment - [ [Recording a comment I sent in an e-mail back in December] ] I see how the patch gets the job done for some cases though I'm not sure whether a conforming XInclude processor should be doing this by default. That aside, since it isn't performing the processing steps required by the xml:id spec [1] you can't really call this support for xml:id and in general it will miss values because they haven't been fully normalized. xml:id processing is logically a separate processing layer from XInclude, schema validation, etc... I understand the usefulness of xml:id in an XInclude context but this attribute has broader usage. When Xerces eventually does support xml:id I feel it should be independent of the other components in the pipeline. [1] http://www.w3.org/TR/xml-id/#processing
        Mark Thomas made changes -
        Field Original Value New Value
        Workflow jira [ 12343760 ] Default workflow, editable Closed status [ 12575365 ]
        Mark Thomas made changes -
        Workflow Default workflow, editable Closed status [ 12575365 ] jira [ 12598145 ]
        Michael Glavassevich made changes -
        Labels gsoc2011
        Hide
        Michael Glavassevich added a comment -

        See recent discussion [1] on the Xerces-J development mailing list.

        [1] http://xerces.markmail.org/thread/2rjlgj3flqptxvll

        Show
        Michael Glavassevich added a comment - See recent discussion [1] on the Xerces-J development mailing list. [1] http://xerces.markmail.org/thread/2rjlgj3flqptxvll
        Michael Glavassevich made changes -
        Summary Support for xml:id [GSoC]: Support for xml:id
        Hide
        Michael Glavassevich added a comment -

        Requirements for the XNI component. It needs to:

        1) Normalize the value of each xml:id attribute.
        2) Perform ID type assignment with the normalized value (in other words give it an ID type if it doesn't already have one).
        3) Report an error if the constraints on the xml:id are violated (in other words validate the xml:id).
        4) Pass the processed xml:id attribute (and other XNI events) to the next component in the pipeline.

        Show
        Michael Glavassevich added a comment - Requirements for the XNI component. It needs to: 1) Normalize the value of each xml:id attribute. 2) Perform ID type assignment with the normalized value (in other words give it an ID type if it doesn't already have one). 3) Report an error if the constraints on the xml:id are violated (in other words validate the xml:id). 4) Pass the processed xml:id attribute (and other XNI events) to the next component in the pipeline.
        Hide
        Ishara Karunarathna added a comment -

        Hi Michael and Devs,

        Here I have posted the latest implemented code for xml:id parser component. And I want to know suggestions and comments on my approach.

        package org.apache.xerces.xmlID;

        import org.apache.xerces.impl.Constants;
        import org.apache.xerces.impl.XMLErrorReporter;
        import org.apache.xerces.impl.dtd.XMLAttributeDecl;
        import org.apache.xerces.impl.dtd.XMLSimpleType;
        import org.apache.xerces.impl.dv.DTDDVFactory;
        import org.apache.xerces.impl.dv.DatatypeValidator;
        import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
        import org.apache.xerces.impl.dv.dtd.IDDatatypeValidator;
        import org.apache.xerces.impl.msg.XMLMessageFormatter;
        import org.apache.xerces.impl.validation.ValidationManager;
        import org.apache.xerces.impl.validation.ValidationState;
        import org.apache.xerces.util.SymbolTable;
        import org.apache.xerces.util.XMLSymbols;
        import org.apache.xerces.xni.QName;
        import org.apache.xerces.xni.XMLAttributes;
        import org.apache.xerces.xni.Augmentations;
        import org.apache.xerces.xni.NamespaceContext;
        import org.apache.xerces.xni.XMLDocumentHandler;
        import org.apache.xerces.xni.XMLLocator;
        import org.apache.xerces.xni.XMLResourceIdentifier;
        import org.apache.xerces.xni.XMLString;
        import org.apache.xerces.xni.XNIException;
        import org.apache.xerces.xni.grammars.XMLGrammarPool;
        import org.apache.xerces.xni.parser.XMLComponent;
        import org.apache.xerces.xni.parser.XMLComponentManager;
        import org.apache.xerces.xni.parser.XMLConfigurationException;
        import org.apache.xerces.xni.parser.XMLDocumentFilter;
        import org.apache.xerces.xni.parser.XMLDocumentSource;

        public class XmlIDHandler implements XMLDocumentFilter, XMLComponent {

        // property identifier: ValidationManager
        protected static final String VALIDATION_MANAGER =
        Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;

        // updated during reset
        protected ValidationManager fValidationManager = null;

        // features

        /** Namespaces. */
        protected boolean fNamespaces;

        /** Validation. */
        protected boolean fValidation;

        /** Validation against only DTD */
        protected boolean fDTDValidation;

        // XML document version
        private String version = "0";

        /** Datatype validator: ID. */
        //protected DatatypeValidator fValID;
        protected IDDatatypeValidator fValID = new IDDatatypeValidator();

        // validation state
        protected final ValidationState fValidationState = new ValidationState();

        /** Error reporter. */
        protected XMLErrorReporter fErrorReporter;

        /** Temporary string buffers. */
        private final StringBuffer fBuffer = new StringBuffer();

        /** Temporary atribute declaration. */
        private final XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl();

        // handlers

        /** Document handler. */
        protected XMLDocumentHandler fDocumentHandler;

        protected XMLDocumentSource fDocumentSource;

        /** Current element index. */
        private int fCurrentElementIndex = -1;

        /** Datatype validator factory. */
        protected DTDDVFactory fDatatypeValidatorFactory;

        @Override
        public void characters(XMLString text, Augmentations augs)
        throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.characters(text, augs); }

        }

        @Override
        public void comment(XMLString text, Augmentations augs) throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.comment(text, augs); }

        }

        @Override
        public void doctypeDecl(String rootElement, String publicId, String systemId,
        Augmentations augs) throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); }

        }

        @Override
        public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
        throws XNIException {

        if (fDocumentHandler !=null)

        { fDocumentHandler.emptyElement(element, attributes, augs); }

        }

        @Override
        public void endCDATA(Augmentations augs) throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.endCDATA(augs); }

        }

        @Override
        public void endDocument(Augmentations augs) throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.endDocument(augs); }

        }

        @Override
        public void endElement(QName element, Augmentations augs) throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.endElement(element,augs); }

        }

        @Override
        public void endGeneralEntity(String name, Augmentations augs)
        throws XNIException {
        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.endGeneralEntity(name, augs); }

        }

        @Override
        public XMLDocumentSource getDocumentSource()

        { return fDocumentSource; }

        @Override
        public void ignorableWhitespace(XMLString text, Augmentations augs)
        throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.ignorableWhitespace(text, augs); }

        }

        @Override
        public void processingInstruction(String target, XMLString data,
        Augmentations augs) throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.processingInstruction(target, data, augs); }

        }

        @Override
        public void setDocumentSource(XMLDocumentSource source)

        { fDocumentSource = source; }

        @Override
        public void startCDATA(Augmentations augs) throws XNIException {

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.startCDATA(augs); }

        }

        @Override
        public void startDocument(XMLLocator locator, String encoding,
        NamespaceContext namespaceContext, Augmentations augs) throws XNIException {

        if (fDocumentHandler != null)

        { fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); }

        }

        public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
        throws XNIException {
        System.out.println("xmlid handler");
        if (version.equals("1.1")){
        if (attributes.getIndex("xml:id") == 0)

        { fCurrentElementIndex = attributes.getIndex("xml:id"); addXmlIDAttrsAndValidate(element, fCurrentElementIndex, attributes); }

        }

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.startElement(element, attributes, augs); }

        }

        @Override
        public void startGeneralEntity(String name, XMLResourceIdentifier identifier,
        String encoding, Augmentations augs) throws XNIException {

        if (fDocumentHandler != null)

        { fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); }

        }

        @Override
        public void textDecl(String version, String encoding, Augmentations augs)
        throws XNIException {
        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.textDecl(version, encoding, augs); }

        }

        public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
        throws XNIException {

        if (version.equals("1.1"))

        { setVersion(version); }

        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.xmlDecl(version, encoding, standalone, augs); }

        } // xmlDecl(String,String,String)

        private void setVersion(String version)

        { this.version = version; }

        @Override
        public XMLDocumentHandler getDocumentHandler()

        { return fDocumentHandler; }

        @Override
        public void setDocumentHandler(XMLDocumentHandler documentHandler)

        { fDocumentHandler = documentHandler; }

        /** Add xml:ids and validate. */
        protected void addXmlIDAttrsAndValidate(QName elementName, int elementIndex,
        XMLAttributes attributes) {

        int attrCount = attributes.getLength();
        for (int i = 0; i < attrCount; i++) {
        String attrRawName = attributes.getQName;

        boolean changedByNormalization = false;
        String oldValue = attributes.getValue;
        String attrValue = oldValue;
        changedByNormalization = normalizeAttrValue(attributes, i);
        attrValue = attributes.getValue;

        // if ( fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID )
        if ( true )

        { //c fTempAttDecl is not define validateXmlIDAttribute(elementName, attrValue, fTempAttDecl); }

        }

        }

        private void validateXmlIDAttribute(QName element, String attValue,
        XMLAttributeDecl attributeDecl) throws XNIException {
        configure();
        try

        { fValID.validate(attValue, fValidationState); }

        catch (InvalidDatatypeValueException ex)

        { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex.getArgs(), XMLErrorReporter.SEVERITY_ERROR ); }

        }

        private void configure() {

        try

        { //REVISIT: datatypeRegistry + initialization of datatype // why do we cast to ListDatatypeValidator? //fDatatypeValidatorFactory = (DTDDVFactory)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY); //fValID = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDSymbol); }

        catch (Exception e)

        { // should never happen e.printStackTrace(System.err); }

        }

        private boolean normalizeAttrValue(XMLAttributes attributes, int index) {

        // vars
        boolean leadingSpace = true;
        boolean spaceStart = false;
        boolean readingNonSpace = false;
        int count = 0;
        int eaten = 0;
        String attrValue = attributes.getValue(index);
        System.out.println(attrValue);
        char[] attValue = new char[attrValue.length()];

        fBuffer.setLength(0);
        attrValue.getChars(0, attrValue.length(), attValue, 0);
        for (int i = 0; i < attValue.length; i++) {

        if (attValue[i] == ' ') {

        // now the tricky part
        if (readingNonSpace)

        { spaceStart = true; readingNonSpace = false; }

        if (spaceStart && !leadingSpace)

        { spaceStart = false; fBuffer.append(attValue[i]); count++; }

        else {
        if (leadingSpace || !spaceStart) {
        eaten ++;
        /*** BUG #3512 ***
        int entityCount = attributes.getEntityCount(index);
        for (int j = 0; j < entityCount; j++) {
        int offset = attributes.getEntityOffset(index, j);
        int length = attributes.getEntityLength(index, j);
        if (offset <= i-eaten+1) {
        if (offset+length >= i-eaten+1)

        { if (length > 0) length--; }

        }
        else

        { if (offset > 0) offset--; }

        attributes.setEntityOffset(index, j, offset);
        attributes.setEntityLength(index, j, length);
        }
        /***/
        }
        }

        }
        else

        { readingNonSpace = true; spaceStart = false; leadingSpace = false; fBuffer.append(attValue[i]); count++; }

        }

        // check if the last appended character is a space.
        if (count > 0 && fBuffer.charAt(count-1) == ' ') {
        fBuffer.setLength(count-1);
        /*** BUG #3512 ***
        int entityCount = attributes.getEntityCount(index);
        for (int j=0; j < entityCount; j++) {
        int offset = attributes.getEntityOffset(index, j);
        int length = attributes.getEntityLength(index, j);
        if (offset < count-1) {
        if (offset+length == count)

        { length--; }

        }
        else

        { offset--; }

        attributes.setEntityOffset(index, j, offset);
        attributes.setEntityLength(index, j, length);
        }
        /***/
        }
        String newValue = fBuffer.toString();
        attributes.setValue(index, newValue);
        return ! attrValue.equals(newValue);
        }

        @Override
        public Boolean getFeatureDefault(String featureId)

        { // TODO Auto-generated method stub return null; }

        @Override
        public Object getPropertyDefault(String propertyId) { // TODO Auto-generated method stub return null; }

        @Override
        public String[] getRecognizedFeatures()

        { // TODO Auto-generated method stub return null; }

        @Override
        public String[] getRecognizedProperties() { // TODO Auto-generated method stub return null; }

        @Override
        public void reset(XMLComponentManager componentManager)
        throws XMLConfigurationException

        { fCurrentElementIndex = -1; fValidationState.resetIDTables(); fValidationManager= (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER); fValidationManager.addValidationState(fValidationState); fValidationState.setUsingNamespaces(fNamespaces); // get needed components fErrorReporter = (XMLErrorReporter)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.ERROR_REPORTER_PROPERTY); }

        @Override
        public void setFeature(String featureId, boolean state)
        throws XMLConfigurationException

        { // TODO Auto-generated method stub }

        @Override
        public void setProperty(String propertyId, Object value)
        throws XMLConfigurationException { // TODO Auto-generated method stub }

        }

        Show
        Ishara Karunarathna added a comment - Hi Michael and Devs, Here I have posted the latest implemented code for xml:id parser component. And I want to know suggestions and comments on my approach. package org.apache.xerces.xmlID; import org.apache.xerces.impl.Constants; import org.apache.xerces.impl.XMLErrorReporter; import org.apache.xerces.impl.dtd.XMLAttributeDecl; import org.apache.xerces.impl.dtd.XMLSimpleType; import org.apache.xerces.impl.dv.DTDDVFactory; import org.apache.xerces.impl.dv.DatatypeValidator; import org.apache.xerces.impl.dv.InvalidDatatypeValueException; import org.apache.xerces.impl.dv.dtd.IDDatatypeValidator; import org.apache.xerces.impl.msg.XMLMessageFormatter; import org.apache.xerces.impl.validation.ValidationManager; import org.apache.xerces.impl.validation.ValidationState; import org.apache.xerces.util.SymbolTable; import org.apache.xerces.util.XMLSymbols; import org.apache.xerces.xni.QName; import org.apache.xerces.xni.XMLAttributes; import org.apache.xerces.xni.Augmentations; import org.apache.xerces.xni.NamespaceContext; import org.apache.xerces.xni.XMLDocumentHandler; import org.apache.xerces.xni.XMLLocator; import org.apache.xerces.xni.XMLResourceIdentifier; import org.apache.xerces.xni.XMLString; import org.apache.xerces.xni.XNIException; import org.apache.xerces.xni.grammars.XMLGrammarPool; import org.apache.xerces.xni.parser.XMLComponent; import org.apache.xerces.xni.parser.XMLComponentManager; import org.apache.xerces.xni.parser.XMLConfigurationException; import org.apache.xerces.xni.parser.XMLDocumentFilter; import org.apache.xerces.xni.parser.XMLDocumentSource; public class XmlIDHandler implements XMLDocumentFilter, XMLComponent { // property identifier: ValidationManager protected static final String VALIDATION_MANAGER = Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; // updated during reset protected ValidationManager fValidationManager = null; // features /** Namespaces. */ protected boolean fNamespaces; /** Validation. */ protected boolean fValidation; /** Validation against only DTD */ protected boolean fDTDValidation; // XML document version private String version = "0"; /** Datatype validator: ID. */ //protected DatatypeValidator fValID; protected IDDatatypeValidator fValID = new IDDatatypeValidator(); // validation state protected final ValidationState fValidationState = new ValidationState(); /** Error reporter. */ protected XMLErrorReporter fErrorReporter; /** Temporary string buffers. */ private final StringBuffer fBuffer = new StringBuffer(); /** Temporary atribute declaration. */ private final XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl(); // handlers /** Document handler. */ protected XMLDocumentHandler fDocumentHandler; protected XMLDocumentSource fDocumentSource; /** Current element index. */ private int fCurrentElementIndex = -1; /** Datatype validator factory. */ protected DTDDVFactory fDatatypeValidatorFactory; @Override public void characters(XMLString text, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.characters(text, augs); } } @Override public void comment(XMLString text, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.comment(text, augs); } } @Override public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); } } @Override public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { if (fDocumentHandler !=null) { fDocumentHandler.emptyElement(element, attributes, augs); } } @Override public void endCDATA(Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.endCDATA(augs); } } @Override public void endDocument(Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.endDocument(augs); } } @Override public void endElement(QName element, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.endElement(element,augs); } } @Override public void endGeneralEntity(String name, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.endGeneralEntity(name, augs); } } @Override public XMLDocumentSource getDocumentSource() { return fDocumentSource; } @Override public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.ignorableWhitespace(text, augs); } } @Override public void processingInstruction(String target, XMLString data, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.processingInstruction(target, data, augs); } } @Override public void setDocumentSource(XMLDocumentSource source) { fDocumentSource = source; } @Override public void startCDATA(Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.startCDATA(augs); } } @Override public void startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException { if (fDocumentHandler != null) { fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); } } public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { System.out.println("xmlid handler"); if (version.equals("1.1")){ if (attributes.getIndex("xml:id") == 0) { fCurrentElementIndex = attributes.getIndex("xml:id"); addXmlIDAttrsAndValidate(element, fCurrentElementIndex, attributes); } } // call handlers if (fDocumentHandler != null) { fDocumentHandler.startElement(element, attributes, augs); } } @Override public void startGeneralEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs) throws XNIException { if (fDocumentHandler != null) { fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); } } @Override public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { // call handlers if (fDocumentHandler != null) { fDocumentHandler.textDecl(version, encoding, augs); } } public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException { if (version.equals("1.1")) { setVersion(version); } // call handlers if (fDocumentHandler != null) { fDocumentHandler.xmlDecl(version, encoding, standalone, augs); } } // xmlDecl(String,String,String) private void setVersion(String version) { this.version = version; } @Override public XMLDocumentHandler getDocumentHandler() { return fDocumentHandler; } @Override public void setDocumentHandler(XMLDocumentHandler documentHandler) { fDocumentHandler = documentHandler; } /** Add xml:ids and validate. */ protected void addXmlIDAttrsAndValidate(QName elementName, int elementIndex, XMLAttributes attributes) { int attrCount = attributes.getLength(); for (int i = 0; i < attrCount; i++) { String attrRawName = attributes.getQName ; boolean changedByNormalization = false; String oldValue = attributes.getValue ; String attrValue = oldValue; changedByNormalization = normalizeAttrValue(attributes, i); attrValue = attributes.getValue ; // if ( fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID ) if ( true ) { //c fTempAttDecl is not define validateXmlIDAttribute(elementName, attrValue, fTempAttDecl); } } } private void validateXmlIDAttribute(QName element, String attValue, XMLAttributeDecl attributeDecl) throws XNIException { configure(); try { fValID.validate(attValue, fValidationState); } catch (InvalidDatatypeValueException ex) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex.getArgs(), XMLErrorReporter.SEVERITY_ERROR ); } } private void configure() { try { //REVISIT: datatypeRegistry + initialization of datatype // why do we cast to ListDatatypeValidator? //fDatatypeValidatorFactory = (DTDDVFactory)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY); //fValID = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDSymbol); } catch (Exception e) { // should never happen e.printStackTrace(System.err); } } private boolean normalizeAttrValue(XMLAttributes attributes, int index) { // vars boolean leadingSpace = true; boolean spaceStart = false; boolean readingNonSpace = false; int count = 0; int eaten = 0; String attrValue = attributes.getValue(index); System.out.println(attrValue); char[] attValue = new char [attrValue.length()] ; fBuffer.setLength(0); attrValue.getChars(0, attrValue.length(), attValue, 0); for (int i = 0; i < attValue.length; i++) { if (attValue [i] == ' ') { // now the tricky part if (readingNonSpace) { spaceStart = true; readingNonSpace = false; } if (spaceStart && !leadingSpace) { spaceStart = false; fBuffer.append(attValue[i]); count++; } else { if (leadingSpace || !spaceStart) { eaten ++; /*** BUG #3512 *** int entityCount = attributes.getEntityCount(index); for (int j = 0; j < entityCount; j++) { int offset = attributes.getEntityOffset(index, j); int length = attributes.getEntityLength(index, j); if (offset <= i-eaten+1) { if (offset+length >= i-eaten+1) { if (length > 0) length--; } } else { if (offset > 0) offset--; } attributes.setEntityOffset(index, j, offset); attributes.setEntityLength(index, j, length); } /***/ } } } else { readingNonSpace = true; spaceStart = false; leadingSpace = false; fBuffer.append(attValue[i]); count++; } } // check if the last appended character is a space. if (count > 0 && fBuffer.charAt(count-1) == ' ') { fBuffer.setLength(count-1); /*** BUG #3512 *** int entityCount = attributes.getEntityCount(index); for (int j=0; j < entityCount; j++) { int offset = attributes.getEntityOffset(index, j); int length = attributes.getEntityLength(index, j); if (offset < count-1) { if (offset+length == count) { length--; } } else { offset--; } attributes.setEntityOffset(index, j, offset); attributes.setEntityLength(index, j, length); } /***/ } String newValue = fBuffer.toString(); attributes.setValue(index, newValue); return ! attrValue.equals(newValue); } @Override public Boolean getFeatureDefault(String featureId) { // TODO Auto-generated method stub return null; } @Override public Object getPropertyDefault(String propertyId) { // TODO Auto-generated method stub return null; } @Override public String[] getRecognizedFeatures() { // TODO Auto-generated method stub return null; } @Override public String[] getRecognizedProperties() { // TODO Auto-generated method stub return null; } @Override public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { fCurrentElementIndex = -1; fValidationState.resetIDTables(); fValidationManager= (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER); fValidationManager.addValidationState(fValidationState); fValidationState.setUsingNamespaces(fNamespaces); // get needed components fErrorReporter = (XMLErrorReporter)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.ERROR_REPORTER_PROPERTY); } @Override public void setFeature(String featureId, boolean state) throws XMLConfigurationException { // TODO Auto-generated method stub } @Override public void setProperty(String propertyId, Object value) throws XMLConfigurationException { // TODO Auto-generated method stub } }
        Hide
        Ishara Karunarathna added a comment -

        HI Michael ,

        I modified xmlDecl(), and validateXmlIDAttribute() methods. And I modified configurePipeline() method in org.apache.xerces.parsers.XML11Configuration class to add xml:id handler component to pipe line, here I have posted those modified methods.

        org.apache.xerces.xmlID.XmlIDHandler

        public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
        throws XNIException {

        fIsXML11 = "1.1".equals(version);
        // call handlers
        if (fDocumentHandler != null)

        { fDocumentHandler.xmlDecl(version, encoding, standalone, augs); }

        } // xmlDecl(String,String,String)

        private void validateXmlIDAttribute(QName element, String attValue,
        XMLAttributeDecl attributeDecl) throws XNIException {
        configure();
        try {
        if(fIsXML11)

        { fValID11.validate(attValue, fValidationState); }

        else

        { fValID.validate(attValue, fValidationState); }

        }
        catch (InvalidDatatypeValueException ex)

        { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex.getArgs(), XMLErrorReporter.SEVERITY_ERROR ); }

        }
        ________________________________________________________________________________________________

        org.apache.xerces.parsers.XML11Configuration

        I added xml:id handler component after the XML Schema validator component.

        /** Configures the pipeline. */
        protected void configurePipeline() {
        if (fCurrentDVFactory != fDatatypeValidatorFactory)

        { fCurrentDVFactory = fDatatypeValidatorFactory; // use XML 1.0 datatype library setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); }

        // setup DTD pipeline
        if (fCurrentDTDScanner != fDTDScanner)

        { fCurrentDTDScanner = fDTDScanner; setProperty(DTD_SCANNER, fCurrentDTDScanner); setProperty(DTD_PROCESSOR, fDTDProcessor); }

        fDTDScanner.setDTDHandler(fDTDProcessor);
        fDTDProcessor.setDTDSource(fDTDScanner);
        fDTDProcessor.setDTDHandler(fDTDHandler);
        if (fDTDHandler != null)

        { fDTDHandler.setDTDSource(fDTDProcessor); }

        fDTDScanner.setDTDContentModelHandler(fDTDProcessor);
        fDTDProcessor.setDTDContentModelSource(fDTDScanner);
        fDTDProcessor.setDTDContentModelHandler(fDTDContentModelHandler);
        if (fDTDContentModelHandler != null)

        { fDTDContentModelHandler.setDTDContentModelSource(fDTDProcessor); }

        // setup document pipeline
        if (fFeatures.get(NAMESPACES) == Boolean.TRUE) {
        if (fCurrentScanner != fNamespaceScanner)

        { fCurrentScanner = fNamespaceScanner; setProperty(DOCUMENT_SCANNER, fNamespaceScanner); setProperty(DTD_VALIDATOR, fDTDValidator); }

        fNamespaceScanner.setDTDValidator(fDTDValidator);
        fNamespaceScanner.setDocumentHandler(fDTDValidator);
        fDTDValidator.setDocumentSource(fNamespaceScanner);
        fDTDValidator.setDocumentHandler(fDocumentHandler);
        if (fDocumentHandler != null)

        { fDocumentHandler.setDocumentSource(fDTDValidator); }

        fLastComponent = fDTDValidator;
        } else {
        // create components
        if (fNonNSScanner == null)

        { fNonNSScanner = new XMLDocumentScannerImpl(); fNonNSDTDValidator = new XMLDTDValidator(); // add components addComponent((XMLComponent) fNonNSScanner); addComponent((XMLComponent) fNonNSDTDValidator); }

        if (fCurrentScanner != fNonNSScanner)

        { fCurrentScanner = fNonNSScanner; setProperty(DOCUMENT_SCANNER, fNonNSScanner); setProperty(DTD_VALIDATOR, fNonNSDTDValidator); }

        fNonNSScanner.setDocumentHandler(fNonNSDTDValidator);
        fNonNSDTDValidator.setDocumentSource(fNonNSScanner);
        fNonNSDTDValidator.setDocumentHandler(fDocumentHandler);
        if (fDocumentHandler != null)

        { fDocumentHandler.setDocumentSource(fNonNSDTDValidator); }

        fLastComponent = fNonNSDTDValidator;
        }

        // add XML Schema validator if needed
        if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) {
        // If schema validator was not in the pipeline insert it.
        if (fSchemaValidator == null) {
        fSchemaValidator = new XMLSchemaValidator();
        // add schema component
        setProperty(SCHEMA_VALIDATOR, fSchemaValidator);
        addCommonComponent(fSchemaValidator);
        fSchemaValidator.reset(this);
        // add schema message formatter
        if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null)

        { XSMessageFormatter xmft = new XSMessageFormatter(); fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, xmft); }

        }
        fLastComponent.setDocumentHandler(fSchemaValidator);
        fSchemaValidator.setDocumentSource(fLastComponent);
        fSchemaValidator.setDocumentHandler(fDocumentHandler);
        if (fDocumentHandler != null)

        { fDocumentHandler.setDocumentSource(fSchemaValidator); }

        fLastComponent = fSchemaValidator;
        }

        // add XML xml:id Handler if needed
        if (fFeatures.get(XMLID_HANDLER) == Boolean.TRUE) {
        // If xml:id Handler was not in the pipeline insert it.
        if (fxmlIDHandler == null)

        { fxmlIDHandler = new XmlIDHandler(); // add xmlIDHandler component setProperty(XMLID_HANDLER, fxmlIDHandler); addCommonComponent(fxmlIDHandler); fxmlIDHandler.reset(this); }

        fLastComponent.setDocumentHandler(fxmlIDHandler);
        fxmlIDHandler.setDocumentSource(fLastComponent);
        fxmlIDHandler.setDocumentHandler(fDocumentHandler);
        if (fDocumentHandler != null)

        { fDocumentHandler.setDocumentSource(fxmlIDHandler); }

        fLastComponent = fxmlIDHandler;
        }
        } // configurePipeline()

        Show
        Ishara Karunarathna added a comment - HI Michael , I modified xmlDecl(), and validateXmlIDAttribute() methods. And I modified configurePipeline() method in org.apache.xerces.parsers.XML11Configuration class to add xml:id handler component to pipe line, here I have posted those modified methods. org.apache.xerces.xmlID.XmlIDHandler public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException { fIsXML11 = "1.1".equals(version); // call handlers if (fDocumentHandler != null) { fDocumentHandler.xmlDecl(version, encoding, standalone, augs); } } // xmlDecl(String,String,String) private void validateXmlIDAttribute(QName element, String attValue, XMLAttributeDecl attributeDecl) throws XNIException { configure(); try { if(fIsXML11) { fValID11.validate(attValue, fValidationState); } else { fValID.validate(attValue, fValidationState); } } catch (InvalidDatatypeValueException ex) { fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, ex.getKey(), ex.getArgs(), XMLErrorReporter.SEVERITY_ERROR ); } } ________________________________________________________________________________________________ org.apache.xerces.parsers.XML11Configuration I added xml:id handler component after the XML Schema validator component. /** Configures the pipeline. */ protected void configurePipeline() { if (fCurrentDVFactory != fDatatypeValidatorFactory) { fCurrentDVFactory = fDatatypeValidatorFactory; // use XML 1.0 datatype library setProperty(DATATYPE_VALIDATOR_FACTORY, fCurrentDVFactory); } // setup DTD pipeline if (fCurrentDTDScanner != fDTDScanner) { fCurrentDTDScanner = fDTDScanner; setProperty(DTD_SCANNER, fCurrentDTDScanner); setProperty(DTD_PROCESSOR, fDTDProcessor); } fDTDScanner.setDTDHandler(fDTDProcessor); fDTDProcessor.setDTDSource(fDTDScanner); fDTDProcessor.setDTDHandler(fDTDHandler); if (fDTDHandler != null) { fDTDHandler.setDTDSource(fDTDProcessor); } fDTDScanner.setDTDContentModelHandler(fDTDProcessor); fDTDProcessor.setDTDContentModelSource(fDTDScanner); fDTDProcessor.setDTDContentModelHandler(fDTDContentModelHandler); if (fDTDContentModelHandler != null) { fDTDContentModelHandler.setDTDContentModelSource(fDTDProcessor); } // setup document pipeline if (fFeatures.get(NAMESPACES) == Boolean.TRUE) { if (fCurrentScanner != fNamespaceScanner) { fCurrentScanner = fNamespaceScanner; setProperty(DOCUMENT_SCANNER, fNamespaceScanner); setProperty(DTD_VALIDATOR, fDTDValidator); } fNamespaceScanner.setDTDValidator(fDTDValidator); fNamespaceScanner.setDocumentHandler(fDTDValidator); fDTDValidator.setDocumentSource(fNamespaceScanner); fDTDValidator.setDocumentHandler(fDocumentHandler); if (fDocumentHandler != null) { fDocumentHandler.setDocumentSource(fDTDValidator); } fLastComponent = fDTDValidator; } else { // create components if (fNonNSScanner == null) { fNonNSScanner = new XMLDocumentScannerImpl(); fNonNSDTDValidator = new XMLDTDValidator(); // add components addComponent((XMLComponent) fNonNSScanner); addComponent((XMLComponent) fNonNSDTDValidator); } if (fCurrentScanner != fNonNSScanner) { fCurrentScanner = fNonNSScanner; setProperty(DOCUMENT_SCANNER, fNonNSScanner); setProperty(DTD_VALIDATOR, fNonNSDTDValidator); } fNonNSScanner.setDocumentHandler(fNonNSDTDValidator); fNonNSDTDValidator.setDocumentSource(fNonNSScanner); fNonNSDTDValidator.setDocumentHandler(fDocumentHandler); if (fDocumentHandler != null) { fDocumentHandler.setDocumentSource(fNonNSDTDValidator); } fLastComponent = fNonNSDTDValidator; } // add XML Schema validator if needed if (fFeatures.get(XMLSCHEMA_VALIDATION) == Boolean.TRUE) { // If schema validator was not in the pipeline insert it. if (fSchemaValidator == null) { fSchemaValidator = new XMLSchemaValidator(); // add schema component setProperty(SCHEMA_VALIDATOR, fSchemaValidator); addCommonComponent(fSchemaValidator); fSchemaValidator.reset(this); // add schema message formatter if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) { XSMessageFormatter xmft = new XSMessageFormatter(); fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, xmft); } } fLastComponent.setDocumentHandler(fSchemaValidator); fSchemaValidator.setDocumentSource(fLastComponent); fSchemaValidator.setDocumentHandler(fDocumentHandler); if (fDocumentHandler != null) { fDocumentHandler.setDocumentSource(fSchemaValidator); } fLastComponent = fSchemaValidator; } // add XML xml:id Handler if needed if (fFeatures.get(XMLID_HANDLER) == Boolean.TRUE) { // If xml:id Handler was not in the pipeline insert it. if (fxmlIDHandler == null) { fxmlIDHandler = new XmlIDHandler(); // add xmlIDHandler component setProperty(XMLID_HANDLER, fxmlIDHandler); addCommonComponent(fxmlIDHandler); fxmlIDHandler.reset(this); } fLastComponent.setDocumentHandler(fxmlIDHandler); fxmlIDHandler.setDocumentSource(fLastComponent); fxmlIDHandler.setDocumentHandler(fDocumentHandler); if (fDocumentHandler != null) { fDocumentHandler.setDocumentSource(fxmlIDHandler); } fLastComponent = fxmlIDHandler; } } // configurePipeline()
        Hide
        Michael Glavassevich added a comment -

        Hi Ishara,

        The changes you're proposing to XML11Configuration look correct, though in future it would be easier to review changes to existing files if you created a patch (e.g. diff -u). Generally also better to add source files as an attachment to the JIRA issue rather than including it directly as a comment.

        Guessing you may have changed XmlIDHandler since June 29th, but wanted to point out some things to improve in startElement(). Processing of xml:id should be done regardless of whether the XML version is XML 1.0 or 1.1. You only need to process that one attribute, so when you look up the index with attributes.getIndex("xml:id"), just use that index to get the attribute value. You don't need a loop and should not be normalizing the attributes which are not xml:id.

        Thanks.

        Show
        Michael Glavassevich added a comment - Hi Ishara, The changes you're proposing to XML11Configuration look correct, though in future it would be easier to review changes to existing files if you created a patch (e.g. diff -u). Generally also better to add source files as an attachment to the JIRA issue rather than including it directly as a comment. Guessing you may have changed XmlIDHandler since June 29th, but wanted to point out some things to improve in startElement(). Processing of xml:id should be done regardless of whether the XML version is XML 1.0 or 1.1. You only need to process that one attribute, so when you look up the index with attributes.getIndex("xml:id"), just use that index to get the attribute value. You don't need a loop and should not be normalizing the attributes which are not xml:id. Thanks.
        Hide
        Ishara Karunarathna added a comment -

        Hi Michael,

        Here I have attached the current code for the xmlID handler component and to configure Pipeline.
        XmlIDHandler class is the class file I created to Process xml:id attribute.

        I modified configurePipeline() method in org.apache.xerces.parsers.XML11Configuration class to add xml:id handler component to pipe line. And I add
        /** xml:id processing feature ("xml:id"). */
        public static final String XMLID_FEATURE = "xmlid";

        to the org.apache.xerces.impl.Constants.java class.
        Can you let me know what's left to do and improve.

        Thank you.

        Show
        Ishara Karunarathna added a comment - Hi Michael, Here I have attached the current code for the xmlID handler component and to configure Pipeline. XmlIDHandler class is the class file I created to Process xml:id attribute. I modified configurePipeline() method in org.apache.xerces.parsers.XML11Configuration class to add xml:id handler component to pipe line. And I add /** xml:id processing feature ("xml:id"). */ public static final String XMLID_FEATURE = "xmlid"; to the org.apache.xerces.impl.Constants.java class. Can you let me know what's left to do and improve. Thank you.
        Ishara Karunarathna made changes -
        Attachment xmlIDHandler.zip [ 12485626 ]
        Michael Glavassevich made changes -
        Assignee Ishara Karunarathna [ ishara ]
        Hide
        Michael Glavassevich added a comment -

        Hi Ishara,

        I've now had a chance to review your code. Good work!

        A key piece which still needs to be implemented is ID type assignment [1]. That is making the type "ID" in the XML Infoset and/or PSVI. XMLAttributes has a setType() method which you can use for that purpose. Also, if the attribute already had a type an xml:id processor is required to check that its type is ID, otherwise it is required to report an error if the attribute had some other type. That's another thing your code should be handling. Other than that you're nearly done with writing the component. Once you have the function complete, I would suggest that you create some JUnit tests for testing it, fix bugs you may find while testing, write up the documentation for the xml:id feature (examples of feature documentation are here [2]) and clean-up the code (e.g. removing System.out.println() and e.printStackTrace()) if you still have time.

        Thanks.

        [1] http://www.w3.org/TR/xml-id/#dt-id-assignment
        [2] http://xerces.apache.org/xerces2-j/features.html

        Show
        Michael Glavassevich added a comment - Hi Ishara, I've now had a chance to review your code. Good work! A key piece which still needs to be implemented is ID type assignment [1] . That is making the type "ID" in the XML Infoset and/or PSVI. XMLAttributes has a setType() method which you can use for that purpose. Also, if the attribute already had a type an xml:id processor is required to check that its type is ID, otherwise it is required to report an error if the attribute had some other type. That's another thing your code should be handling. Other than that you're nearly done with writing the component. Once you have the function complete, I would suggest that you create some JUnit tests for testing it, fix bugs you may find while testing, write up the documentation for the xml:id feature (examples of feature documentation are here [2] ) and clean-up the code (e.g. removing System.out.println() and e.printStackTrace()) if you still have time. Thanks. [1] http://www.w3.org/TR/xml-id/#dt-id-assignment [2] http://xerces.apache.org/xerces2-j/features.html
        Hide
        Ishara Karunarathna added a comment -

        Hi Michael,

        I have implemented ID type assignment and error reporting in the addXmlIDAttrsAndValidate() method in a following way.
        Thanks.

        protected void addXmlIDAttrsAndValidate(QName elementName, int elementIndex,
        XMLAttributes attributes) {

        if(attributes.getType(elementIndex) != null){
        String oldType = attributes.getType(elementIndex);
        if(!oldType.equals("ID")){
        fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
        "InvalidAttributeType",
        new Object[]

        {oldType}

        ,
        XMLErrorReporter.SEVERITY_FATAL_ERROR);

        }

        }
        else

        { attributes.setType(elementIndex, "ID"); }

        //

        Show
        Ishara Karunarathna added a comment - Hi Michael, I have implemented ID type assignment and error reporting in the addXmlIDAttrsAndValidate() method in a following way. Thanks. protected void addXmlIDAttrsAndValidate(QName elementName, int elementIndex, XMLAttributes attributes) { if(attributes.getType(elementIndex) != null){ String oldType = attributes.getType(elementIndex); if(!oldType.equals("ID")){ fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN, "InvalidAttributeType", new Object[] {oldType} , XMLErrorReporter.SEVERITY_FATAL_ERROR); } } else { attributes.setType(elementIndex, "ID"); } //
        Hide
        Michael Glavassevich added a comment -

        Hi Ishara,

        The xml:id specification says: "The xml:id processor performs ID type assignment on all xml:id attributes, even those that do not satisfy the constraints", so even when the declared type is incorrect you should be setting the type to be ID.

        Show
        Michael Glavassevich added a comment - Hi Ishara, The xml:id specification says: "The xml:id processor performs ID type assignment on all xml:id attributes, even those that do not satisfy the constraints", so even when the declared type is incorrect you should be setting the type to be ID.
        Hide
        Ishara Karunarathna added a comment -

        Hi Michael and Devs,

        Here I have attached[1] the complete code for xmlIDHandler component.

        Thank you,
        Ishara.

        [1] XmlIDhandler(v1.0)

        Show
        Ishara Karunarathna added a comment - Hi Michael and Devs, Here I have attached [1] the complete code for xmlIDHandler component. Thank you, Ishara. [1] XmlIDhandler(v1.0)
        Ishara Karunarathna made changes -
        Attachment XmlIDhandler(v1.0).zip [ 12491211 ]
        Hide
        Michael Glavassevich added a comment -

        Thanks Ishara.

        Show
        Michael Glavassevich added a comment - Thanks Ishara.
        Hide
        Jeff Powanda added a comment -

        Ishara:

        I'm very interested in using your Xerces patch to take advantage of xml:id support in Xerces. Please let me know how I can download or build the patch. Do I need to call Xerces differently?

        Regards,
        Jeff Powanda
        Vocera Communications, Inc.

        Show
        Jeff Powanda added a comment - Ishara: I'm very interested in using your Xerces patch to take advantage of xml:id support in Xerces. Please let me know how I can download or build the patch. Do I need to call Xerces differently? Regards, Jeff Powanda Vocera Communications, Inc.

          People

          • Assignee:
            Ishara Karunarathna
            Reporter:
            George Cristian Bina
          • Votes:
            4 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:

              Development