/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package xni; import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Stack; import java.util.Vector; import org.apache.xerces.dom.DocumentImpl; import org.apache.xerces.impl.Constants; import org.apache.xerces.impl.xs.SchemaSymbols; import org.apache.xerces.util.DOMUtil; import org.apache.xerces.util.NamespaceSupport; import org.apache.xerces.util.XMLAttributesImpl; import org.apache.xerces.util.XMLSymbols; import org.apache.xerces.xni.Augmentations; import org.apache.xerces.xni.NamespaceContext; import org.apache.xerces.xni.QName; import org.apache.xerces.xni.XMLAttributes; 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.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; import org.apache.xerces.xs.AttributePSVI; import org.apache.xerces.xs.ElementPSVI; import org.apache.xerces.xs.ItemPSVI; import org.apache.xerces.xs.StringList; import org.apache.xerces.xs.XSAnnotation; import org.apache.xerces.xs.XSAttributeDeclaration; import org.apache.xerces.xs.XSAttributeGroupDefinition; import org.apache.xerces.xs.XSAttributeUse; import org.apache.xerces.xs.XSComplexTypeDefinition; import org.apache.xerces.xs.XSConstants; import org.apache.xerces.xs.XSElementDeclaration; import org.apache.xerces.xs.XSFacet; import org.apache.xerces.xs.XSIDCDefinition; import org.apache.xerces.xs.XSModel; import org.apache.xerces.xs.XSModelGroup; import org.apache.xerces.xs.XSModelGroupDefinition; import org.apache.xerces.xs.XSMultiValueFacet; import org.apache.xerces.xs.XSNamedMap; import org.apache.xerces.xs.XSNamespaceItem; import org.apache.xerces.xs.XSNamespaceItemList; import org.apache.xerces.xs.XSNotationDeclaration; import org.apache.xerces.xs.XSObject; import org.apache.xerces.xs.XSObjectList; import org.apache.xerces.xs.XSParticle; import org.apache.xerces.xs.XSSimpleTypeDefinition; import org.apache.xerces.xs.XSTypeDefinition; import org.apache.xerces.xs.XSWildcard; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; /** * This class is a intersepts XNI events and serialized * XML infoset and Post Schema Validation Infoset. * * @author Arun Yadav,Sun Miscrosystem. * @author Peter McCracken, IBM * @version $Id: PSVIWriter.java 778248 2009-05-24 22:39:36Z mrglavas $ */ public class PSVIWriter implements XMLComponent, XMLDocumentFilter { public static final String XERCES_PSVI_NS = "http://apache.org/xml/2001/PSVInfosetExtension"; /** Feature id: augment Post-Schema-Validation-Infoset */ protected static final String PSVINFOSET = Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI; /** Feature id: include ignorable whitespace. */ protected static final String INCLUDE_IGNORABLE_WHITESPACE = "http://apache.org/xml/features/dom/include-ignorable-whitespace"; /** Include ignorable whitespace. */ protected boolean fIncludeIgnorableWhitespace; /** Recognized features. */ private static final String[] RECOGNIZED_FEATURES = { INCLUDE_IGNORABLE_WHITESPACE, PSVINFOSET, }; /** Feature defaults. */ private static final Boolean[] FEATURE_DEFAULTS = { null, null, }; /** Recognized properties. */ private static final String[] RECOGNIZED_PROPERTIES = { }; /** Property defaults. */ private static final Object[] PROPERTY_DEFAULTS = { }; /** PSVInfoset */ protected boolean fPSVInfoset; /** Document handler. */ protected XMLDocumentHandler fDocumentHandler; /** Document source */ protected XMLDocumentSource fDocumentSource; /** The namespace context for the received event stream */ protected NamespaceContext fNamespaceContext; /** The namespace context for the new event stream */ protected NamespaceContext fPSVINamespaceContext; /** Document Location */ protected XMLLocator fDocumentLocation; /** Attributes and Element Info is cached in stack */ private Stack _elementState = new Stack(); /** The number used for anonymous types */ protected int fAnonNum; /** The number that stores the indent level */ protected int fIndent; /** The map used to store IDs for types and elements */ protected HashMap fIDMap; /** A list of ids for defined XSObjects */ protected Vector fDefined; private char[] fIndentChars = { '\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t' }; private XMLString newLine = new XMLString(new char[] { '\n' }, 0, 1); public PSVIWriter() { /* System.out.println( "Generating Schema Information Set Contribution (PSVI) \n" + "which follow as a consequence of validation and/or assessment."); System.out.println("NOTE: Requires use of -s and -v"); System.out.println("Output: generated in " + PSVI_OUTPUT); */ } // <init>() public void reset(XMLComponentManager componentManager) throws XNIException { try { fPSVInfoset = componentManager.getFeature(PSVINFOSET); } catch (XMLConfigurationException e) { fPSVInfoset = false; } fIncludeIgnorableWhitespace = componentManager.getFeature(INCLUDE_IGNORABLE_WHITESPACE); fAnonNum = 1000; fIDMap = new HashMap(); fDefined = new Vector(); fIndent = 0; fPSVINamespaceContext = new NamespaceSupport(); } // reset(XMLComponentManager) /** * Returns a list of feature identifiers that are recognized by * this component. This method may return null if no features * are recognized by this component. */ public String[] getRecognizedFeatures() { return RECOGNIZED_FEATURES; } // getRecognizedFeatures():String[] /** * Sets the state of a feature. This method is called by the component * manager any time after reset when a feature changes state. * <p> * <strong>Note:</strong> Components should silently ignore features * that do not affect the operation of the component. * * @param featureId The feature identifier. * @param state The state of the feature. * * @throws SAXNotRecognizedException The component should not throw * this exception. * @throws SAXNotSupportedException The component should not throw * this exception. */ public void setFeature(String featureId, boolean state) throws XMLConfigurationException { } // setFeature(String,boolean) /** * Returns a list of property identifiers that are recognized by * this component. This method may return null if no properties * are recognized by this component. */ public String[] getRecognizedProperties() { return RECOGNIZED_PROPERTIES; } // getRecognizedProperties():String[] /** * Sets the value of a property. This method is called by the component * manager any time after reset when a property changes value. * <p> * <strong>Note:</strong> Components should silently ignore properties * that do not affect the operation of the component. * * @param propertyId The property identifier. * @param value The value of the property. * * @throws SAXNotRecognizedException The component should not throw * this exception. * @throws SAXNotSupportedException The component should not throw * this exception. */ public void setProperty(String propertyId, Object value) throws XMLConfigurationException { } // setProperty(String,Object) /** * Returns the default state for a feature, or null if this * component does not want to report a default value for this * feature. * * @param featureId The feature identifier. * * @since Xerces 2.2.0 */ public Boolean getFeatureDefault(String featureId) { for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { if (RECOGNIZED_FEATURES[i].equals(featureId)) { return FEATURE_DEFAULTS[i]; } } return null; } // getFeatureDefault(String):Boolean /** * Returns the default state for a property, or null if this * component does not want to report a default value for this * property. * * @param propertyId The property identifier. * * @since Xerces 2.2.0 */ public Object getPropertyDefault(String propertyId) { for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { return PROPERTY_DEFAULTS[i]; } } return null; } // getPropertyDefault(String):Object // // XMLDocumentSource methods // /** Sets the document handler to receive information about the document. */ public void setDocumentHandler(XMLDocumentHandler documentHandler) { fDocumentHandler = documentHandler; } // setDocumentHandler(XMLDocumentHandler) /** Returns the document handler */ public XMLDocumentHandler getDocumentHandler() { return fDocumentHandler; } // setDocumentHandler(XMLDocumentHandler) // // XMLDocumentHandler methods // /** Sets the document source */ public void setDocumentSource(XMLDocumentSource source) { fDocumentSource = source; } // setDocumentSource /** Returns the document source */ public XMLDocumentSource getDocumentSource() { return fDocumentSource; } // getDocumentSource /** * This method notifies the start of an entity. General entities are just * specified by their name. * <p> * <strong>Note:</strong> This method is not called for entity references * appearing as part of attribute values. * * @param name The name of the entity. * @param publicId The public identifier of the entity if the entity * is external, null otherwise. * @param systemId The system identifier of the entity if the entity * is external, null otherwise. * @param baseSystemId The base system identifier of the entity if * the entity is external, null otherwise. * @param encoding The auto-detected IANA encoding name of the entity * stream. This value will be null in those situations * where the entity encoding is not auto-detected (e.g. * internal entities or a document entity that is * parsed from a java.io.Reader). * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void startGeneralEntity( String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs) throws XNIException { } // startEntity(String,String,String,String,String) /** * Notifies of the presence of a TextDecl line in an entity. If present, * this method will be called immediately following the startEntity call. * <p> * <strong>Note:</strong> This method will never be called for the * document entity; it is only called for external general entities * referenced in document content. * <p> * <strong>Note:</strong> This method is not called for entity references * appearing as part of attribute values. * * @param version The XML version, or null if not specified. * @param encoding The IANA encoding name of the entity. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { } // textDecl(String,String) /** * The start of the document. * @throws XNIException Thrown by handler to signal an error. */ public void startDocument( XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException { fNamespaceContext = namespaceContext; fDocumentLocation = locator; fPSVINamespaceContext.declarePrefix( "xsi", "http://www.w3.org/2001/XMLSchema-instance"); fPSVINamespaceContext.declarePrefix("psv", XERCES_PSVI_NS); fPSVINamespaceContext.declarePrefix( "", "http://www.w3.org/2001/05/XMLInfoset"); if (fDocumentHandler == null) return; fDocumentHandler.startDocument( locator, "UTF-8", fPSVINamespaceContext, null); Vector attributes = new Vector(); attributes.add("xmlns:xsi"); attributes.add("http://www.w3.org/2001/XMLSchema-instance"); attributes.add(XMLSymbols.fCDATASymbol); attributes.add("xmlns:psv"); attributes.add(XERCES_PSVI_NS); attributes.add(XMLSymbols.fCDATASymbol); attributes.add("xmlns"); attributes.add("http://www.w3.org/2001/05/XMLInfoset"); attributes.add(XMLSymbols.fCDATASymbol); sendIndentedElement("document", attributes); } // startDocument(XMLLocator,String) /** * Notifies of the presence of an XMLDecl line in the document. If * present, this method will be called immediately following the * startDocument call. * * @param version The XML version. * @param encoding The IANA encoding name of the document, or null if * not specified. * @param standalone The standalone value, or null if not specified. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void xmlDecl( String version, String encoding, String standalone, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; sendElementEvent("characterEncodingScheme", encoding); sendElementEvent("standalone", standalone); sendElementEvent("version", version); } // xmlDecl(String,String,String) /** * Notifies of the presence of the DOCTYPE line in the document. * * @param rootElement The name of the root element. * @param publicId The public identifier if an external DTD or null * if the external DTD is specified using SYSTEM. * @param systemId The system identifier if an external DTD, null * otherwise. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void doctypeDecl( String rootElement, String publicId, String systemId, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; checkForChildren(); sendIndentedElement("docTypeDeclaration"); if (publicId != null) sendElementEvent("publicIdentifier", publicId); if (systemId != null) sendElementEvent("systemIdentifier", systemId); sendUnIndentedElement("docTypeDeclaration"); } // doctypeDecl(String,String,String) /** * A comment. * * @param text The text in the comment. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by application to signal an error. */ public void comment(XMLString text, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; checkForChildren(); sendIndentedElement("comment"); sendElementEvent("content", text); sendUnIndentedElement("comment"); } // comment(XMLString) /** * A processing instruction. Processing instructions consist of a * target name and, optionally, text data. The data is only meaningful * to the application. * <p> * Typically, a processing instruction's data will contain a series * of pseudo-attributes. These pseudo-attributes follow the form of * element attributes but are <strong>not</strong> parsed or presented * to the application as anything other than text. The application is * responsible for parsing the data. * * @param target The target. * @param data The data or null if none specified. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void processingInstruction( String target, XMLString data, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; checkForChildren(); sendIndentedElement("processingInstruction"); sendElementEvent("target", target); sendElementEvent("content", data); sendUnIndentedElement("processingInstruction"); } // processingInstruction(String,XMLString) /** * Binds the namespaces. This method will handle calling the * document handler to start the prefix mappings. * <p> * <strong>Note:</strong> This method makes use of the * fAttributeQName variable. Any contents of the variable will * be destroyed. Caller should copy the values out of this * temporary variable before calling this method. * * @param element The name of the element. * @param attributes The element attributes. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void startElement( QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; checkForChildren(); _elementState.push(new ElementState(true)); sendIndentedElement("element"); sendElementEvent("namespaceName", element.uri); sendElementEvent("localName", element.localpart); sendElementEvent("prefix", element.prefix); processAttributes(attributes); processInScopeNamespaces(); sendElementEvent("baseURI", fDocumentLocation.getBaseSystemId()); if (fPSVInfoset) { processPSVIStartElement(augs); } } // startElement(QName,XMLAttributes) /** * An empty element. * * @param element The name of the element. * @param attributes The element attributes. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void emptyElement( QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; checkForChildren(); sendIndentedElement("element"); sendElementEvent("namespaceName", element.uri); sendElementEvent("localName", element.localpart); sendElementEvent("prefix", element.prefix); processAttributes(attributes); processInScopeNamespaces(); sendElementEvent("baseURI", fDocumentLocation.getBaseSystemId()); if (fPSVInfoset) { processPSVIStartElement(augs); } sendEmptyElementEvent("children"); if (fPSVInfoset) { processPSVIEndElement(augs); } sendUnIndentedElement("element"); } // emptyElement(QName,XMLAttributes) /** * Character content. * * @param text The content. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void characters(XMLString text, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; checkForChildren(); sendIndentedElement("character"); sendElementEvent("textContent", text); // detecting whitespace is not relevant here // this is only useful if characters are output individually sendUnIndentedElement("character"); } // characters(XMLString) /** * Ignorable whitespace. For this method to be called, the document * source must have some way of determining that the text containing * only whitespace characters should be considered ignorable. For * example, the validator can determine if a length of whitespace * characters in the document are ignorable based on the element * content model. * * @param text The ignorable whitespace. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; if (fIncludeIgnorableWhitespace) { this.characters(text, augs); } } // ignorableWhitespace(XMLString) /** * The end of an element. * * @param element The name of the element. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void endElement(QName element, Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; ElementState fElementState = (ElementState)_elementState.peek(); if (fElementState.isEmpty) { sendEmptyElementEvent("children"); } else { sendUnIndentedElement("children"); } _elementState.pop(); if (fPSVInfoset) { processPSVIStartElement(augs); processPSVIEndElement(augs); } sendUnIndentedElement("element"); } // endElement(QName) /** * The start of a CDATA section. * * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void startCDATA(Augmentations augs) throws XNIException { } // startCDATA() /** * The end of a CDATA section. * * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void endCDATA(Augmentations augs) throws XNIException { } // endCDATA() /** * The end of the document. * * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void endDocument(Augmentations augs) throws XNIException { if (fDocumentHandler == null) return; sendUnIndentedElement("children"); sendElementEvent("documentElement"); // these aren't relevent for PSVI sendEmptyElementEvent("notations"); sendEmptyElementEvent("unparsedEntities"); sendElementEvent("baseURI", fDocumentLocation.getBaseSystemId()); // do we ALWAYS process all declarations? I think so - PJM // this isn't relevant to PSVI sendElementEvent("allDeclarationsProcessed", "true"); sendUnIndentedElement("document"); fDocumentHandler.endDocument(null); } // endDocument() /** * This method notifies the end of an entity. General entities are just * specified by their name. * <p> * <strong>Note:</strong> This method is not called for entity references * appearing as part of attribute values. * * @param name The name of the entity. * @param augs Additional information that may include infoset augmentations * * @throws XNIException Thrown by handler to signal an error. */ public void endGeneralEntity(String name, Augmentations augs) throws XNIException { } // endEntity(String) /** * Write an unordered set of attribute information items, one for each of * the attributes (specified or defaulted from the DTD) of this element. * Namespace declarations do not appear in this set. If the element has no * attributes, this set has no members. */ private void processAttributes(XMLAttributes attributes) { boolean namespaceAttribute = false; boolean attrElement = false; int attrCount = attributes == null ? 0 : attributes.getLength(); if (attrCount == 0) { sendEmptyElementEvent("attributes"); sendEmptyElementEvent("namespaceAttributes"); return; } for (int i = 0; i < attrCount; i++) { String localpart = attributes.getLocalName(i); String prefix = attributes.getPrefix(i); if (prefix.equals(XMLSymbols.PREFIX_XMLNS) || localpart.equals(XMLSymbols.PREFIX_XMLNS)) { namespaceAttribute = true; continue; } if (!attrElement) sendIndentedElement("attributes"); sendIndentedElement("attribute"); sendElementEvent("namespaceName", attributes.getURI(i)); sendElementEvent("localName", attributes.getLocalName(i)); sendElementEvent("prefix", attributes.getPrefix(i)); sendElementEvent("normalizedValue", attributes.getValue(i)); sendElementEvent( "specified", String.valueOf(attributes.isSpecified(i))); sendElementEvent("attributeType", attributes.getType(i)); // this property isn't relevent to PSVI sendElementEvent("references"); if (fPSVInfoset) { processPSVIAttribute(attributes.getAugmentations(i)); } sendUnIndentedElement("attribute"); attrElement = true; } if (attrElement) { sendUnIndentedElement("attributes"); } else { sendEmptyElementEvent("attributes"); } if (namespaceAttribute) { processNamespaceAttributes(attributes); } else { sendEmptyElementEvent("namespaceAttributes"); } } //printAttributes /** * Write an unordered set of attribute information items, one for each of * the namespace declarations (specified or defaulted from the DTD) of this * element. A declaration of the form xmlns="", which undeclares the default * namespace, counts as a namespace declaration. By definition, all * namespace attributes (including those named xmlns, whose [prefix] * property has no value) have a namespace URI of * http://www.w3.org/2000/xmlns/. If the element has no namespace * declarations, this set has no members */ private void processNamespaceAttributes(XMLAttributes attributes) { // we don't need to check for null, since that was checked for in processAttributes() int attrCount = attributes.getLength(); sendIndentedElement("namespaceAttributes"); for (int i = 0; i < attrCount; i++) { String localpart = attributes.getLocalName(i); String prefix = attributes.getPrefix(i); if (!(prefix.equals(XMLSymbols.PREFIX_XMLNS) || localpart.equals(XMLSymbols.PREFIX_XMLNS))) continue; sendIndentedElement("attribute"); sendElementEvent("namespaceName", NamespaceContext.XMLNS_URI); sendElementEvent("localName", localpart); sendElementEvent("prefix", prefix); sendElementEvent("normalizedValue", attributes.getValue(i)); sendElementEvent( "specified", String.valueOf(attributes.isSpecified(i))); sendElementEvent("attributeType", attributes.getType(i)); // this property isn't relevent to PSVI sendElementEvent("references"); if (fPSVInfoset) { processPSVIAttribute(attributes.getAugmentations(i)); } sendUnIndentedElement("attribute"); } sendUnIndentedElement("namespaceAttributes"); } //printNamespacesAttributes() /** * Write an unordered set of namespace information items, one for each of the * namespaces in effect for this element. This set always contains an item * with the prefix xml which is implicitly bound to the namespace name * http://www.w3.org/XML/1998/namespace. It does not contain an item with the * prefix xmlns (used for declaring namespaces), since an application can * never encounter an element or attribute with that prefix. The set will * include namespace items corresponding to all of the members of * [namespace attributes], except for any representing a declaration of the * form xmlns="", which does not declare a namespace but rather undeclares * the default namespace */ private void processInScopeNamespaces() { sendIndentedElement("inScopeNamespaces"); sendIndentedElement("namespace"); // print 'xml' binding sendElementEvent("prefix", "xml"); sendElementEvent("namespaceName", NamespaceContext.XML_URI); sendUnIndentedElement("namespace"); Enumeration prefixes = fNamespaceContext.getAllPrefixes(); while (prefixes.hasMoreElements()) { sendIndentedElement("namespace"); String prefix = (String)prefixes.nextElement(); String uri = fNamespaceContext.getURI(prefix); sendElementEvent("prefix", prefix); sendElementEvent("namespaceName", uri); sendUnIndentedElement("namespace"); } sendUnIndentedElement("inScopeNamespaces"); } //printinScopeNamespaces() /* The following information will be available at the startElement call: * name, namespace, type, notation, validation context * * The following information will be available at the endElement call: * nil, specified, normalized value, member type, validity, error codes, * default */ private void processPSVIStartElement(Augmentations augs) { if (augs == null) return; ElementPSVI elemPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI); if (elemPSVI != null) { // Should we store the values till end element call? -- AY // I don't think so -- PJM } } /* The following information will be available at the startElement call: * name, namespace, type, notation, validation context * * The following information will be available at the endElement call: * nil, specified, normalized value, member type, validity, error codes, * default */ private void processPSVIEndElement(Augmentations augs) { if (augs == null) return; ElementPSVI elemPSVI = (ElementPSVI)augs.getItem(Constants.ELEMENT_PSVI); if (elemPSVI != null) { processPSVISchemaInformation(elemPSVI); sendElementEvent( "psv:validationAttempted", this.translateValidationAttempted( elemPSVI.getValidationAttempted())); // Would rather getValidationContext() return element info item. // This is non the same as XSV. sendElementEvent( "psv:validationContext", elemPSVI.getValidationContext()); sendElementEvent( "psv:validity", this.translateValidity(elemPSVI.getValidity())); processPSVISchemaErrorCode(elemPSVI.getErrorCodes()); sendElementEvent( "psv:schemaNormalizedValue", elemPSVI.getSchemaNormalizedValue()); sendElementEvent( "psv:schemaSpecified", elemPSVI.getIsSchemaSpecified() ? "schema" : "infoset"); sendElementEvent("psv:schemaDefault", elemPSVI.getSchemaDefault()); processPSVITypeDefinitionRef( "psv:typeDefinition", elemPSVI.getTypeDefinition()); processPSVITypeDefinitionRef( "psv:memberTypeDefinition", elemPSVI.getMemberTypeDefinition()); // A value for nil is not necessary, since we output declaration, instead. // See http://www.w3.org/TR/xmlschema-1/#section-Element-Declaration-Information-Set-Contributions. sendElementEvent("psv:nil"); sendIndentedElement("psv:declaration"); processPSVIElementRef( "psv:elementDeclaration", elemPSVI.getElementDeclaration()); sendUnIndentedElement("psv:declaration"); processPSVIElementRef("psv:notation", elemPSVI.getNotation()); // idref table does not have to be exposed, and is not exposed sendElementEvent("psv:idIdrefTable"); // identity constraint table does not have to be exposed, and is not exposed sendElementEvent("psv:identityConstraintTable"); } } private void processPSVIAttribute(Augmentations augs) { if (augs == null) return; AttributePSVI attrPSVI = (AttributePSVI)augs.getItem(Constants.ATTRIBUTE_PSVI); if (attrPSVI != null) { sendElementEvent( "psv:validationAttempted", this.translateValidationAttempted( attrPSVI.getValidationAttempted())); // Would rather getValidationContext() return element info item. // This is not the same as XSV. sendElementEvent( "psv:validationContext", attrPSVI.getValidationContext()); sendElementEvent( "psv:validity", this.translateValidity(attrPSVI.getValidity())); processPSVISchemaErrorCode(attrPSVI.getErrorCodes()); sendElementEvent( "psv:schemaNormalizedValue", attrPSVI.getSchemaNormalizedValue()); sendElementEvent( "psv:schemaSpecified", attrPSVI.getIsSchemaSpecified() ? "schema" : "infoset"); sendElementEvent("psv:schemaDefault", attrPSVI.getSchemaDefault()); processPSVITypeDefinitionRef( "psv:typeDefinition", attrPSVI.getTypeDefinition()); processPSVITypeDefinitionRef( "psv:memberTypeDefinition", attrPSVI.getMemberTypeDefinition()); if (attrPSVI.getAttributeDeclaration() == null) { sendElementEvent("psv:declaration"); } else { sendIndentedElement("psv:declaration"); processPSVIAttributeDeclarationRef( attrPSVI.getAttributeDeclaration()); sendUnIndentedElement("psv:declaration"); } } } private void processPSVISchemaErrorCode(StringList errorCodes) { StringBuffer errorBuffer = new StringBuffer(); if (errorCodes != null && errorCodes.getLength() > 0) { for (int i = 0; i < errorCodes.getLength() - 1; i++) { errorBuffer.append(errorCodes.item(i)); errorBuffer.append(" "); } errorBuffer.append(errorCodes.item(errorCodes.getLength() - 1)); } sendElementEvent("psv:schemaErrorCode", errorBuffer.toString()); } private void processPSVISchemaInformation(ElementPSVI elemPSVI) { if (elemPSVI == null) return; XSModel schemaInfo = elemPSVI.getSchemaInformation(); XSNamespaceItemList schemaNamespaces = schemaInfo == null ? null : schemaInfo.getNamespaceItems(); if (schemaNamespaces == null || schemaNamespaces.getLength() == 0) { sendElementEvent("psv:schemaInformation"); } else { sendIndentedElement("psv:schemaInformation"); for (int i = 0; i < schemaNamespaces.getLength(); i++) { processPSVINamespaceItem(schemaNamespaces.item(i)); } sendUnIndentedElement("psv:schemaInformation"); } } private void processPSVINamespaceItem(XSNamespaceItem item) { if (item == null) return; String namespace = item.getSchemaNamespace(); if (namespace != null && namespace.equals(Constants.NS_XMLSCHEMA)) { // we don't want to output information for schema for schemas return; } sendIndentedElement("psv:namespaceSchemaInformation"); sendElementEvent("psv:schemaNamespace", namespace); // print out schema components processPSVISchemaComponents(item); // print out schema document information processPSVISchemaDocuments(item); // print out schema annotations processPSVISchemaAnnotations(item.getAnnotations()); sendUnIndentedElement("psv:namespaceSchemaInformation"); } private void processPSVISchemaDocuments(XSNamespaceItem item) { StringList locations = item == null ? null : item.getDocumentLocations(); if (locations == null || locations.getLength() == 0) { sendEmptyElementEvent("psv:schemaDocuments"); return; } sendIndentedElement("psv:schemaDocuments"); for (int i = 0; i < locations.getLength(); i++) { sendIndentedElement("psv:schemaDocument"); sendElementEvent("psv:documentLocation", locations.item(i)); // It's supposed to point to a <document> element, and we're not really // dealing with those (except for the one at the root) sendElementEvent("psv:document"); sendUnIndentedElement("psv:schemaDocument"); } sendUnIndentedElement("psv:schemaDocuments"); } private void processPSVISchemaComponents(XSNamespaceItem item) { if (item == null) { sendEmptyElementEvent("psv:schemaComponents"); return; } // it we happen to not get any components, this will output a start tag // and a close tag, instead of an empty element tag. This isn't a big // deal, though sendIndentedElement("psv:schemaComponents"); // typeDefinitions XSNamedMap components = item.getComponents(XSConstants.TYPE_DEFINITION); for (int i = 0; i < components.getLength(); i++) { processPSVITypeDefinition((XSTypeDefinition)components.item(i)); } // elementDeclarations components = item.getComponents(XSConstants.ELEMENT_DECLARATION); for (int i = 0; i < components.getLength(); i++) { processPSVIElementDeclaration( (XSElementDeclaration)components.item(i)); } // attributeDeclarations components = item.getComponents(XSConstants.ATTRIBUTE_DECLARATION); for (int i = 0; i < components.getLength(); i++) { processPSVIAttributeDeclaration( (XSAttributeDeclaration)components.item(i)); } // modelGroupDefinitions components = item.getComponents(XSConstants.MODEL_GROUP_DEFINITION); for (int i = 0; i < components.getLength(); i++) { processPSVIModelGroupDefinition( (XSModelGroupDefinition)components.item(i)); } // attributeGroupDefinitions components = item.getComponents(XSConstants.ATTRIBUTE_GROUP); for (int i = 0; i < components.getLength(); i++) { processPSVIAttributeGroupDefinition( (XSAttributeGroupDefinition)components.item(i)); } // notationDeclarations components = item.getComponents(XSConstants.NOTATION_DECLARATION); for (int i = 0; i < components.getLength(); i++) { processPSVINotationDeclaration( (XSNotationDeclaration)components.item(i)); } sendUnIndentedElement("psv:schemaComponents"); } private void processPSVITypeDefinition(XSTypeDefinition type) { if (type == null) return; if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { processPSVIComplexTypeDefinition((XSComplexTypeDefinition)type); } else if (type.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { processPSVISimpleTypeDefinition((XSSimpleTypeDefinition)type); } else { throw new IllegalArgumentException( "Unknown type definition value: " + type.getType()); } } private void processPSVIComplexTypeDefinition(XSComplexTypeDefinition type) { if (type == null) return; sendIndentedElementWithID("psv:complexTypeDefinition", type); sendElementEvent("psv:name", type.getName()); sendElementEvent("psv:targetNamespace", type.getNamespace()); processPSVITypeDefinitionOrRef( "psv:baseTypeDefinition", type.getBaseType()); sendElementEvent( "psv:derivationMethod", this.translateDerivation(type.getDerivationMethod())); sendElementEvent("psv:final", this.translateBlockOrFinal(type.getFinal())); sendElementEvent("psv:abstract", String.valueOf(type.getAbstract())); processPSVIAttributeUses(type.getAttributeUses()); processPSVIAttributeWildcard(type.getAttributeWildcard()); sendIndentedElement("psv:contentType"); sendElementEvent( "psv:variety", this.translateContentType(type.getContentType())); XSSimpleTypeDefinition simpleType = type.getSimpleType(); if(simpleType == null || (!simpleType.getAnonymous() || fDefined.contains(this.getID(simpleType)))) { processPSVIElementRef("psv:simpleTypeDefinition", simpleType); } else { processPSVISimpleTypeDefinition(simpleType); } processPSVIParticle(type.getParticle()); sendUnIndentedElement("psv:contentType"); sendElementEvent( "psv:prohibitedSubstitutions", this.translateBlockOrFinal(type.getProhibitedSubstitutions())); processPSVIAnnotations(type.getAnnotations()); sendUnIndentedElement("psv:complexTypeDefinition"); } private void processPSVISimpleTypeDefinition(XSSimpleTypeDefinition type) { if (type == null) { sendElementEvent("psv:simpleTypeDefinition"); return; } sendIndentedElementWithID("psv:simpleTypeDefinition", type); sendElementEvent("psv:name", type.getName()); sendElementEvent("psv:targetNamespace", type.getNamespace()); processPSVITypeDefinitionOrRef( "psv:baseTypeDefinition", type.getBaseType()); processPSVITypeDefinitionOrRef( "psv:primitiveTypeDefinition", type.getPrimitiveType()); processPSVIFacets(type); sendIndentedElement("psv:fundamentalFacets"); sendIndentedElement("psv:ordered"); sendElementEvent("psv:value", this.translateOrdered(type.getOrdered())); sendUnIndentedElement("psv:ordered"); sendIndentedElement("psv:bounded"); sendElementEvent("psv:value", String.valueOf(type.getBounded())); sendUnIndentedElement("psv:bounded"); sendIndentedElement("psv:cardinality"); sendElementEvent("psv:value", String.valueOf(type.getFinite())); sendUnIndentedElement("psv:cardinality"); sendIndentedElement("psv:numeric"); sendElementEvent("psv:value", String.valueOf(type.getNumeric())); sendUnIndentedElement("psv:numeric"); sendUnIndentedElement("psv:fundamentalFacets"); sendElementEvent("psv:final", this.translateBlockOrFinal(type.getFinal())); sendElementEvent( "psv:variety", this.translateVariety(type.getVariety())); processPSVITypeDefinitionOrRef( "psv:itemTypeDefinition", type.getItemType()); processPSVIMemberTypeDefinitions(type.getMemberTypes()); processPSVIAnnotations(type.getAnnotations()); sendUnIndentedElement("psv:simpleTypeDefinition"); } private void processPSVIFacets(XSSimpleTypeDefinition type) { if (type == null) return; XSObjectList facets = type.getFacets(); XSObjectList multiValueFacets = type.getMultiValueFacets(); if ((facets == null || facets.getLength() == 0) && (multiValueFacets == null || multiValueFacets.getLength() == 0)) { sendElementEvent("psv:facets"); } else { sendIndentedElement("psv:facets"); if (facets != null) { for (int i = 0; i < facets.getLength(); i++) { XSFacet facet = (XSFacet)facets.item(i); String name = this.translateFacetKind(facet.getFacetKind()); sendIndentedElement("psv:" + name); sendElementEvent("psv:value", facet.getLexicalFacetValue()); sendElementEvent( "psv:fixed", String.valueOf(facet.getFixed())); processPSVIAnnotation(facet.getAnnotation()); sendUnIndentedElement("psv:" + name); } } if (multiValueFacets != null) { for (int i = 0; i < multiValueFacets.getLength(); i++) { XSMultiValueFacet facet = (XSMultiValueFacet)multiValueFacets.item(i); String name = this.translateFacetKind(facet.getFacetKind()); sendIndentedElement("psv:" + name); StringList values = facet.getLexicalFacetValues(); for (int j = 0; j < values.getLength(); j++) { sendElementEvent("psv:value", values.item(j)); } sendElementEvent("psv:fixed", "false"); processPSVIAnnotations(facet.getAnnotations()); sendUnIndentedElement("psv:" + name); } } sendUnIndentedElement("psv:facets"); } } private void processPSVIMemberTypeDefinitions(XSObjectList memTypes) { if (memTypes == null || memTypes.getLength() == 0) { sendElementEvent("psv:memberTypeDefinitions"); } else { sendIndentedElement("psv:memberTypeDefinitions"); for (int i = 0; i < memTypes.getLength(); i++) { processPSVITypeDefinitionOrRef( "psv:memberTypeDefinition", (XSTypeDefinition)memTypes.item(i)); } sendUnIndentedElement("psv:memberTypeDefinitions"); } } /* It's possible that this method will send events for null annotations, i.e. * <psv:annotations> * <psv:annotation xsi:nil="true"/> * <psv:annotation>...</psv:annotation> * </psv:annotations> * * This is because of the way multi-value facet is implemented. It represents * the annotation on each value of the facet, and if a value doesn't have one, * it's corresponding annotation is null. Thus, it's possible for the first * annotation to be null, but the second one to be exist. * * An exception to this is if all of the annotations are null; then I output * <psv:annotations xsi:nil="true"/> */ private void processPSVIAnnotations(XSObjectList annotations) { boolean empty = true; if (annotations != null && annotations.getLength() > 0) { for (int i = 0; i < annotations.getLength(); i++) { if (annotations.item(i) != null) { empty = false; break; } } } if (empty) { sendElementEvent("psv:annotations"); } else { sendIndentedElement("psv:annotations"); for (int i = 0; i < annotations.getLength(); i++) { processPSVIAnnotation((XSAnnotation)annotations.item(i)); } sendUnIndentedElement("psv:annotations"); } } private void processPSVISchemaAnnotations(XSObjectList annotations) { if (annotations == null || annotations.getLength() == 0) { sendElementEvent("psv:schemaAnnotations"); } else { sendIndentedElement("psv:schemaAnnotations"); for (int i = 0; i < annotations.getLength(); i++) { processPSVIAnnotation((XSAnnotation)annotations.item(i)); } sendUnIndentedElement("psv:schemaAnnotations"); } } private void processPSVIAttributeUses(XSObjectList uses) { if (uses == null || uses.getLength() == 0) { sendElementEvent("psv:attributeUses"); } else { sendIndentedElement("psv:attributeUses"); for (int i = 0; i < uses.getLength(); i++) { XSAttributeUse use = (XSAttributeUse)uses.item(i); sendIndentedElement("psv:attributeUse"); sendElementEvent("psv:required", String.valueOf(use.getRequired())); processPSVIAttributeDeclarationOrRef(use.getAttrDeclaration()); processPSVIValueConstraint(use.getConstraintType(), use.getConstraintValue()); sendUnIndentedElement("psv:attributeUse"); } sendUnIndentedElement("psv:attributeUses"); } } private void processPSVIAttributeWildcard(XSWildcard wildcard) { if (wildcard == null) { sendElementEvent("psv:attributeWildcard"); } else { sendIndentedElement("psv:attributeWildcard"); processPSVIWildcard(wildcard); sendUnIndentedElement("psv:attributeWildcard"); } } private void processPSVIWildcard(XSWildcard wildcard) { if (wildcard == null) return; sendIndentedElement("psv:wildcard"); sendIndentedElement("psv:namespaceConstraint"); sendElementEvent( "psv:variety", this.translateConstraintType(wildcard.getConstraintType())); StringBuffer constraintBuffer = new StringBuffer(); StringList constraints = wildcard.getNsConstraintList(); if (constraints != null && constraints.getLength() > 0) { for (int i = 0; i < constraints.getLength() - 1; i++) { constraintBuffer.append(constraints.item(i)); constraintBuffer.append(" "); } constraintBuffer.append( constraints.item(constraints.getLength() - 1)); } sendElementEvent("psv:namespaces", constraintBuffer.toString()); sendUnIndentedElement("psv:namespaceConstraint"); sendElementEvent( "psv:processContents", this.translateProcessContents(wildcard.getProcessContents())); processPSVIAnnotation(wildcard.getAnnotation()); sendUnIndentedElement("psv:wildcard"); } private void processPSVIAnnotation(XSAnnotation ann) { if (ann == null) { sendElementEvent("psv:annotation"); } else { sendIndentedElement("psv:annotation"); // We can't get all the information from DOM, but I've outputed what // we can get -- PJM Node dom = new DocumentImpl(); ann.writeAnnotation(dom, XSAnnotation.W3C_DOM_DOCUMENT); // this child will be the annotation element Element annot = DOMUtil.getFirstChildElement(dom); processDOMElement( annot, SchemaSymbols.ELT_APPINFO, "psv:applicationInformation"); processDOMElement( annot, SchemaSymbols.ELT_DOCUMENTATION, "psv:userInformation"); processDOMAttributes(annot); sendUnIndentedElement("psv:annotation"); } } private void processDOMElement( Node node, String elementName, String tagName) { if (node == null) return; boolean foundElem = false; for (Element child = DOMUtil.getFirstChildElement(node); child != null; child = DOMUtil.getNextSiblingElement(child)) { if (DOMUtil.getLocalName(child).equals(elementName)) { if (!foundElem) { sendIndentedElement(tagName); foundElem = true; } sendIndentedElement("element"); sendElementEvent( "namespaceName", DOMUtil.getNamespaceURI(child)); sendElementEvent("localName", DOMUtil.getLocalName(child)); sendElementEvent("prefix", child.getPrefix()); sendIndentedElement("children"); sendIndentedElement("character"); sendElementEvent("textContent", DOMUtil.getChildText(child)); sendUnIndentedElement("character"); sendUnIndentedElement("children"); //Create XMLAttributes from DOM Attr[] atts = (Element) child == null ? null : DOMUtil.getAttrs((Element) child); XMLAttributes attrs = new XMLAttributesImpl(); for (int i=0; i<atts.length; i++) { Attr att = (Attr)atts[i]; attrs.addAttribute( new QName(att.getPrefix(), att.getLocalName(), att.getName(), att.getNamespaceURI()), "CDATA" ,att.getValue() ); } processAttributes(attrs); sendUnIndentedElement("element"); } } if (foundElem) { sendUnIndentedElement(tagName); } else { sendEmptyElementEvent(tagName); } } private void processDOMAttributes(Element elem) { Attr[] atts = elem == null ? null : DOMUtil.getAttrs(elem); boolean namespaceAttribute = false; boolean attrElement = false; int attrCount = atts == null ? 0 : atts.length; if (attrCount == 0) { sendEmptyElementEvent("attributes"); sendEmptyElementEvent("namespaceAttributes"); return; } for (int i = 0; i < attrCount; i++) { Attr att = (Attr)atts[i]; String localpart = DOMUtil.getLocalName(att); String prefix = att.getPrefix(); if (localpart.equals(XMLSymbols.PREFIX_XMLNS) || prefix.equals(XMLSymbols.PREFIX_XMLNS)) { namespaceAttribute = true; continue; } if (!attrElement) sendIndentedElement("attributes"); sendIndentedElement("attribute"); sendElementEvent("namespaceName", DOMUtil.getNamespaceURI(att)); sendElementEvent("localName", DOMUtil.getLocalName(att)); sendElementEvent("prefix", att.getPrefix()); sendElementEvent("normalizedValue", att.getValue()); sendElementEvent( "specified", String.valueOf(att.getSpecified())); sendElementEvent("attributeType"); // this property isn't relevent to PSVI sendElementEvent("references"); sendUnIndentedElement("attribute"); attrElement = true; } if (attrElement) { sendUnIndentedElement("attributes"); } else { sendEmptyElementEvent("attributes"); } if (namespaceAttribute) { sendIndentedElement("namespaceAttributes"); for (int i = 0; i < attrCount; i++) { Attr att = (Attr)atts[i]; String localpart = DOMUtil.getLocalName(att); String prefix = att.getPrefix(); if (localpart.equals(XMLSymbols.PREFIX_XMLNS) || prefix.equals(XMLSymbols.PREFIX_XMLNS)) { sendIndentedElement("attribute"); sendElementEvent("namespaceName", DOMUtil.getNamespaceURI(att)); sendElementEvent("localName", DOMUtil.getLocalName(att)); sendElementEvent("prefix", att.getPrefix()); sendElementEvent("normalizedValue", att.getValue()); sendElementEvent( "specified", String.valueOf(att.getSpecified())); sendElementEvent("attributeType"); // this property isn't relevent to PSVI sendElementEvent("references"); sendUnIndentedElement("attribute"); } } sendUnIndentedElement("namespaceAttributes"); } else { sendEmptyElementEvent("namespaceAttributes"); } } private void processPSVIElementDeclaration(XSElementDeclaration elem) { if (elem == null) return; sendIndentedElementWithID("psv:elementDeclaration", elem); sendElementEvent("psv:name", elem.getName()); sendElementEvent("psv:targetNamespace", elem.getNamespace()); processPSVITypeDefinitionOrRef( "psv:typeDefinition", elem.getTypeDefinition()); processPSVIScope("psv:scope", elem.getEnclosingCTDefinition(), elem.getScope()); processPSVIValueConstraint(elem.getConstraintType(), elem.getConstraintValue()); sendElementEvent("psv:nillable", String.valueOf(elem.getNillable())); processPSVIIdentityConstraintDefinitions(elem.getIdentityConstraints()); processPSVISubstitutionGroupAffiliation(elem); sendElementEvent( "psv:substitutionGroupExclusions", this.translateBlockOrFinal(elem.getSubstitutionGroupExclusions())); sendElementEvent( "psv:disallowedSubstitutions", this.translateBlockOrFinal(elem.getDisallowedSubstitutions())); sendElementEvent("psv:abstract", String.valueOf(elem.getAbstract())); processPSVIAnnotation(elem.getAnnotation()); sendUnIndentedElement("psv:elementDeclaration"); } private void processPSVIAttributeDeclaration(XSAttributeDeclaration attr) { if (attr == null) return; sendIndentedElementWithID("psv:attributeDeclaration", attr); sendElementEvent("psv:name", attr.getName()); sendElementEvent("psv:targetNamespace", attr.getNamespace()); processPSVITypeDefinitionOrRef( "psv:typeDefinition", attr.getTypeDefinition()); processPSVIScope("psv:scope", attr.getEnclosingCTDefinition(), attr.getScope()); processPSVIValueConstraint(attr.getConstraintType(), attr.getConstraintValue()); processPSVIAnnotation(attr.getAnnotation()); sendUnIndentedElement("psv:attributeDeclaration"); } private void processPSVIAttributeGroupDefinition(XSAttributeGroupDefinition ag) { if (ag == null) return; sendIndentedElementWithID("psv:attributeGroupDefinition", ag); sendElementEvent("psv:name", ag.getName()); sendElementEvent("psv:targetNamespace", ag.getNamespace()); processPSVIAttributeUses(ag.getAttributeUses()); processPSVIAttributeWildcard(ag.getAttributeWildcard()); processPSVIAnnotation(ag.getAnnotation()); sendUnIndentedElement("psv:attributeGroupDefinition"); } private void processPSVIModelGroupDefinition(XSModelGroupDefinition mgd) { if (mgd == null) { sendElementEvent("psv:modelGroupDefinition"); } else { sendIndentedElementWithID("psv:modelGroupDefinition", mgd); sendElementEvent("psv:name", mgd.getName()); sendElementEvent("psv:targetNamespace", mgd.getNamespace()); processPSVIModelGroup(mgd.getModelGroup()); processPSVIAnnotation(mgd.getAnnotation()); sendUnIndentedElement("psv:modelGroupDefinition"); } } private void processPSVIModelGroup(XSModelGroup mg) { if (mg == null) { sendElementEvent("psv:modelGroup"); } else { sendIndentedElement("psv:modelGroup"); sendElementEvent( "psv:compositor", this.translateCompositor(mg.getCompositor())); processPSVIParticles(mg.getParticles()); processPSVIAnnotation(mg.getAnnotation()); sendUnIndentedElement("psv:modelGroup"); } } private void processPSVINotationDeclaration(XSNotationDeclaration not) { if (not == null) { sendElementEvent("psv:notationDeclaration"); } else { sendIndentedElementWithID("psv:notationDeclaration", not); sendElementEvent("psv:name", not.getName()); sendElementEvent("psv:targetNamespace", not.getNamespace()); sendElementEvent("systemIdentifier", not.getSystemId()); sendElementEvent("publicIdentifier", not.getPublicId()); processPSVIAnnotation(not.getAnnotation()); sendUnIndentedElement("psv:notationDeclaration"); } } private void processPSVIIdentityConstraintDefinitions(XSNamedMap constraints) { if (constraints == null || constraints.getLength() == 0) { sendElementEvent("psv:identityConstraintDefinitions"); } else { sendIndentedElement("psv:identityConstraintDefinitions"); for (int i = 0; i < constraints.getLength(); i++) { XSIDCDefinition constraint = (XSIDCDefinition)constraints.item(i); sendIndentedElementWithID( "psv:identityConstraintDefinition", constraint); sendElementEvent("psv:name", constraint.getName()); sendElementEvent( "psv:targetNamespace", constraint.getNamespace()); sendElementEvent( "psv:identityConstraintCategory", this.translateCategory(constraint.getCategory())); sendIndentedElement("psv:selector"); processPSVIXPath(constraint.getSelectorStr()); sendUnIndentedElement("psv:selector"); processPSVIFields(constraint.getFieldStrs()); processPSVIElementRef( "psv:referencedKey", constraint.getRefKey()); processPSVIAnnotations(constraint.getAnnotations()); sendUnIndentedElement("psv:identityConstraintDefinition"); } sendUnIndentedElement("psv:identityConstraintDefinitions"); } } private void processPSVIFields(StringList fields) { if (fields == null || fields.getLength() == 0) { sendElementEvent("psv:fields"); } else { sendIndentedElement("psv:fields"); for (int i = 0; i < fields.getLength(); i++) { processPSVIXPath(fields.item(i)); } sendUnIndentedElement("psv:fields"); } } private void processPSVIXPath(String path) { sendIndentedElement("psv:xpath"); sendElementEvent("psv:xpath", path); sendUnIndentedElement("psv:xpath"); } private void processPSVIParticles(XSObjectList particles) { if (particles == null || particles.getLength() == 0) { sendElementEvent("psv:particles"); } else { sendIndentedElement("psv:particles"); for (int i = 0; i < particles.getLength(); i++) { processPSVIParticle((XSParticle)particles.item(i)); } sendUnIndentedElement("psv:particles"); } } private void processPSVIParticle(XSParticle part) { if (part == null) { sendElementEvent("psv:particle"); } else { sendIndentedElement("psv:particle"); sendElementEvent( "psv:minOccurs", String.valueOf(part.getMinOccurs())); sendElementEvent( "psv:maxOccurs", part.getMaxOccurs() == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded" : String.valueOf(part.getMaxOccurs())); sendIndentedElement("psv:term"); switch (part.getTerm().getType()) { case XSConstants.ELEMENT_DECLARATION : processPSVIElementDeclarationOrRef( (XSElementDeclaration)part.getTerm()); break; case XSConstants.MODEL_GROUP : processPSVIModelGroup((XSModelGroup)part.getTerm()); break; case XSConstants.WILDCARD : processPSVIWildcard((XSWildcard)part.getTerm()); break; } sendUnIndentedElement("psv:term"); sendUnIndentedElement("psv:particle"); } } private void processPSVIElementRef(String elementName, XSObject obj) { this.processPSVIElementRef(elementName, null, obj); } private void processPSVIElementRef( String elementName, Vector attributes, XSObject obj) { if (attributes == null) { attributes = new Vector(); } String ref = this.getID(obj); if (ref != null) { attributes.add("ref"); attributes.add(ref); attributes.add(XMLSymbols.fIDREFSymbol); } sendElementEvent(elementName, attributes, (XMLString) null); } private void processPSVIAttributeDeclarationOrRef(XSAttributeDeclaration att) { if (att == null) return; // for global attributes, and attributes that have already been printed, // we always want to print references if (att.getScope() == XSConstants.SCOPE_GLOBAL || fDefined.contains(this.getID(att))) { processPSVIAttributeDeclarationRef(att); } else { processPSVIAttributeDeclaration(att); } } private void processPSVIAttributeDeclarationRef(XSAttributeDeclaration att) { if (att == null) return; Vector attributes = new Vector(); attributes.add("name"); attributes.add(att.getName()); attributes.add(XMLSymbols.fCDATASymbol); if (att.getNamespace() != null) { attributes.add("tns"); attributes.add(att.getNamespace()); attributes.add(XMLSymbols.fCDATASymbol); } processPSVIElementRef("psv:attributeDeclaration", attributes, att); } // always prints a reference private void processPSVITypeDefinitionRef( String enclose, XSTypeDefinition type) { if (type == null) { sendElementEvent(enclose); return; } sendIndentedElement(enclose); if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { processPSVIElementRef("psv:complexTypeDefinition", type); } else if (type.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { processPSVIElementRef("psv:simpleTypeDefinition", type); } else { throw new IllegalArgumentException( "Unknown type definition value: " + type.getTypeCategory()); } sendUnIndentedElement(enclose); } // prints a reference if the type is anonymous and hasn't already been defined, // otherwise prints a definition private void processPSVITypeDefinitionOrRef( String enclose, XSTypeDefinition type) { if (type == null){ sendElementEvent(enclose); return; } // we'll check for anonymous types here, since they only occur in places where // a reference would be appropriate if (type.getAnonymous() && !fDefined.contains(this.getID(type))) { sendIndentedElement(enclose); processPSVITypeDefinition(type); sendUnIndentedElement(enclose); } else { processPSVITypeDefinitionRef(enclose, type); } } private void processPSVIElementDeclarationRef(XSElementDeclaration elem) { if (elem == null) return; processPSVIElementRef("psv:elementDeclaration", elem); } private void processPSVIElementDeclarationOrRef(XSElementDeclaration elem) { if (elem == null) return; // for global attributes, and attributes that have already been printed, // we always want to print references if (elem.getScope() == XSConstants.SCOPE_GLOBAL || fDefined.contains(this.getID(elem))) { processPSVIElementDeclarationRef(elem); } else { processPSVIElementDeclaration(elem); } } private void processPSVIScope( String enclose, XSComplexTypeDefinition enclosingCTD, short scope) { if (scope == XSConstants.SCOPE_ABSENT || scope == XSConstants.SCOPE_GLOBAL) { sendElementEvent(enclose, this.translateScope(scope)); } else { // XSConstants.SCOPE_LOCAL processPSVITypeDefinitionRef(enclose, enclosingCTD); } } private void processPSVIValueConstraint( short constraintType, String constraintValue) { if (constraintType == XSConstants.VC_NONE) { sendElementEvent("psv:valueConstraint"); } else { sendIndentedElement("psv:valueConstraint"); sendElementEvent("psv:variety", translateValueConstraintType(constraintType)); sendElementEvent("psv:value", constraintValue); sendUnIndentedElement("psv:valueConstraint"); } } private void processPSVISubstitutionGroupAffiliation(XSElementDeclaration elem) { if (elem.getSubstitutionGroupAffiliation() == null) { sendElementEvent("psv:substitutionGroupAffiliation"); } else { sendIndentedElement("psv:substitutionGroupAffiliation"); processPSVIElementRef("psv:elementDeclaration", elem.getSubstitutionGroupAffiliation()); sendUnIndentedElement("psv:substitutionGroupAffiliation"); } } /** * This method writes an empty element at the current indent level. * * @param tagname The name of the Element. * * @throws IOEXception */ private void sendEmptyElementEvent(String tagname) { this.sendEmptyElementEvent(tagname, null); } //sendEmptyElementEvent private void sendEmptyElementEvent(String tagname, Vector attributes) { this.sendIndent(); fDocumentHandler.emptyElement( createQName(tagname), createAttributes(attributes), null); this.sendNewLine(); } //sendEmptyElementEvent /** * This method writes an empty element at the current indent level. * * @param tagname The name of the Element. * * @throws IOEXception */ private void sendStartElementEvent(String tagname, Vector attributes) { fDocumentHandler.startElement( createQName(tagname), createAttributes(attributes), null); } //sendStartElementEvent /** * This method writes a closing tag at the current indent level. * * @param tagname The name of the Element. * * @throws IOEXception */ private void sendEndElementEvent(String tagname) { fDocumentHandler.endElement(this.createQName(tagname), null); } //sendEndElementEvent /** * This method write the element at the current indent level and increase * the one level of indentation. * * @param The name of the Element. * * @throws IOException */ private void sendIndentedElement(String tagName) { this.sendIndentedElement(tagName, null); } //sendIndentedElement private void sendIndentedElement(String tagName, Vector attributes) { this.sendIndent(); this.sendStartElementEvent(tagName, attributes); this.sendNewLine(); fIndent++; } //sendIndentedElement /** * This method write the element at the current indent level and decrease * one level of indentation. * * @param the name of the Element. * */ private void sendUnIndentedElement(String tagName) { fIndent--; this.sendIndent(); this.sendEndElementEvent(tagName); this.sendNewLine(); } //sendUnIndentedElement /** * Write the Element Information Item for each element appearing in the XML * document. One of the element information items is the value of the * [document element] property of the document information item, corresponding * to the root of the element tree, and all other element information items * are accessible by recursively following its [children] property. * * @elementName Name of the elment. * @elemmentValue Value of the element */ private void sendElementEvent(String elementName) { this.sendElementEvent(elementName, null, (XMLString) null); } //sendElementEvents private void sendElementEvent(String elementName, String elementValue) { this.sendElementEvent(elementName, null, elementValue); } //sendElementEvents private void sendElementEvent(String elementName, XMLString elementValue) { this.sendElementEvent(elementName, null, elementValue); } //sendElementEvents private void sendElementEvent( String elementName, Vector attributes, String elementValue) { XMLString text = elementValue == null ? null : new XMLString( elementValue.toCharArray(), 0, elementValue.length()); this.sendElementEvent(elementName, attributes, text); } private void sendElementEvent( String elementName, Vector attributes, XMLString elementValue) { if (elementValue == null || elementValue.length == 0) { if (attributes == null) { attributes = new Vector(); } attributes.add("xsi:nil"); attributes.add("true"); attributes.add(XMLSymbols.fCDATASymbol); this.sendEmptyElementEvent(elementName, attributes); } else { this.sendIndent(); this.sendStartElementEvent(elementName, attributes); fDocumentHandler.characters(elementValue, null); this.sendEndElementEvent(elementName); this.sendNewLine(); } } //sendElementEvents private void sendIndentedElementWithID(String elementName, XSObject obj) { String id = this.getID(obj); // since this method is called everytime we define something with an ID, // may as well mark the ID as defined here fDefined.add(id); Vector attributes = new Vector(); attributes.add("id"); attributes.add(id); attributes.add(XMLSymbols.fIDSymbol); sendIndentedElement(elementName, attributes); } private void sendIndent() { if (fIndent > fIndentChars.length) { fIndentChars = new char[fIndentChars.length * 2]; for (int i = 0; i < fIndentChars.length; i++) { fIndentChars[i] = '\t'; } } XMLString text = new XMLString(fIndentChars, 0, fIndent); fDocumentHandler.characters(text, null); } private void sendNewLine() { fDocumentHandler.characters(newLine, null); } private QName createQName(String rawname) { int index = rawname.indexOf(':'); String prefix, localpart; if (index == -1) { prefix = ""; localpart = rawname; } else { prefix = rawname.substring(0, index); localpart = rawname.substring(index + 1); } String uri = fPSVINamespaceContext.getURI(prefix); return new QName(prefix, localpart, rawname, uri); } private XMLAttributes createAttributes(Vector atts) { XMLAttributes attributes = new XMLAttributesImpl(); if (atts != null) { for (int i = 0; i < atts.size(); i += 3) { String rawname = (String)atts.elementAt(i); String value = (String)atts.elementAt(i + 1); String type = (String)atts.elementAt(i + 2); attributes.addAttribute(createQName(rawname), type, value); } } return attributes; } private String createID(XSObject obj) { String namespace = obj.getNamespace(); String prefix = fNamespaceContext.getPrefix(obj.getNamespace()); String name = obj.getName(); String type = this.translateType(obj.getType()); // must be anonymous if (name == null) { name = "anon_" + fAnonNum++; } // no namespace else if (namespace == null || namespace == XMLSymbols.EMPTY_STRING) { name = name + "." + fAnonNum++; } if (namespace == Constants.NS_XMLSCHEMA) { return name; } else { return (prefix == null ? "" : prefix + ".") + type + "." + name; } } private String getID(XSObject obj) { if (obj == null) return null; String id = (String)fIDMap.get(obj); if (id == null) { id = createID(obj); fIDMap.put(obj, id); } return id; } private String translateType(short type) { switch (type) { case XSConstants.TYPE_DEFINITION : return "type"; case XSConstants.ANNOTATION : return "annot"; case XSConstants.ATTRIBUTE_DECLARATION : return "attr"; case XSConstants.ATTRIBUTE_GROUP : return "ag"; case XSConstants.ATTRIBUTE_USE : return "au"; case XSConstants.ELEMENT_DECLARATION : return "elt"; case XSConstants.MODEL_GROUP_DEFINITION : return "mg"; case XSConstants.NOTATION_DECLARATION : return "not"; case XSConstants.IDENTITY_CONSTRAINT : return "idc"; default : return "unknown"; } } private String translateFacetKind(short kind) { switch (kind) { case XSSimpleTypeDefinition.FACET_WHITESPACE : return SchemaSymbols.ELT_WHITESPACE; case XSSimpleTypeDefinition.FACET_LENGTH : return SchemaSymbols.ELT_LENGTH; case XSSimpleTypeDefinition.FACET_MINLENGTH : return SchemaSymbols.ELT_MINLENGTH; case XSSimpleTypeDefinition.FACET_MAXLENGTH : return SchemaSymbols.ELT_MAXLENGTH; case XSSimpleTypeDefinition.FACET_TOTALDIGITS : return SchemaSymbols.ELT_TOTALDIGITS; case XSSimpleTypeDefinition.FACET_FRACTIONDIGITS : return SchemaSymbols.ELT_FRACTIONDIGITS; case XSSimpleTypeDefinition.FACET_PATTERN : return SchemaSymbols.ELT_PATTERN; case XSSimpleTypeDefinition.FACET_ENUMERATION : return SchemaSymbols.ELT_ENUMERATION; case XSSimpleTypeDefinition.FACET_MAXINCLUSIVE : return SchemaSymbols.ELT_MAXINCLUSIVE; case XSSimpleTypeDefinition.FACET_MAXEXCLUSIVE : return SchemaSymbols.ELT_MAXEXCLUSIVE; case XSSimpleTypeDefinition.FACET_MINEXCLUSIVE : return SchemaSymbols.ELT_MINEXCLUSIVE; case XSSimpleTypeDefinition.FACET_MININCLUSIVE : return SchemaSymbols.ELT_MININCLUSIVE; default : return "unknown"; } } private String translateVariety(short var) { switch (var) { case XSSimpleTypeDefinition.VARIETY_LIST : return "list"; case XSSimpleTypeDefinition.VARIETY_UNION : return "union"; case XSSimpleTypeDefinition.VARIETY_ATOMIC : return "atomic"; case XSSimpleTypeDefinition.VARIETY_ABSENT : return null; default : return "unknown"; } } private String translateConstraintType(short type) { switch (type) { case XSWildcard.NSCONSTRAINT_ANY : return "any"; // the spec says that when it's a list, the "type" shouldn't be there case XSWildcard.NSCONSTRAINT_LIST : return null; case XSWildcard.NSCONSTRAINT_NOT : return "not"; default : return "unknown"; } } private String translateValueConstraintType(short type) { switch (type) { case XSConstants.VC_DEFAULT : return "default"; case XSConstants.VC_FIXED : return "fixed"; default : return "unknown"; } } private String translateBlockOrFinal(short val) { String ret = ""; if ((val & XSConstants.DERIVATION_EXTENSION) != 0) { ret += SchemaSymbols.ATTVAL_EXTENSION; } if ((val & XSConstants.DERIVATION_LIST) != 0) { if (ret.length() != 0) ret += " "; ret += SchemaSymbols.ATTVAL_LIST; } if ((val & XSConstants.DERIVATION_RESTRICTION) != 0) { if (ret.length() != 0) ret += " "; ret += SchemaSymbols.ATTVAL_RESTRICTION; } if ((val & XSConstants.DERIVATION_UNION) != 0) { if (ret.length() != 0) ret += " "; ret += SchemaSymbols.ATTVAL_UNION; } if ((val & XSConstants.DERIVATION_SUBSTITUTION) != 0) { if (ret.length() != 0) ret += " "; ret += SchemaSymbols.ATTVAL_SUBSTITUTION; } return ret; } private String translateScope(short scope) { switch (scope) { case XSConstants.SCOPE_ABSENT : return null; case XSConstants.SCOPE_GLOBAL : return "global"; case XSConstants.SCOPE_LOCAL : return "local"; default : return "unknown"; } } private String translateCompositor(short comp) { switch (comp) { case XSModelGroup.COMPOSITOR_SEQUENCE : return SchemaSymbols.ELT_SEQUENCE; case XSModelGroup.COMPOSITOR_CHOICE : return SchemaSymbols.ELT_CHOICE; case XSModelGroup.COMPOSITOR_ALL : return SchemaSymbols.ELT_ALL; default : return "unknown"; } } private String translateContentType(short contentType) { switch (contentType) { case XSComplexTypeDefinition.CONTENTTYPE_ELEMENT : return "elementOnly"; case XSComplexTypeDefinition.CONTENTTYPE_EMPTY : return "empty"; case XSComplexTypeDefinition.CONTENTTYPE_MIXED : return "mixed"; case XSComplexTypeDefinition.CONTENTTYPE_SIMPLE : return "simple"; default : return "unknown"; } } private String translateProcessContents(short process) { switch (process) { case XSWildcard.PC_LAX : return SchemaSymbols.ATTVAL_LAX; case XSWildcard.PC_SKIP : return SchemaSymbols.ATTVAL_SKIP; case XSWildcard.PC_STRICT : return SchemaSymbols.ATTVAL_STRICT; default : return "unknown"; } } private String translateDerivation(short deriv) { switch (deriv) { case XSConstants.DERIVATION_EXTENSION : return SchemaSymbols.ELT_EXTENSION; case XSConstants.DERIVATION_LIST : return SchemaSymbols.ELT_LIST; case XSConstants.DERIVATION_RESTRICTION : return SchemaSymbols.ELT_RESTRICTION; case XSConstants.DERIVATION_SUBSTITUTION : return SchemaSymbols.ATTVAL_SUBSTITUTION; case XSConstants.DERIVATION_UNION : return SchemaSymbols.ELT_UNION; case XSConstants.DERIVATION_NONE : return null; default : return "unknown"; } } private String translateCategory(short cat) { switch (cat) { case XSIDCDefinition.IC_KEY : return SchemaSymbols.ELT_KEY; case XSIDCDefinition.IC_KEYREF : return SchemaSymbols.ELT_KEYREF; case XSIDCDefinition.IC_UNIQUE : return SchemaSymbols.ELT_UNIQUE; default : return "unknown"; } } private String translateOrdered(short ordered) { switch (ordered) { case XSSimpleTypeDefinition.ORDERED_FALSE : return "false"; case XSSimpleTypeDefinition.ORDERED_PARTIAL : return "partial"; case XSSimpleTypeDefinition.ORDERED_TOTAL : return "total"; default : return "unknown"; } } private String translateValidationAttempted(short val) { switch (val) { case ItemPSVI.VALIDATION_NONE : return "none"; case ItemPSVI.VALIDATION_PARTIAL : return "partial"; case ItemPSVI.VALIDATION_FULL : return "full"; default : return "unknown"; } } private String translateValidity(short val) { switch (val) { case ItemPSVI.VALIDITY_NOTKNOWN : return "notKnown"; case ItemPSVI.VALIDITY_VALID : return "valid"; case ItemPSVI.VALIDITY_INVALID : return "invalid"; default : return "unknown"; } } /** * Check whether the calling event is first in children list , * if yes print the <children>. */ private void checkForChildren() { if (!_elementState.empty()) { ElementState fElementState = (ElementState)_elementState.peek(); if (fElementState.isEmpty == true) { sendIndentedElement("children"); fElementState.isEmpty = false; } } else { sendIndentedElement("children"); _elementState.push(new ElementState(false)); } } //checkForChildren class ElementState { public boolean isEmpty; XMLAttributes fAttributes; public ElementState(XMLAttributes attributes) { fAttributes = attributes; isEmpty = true; } public ElementState(boolean value) { isEmpty = value; } public XMLAttributes getAttributes() { return fAttributes; } public void isEmpty(boolean value) { isEmpty = value; } } //class ElementState } // class PSVIWriter