protected Node processAttributeDeclaration( XSDAttributeDeclaration decl, Node parentNode, boolean isUse) throws RepositoryException { if (decl == null) { return null; } logger.debug( "Attribute declaration: '{0}' in ns '{1}' ", decl.getName(), decl.getTargetNamespace()); Node attributeDeclarationNode = parentNode.addNode(decl.getName(), XsdLexicon.ATTRIBUTE_DECLARATION); attributeDeclarationNode.setProperty(XsdLexicon.NC_NAME, decl.getName()); attributeDeclarationNode.setProperty(XsdLexicon.NAMESPACE, decl.getTargetNamespace()); if (decl.isGlobal() && !isUse) { registerForSymbolSpace( ATTRIBUTE_DECLARATIONS, decl.getTargetNamespace(), decl.getName(), attributeDeclarationNode.getIdentifier()); } XSDTypeDefinition type = decl.getType(); if (type != null) { attributeDeclarationNode.setProperty(XsdLexicon.TYPE_NAME, type.getName()); attributeDeclarationNode.setProperty(XsdLexicon.TYPE_NAMESPACE, type.getTargetNamespace()); } processAnnotation(decl.getAnnotation(), attributeDeclarationNode); processNonSchemaAttributes(type, attributeDeclarationNode); return attributeDeclarationNode; }
protected void processComplexTypeDefinition(XSDComplexTypeDefinition type, Node parentNode) throws RepositoryException { logger.debug("Complex type: '{0}' in ns '{1}' ", type.getName(), type.getTargetNamespace()); boolean isAnonymous = type.getName() == null; String nodeName = isAnonymous ? XsdLexicon.COMPLEX_TYPE : type.getName(); Node typeNode = parentNode.addNode(nodeName, XsdLexicon.COMPLEX_TYPE_DEFINITION); typeNode.setProperty(XsdLexicon.NAMESPACE, type.getTargetNamespace()); if (!isAnonymous) { typeNode.setProperty(XsdLexicon.NC_NAME, type.getName()); registerForSymbolSpace( TYPE_DEFINITIONS, type.getTargetNamespace(), type.getName(), typeNode.getIdentifier()); } XSDTypeDefinition baseType = type.getBaseType(); if (baseType == type) { // The base type is the anytype ... baseType = type.getSchema() .getSchemaForSchema() .resolveComplexTypeDefinition("http://www.w3.org/2001/XMLSchema", "anyType"); } if (baseType != null) { typeNode.setProperty(XsdLexicon.BASE_TYPE_NAME, baseType.getName()); typeNode.setProperty(XsdLexicon.BASE_TYPE_NAMESPACE, baseType.getTargetNamespace()); } typeNode.setProperty(XsdLexicon.ABSTRACT, type.isAbstract()); typeNode.setProperty(XsdLexicon.MIXED, type.isMixed()); @SuppressWarnings("unchecked") List<XSDProhibitedSubstitutions> blocks = type.getBlock(); processEnumerators(blocks, typeNode, XsdLexicon.BLOCK); @SuppressWarnings("unchecked") List<XSDSimpleFinal> finalFacets = type.getFinal(); processEnumerators(finalFacets, typeNode, XsdLexicon.FINAL); processComplexTypeContent(type.getContent(), typeNode); processAnnotation(type.getAnnotation(), typeNode); processNonSchemaAttributes(type, typeNode); }
/** * Return a collection of all types referenced by the attributes (XSDFeatures) of source. This * method is non-recursive (i.e. the list only contains direct references, not * references-of-references) Will not return null, but may return an empty set. This will return a * BO reference if the file has been deleted (or just doesn't exist). * * @param source The complex type to examine for references * @param includeAnonymous if true, the returned list will include anonymous inlined types as * well. These are not technically "referenced", however it allows this method to be used as a * way to get all non-primitive types used in any way by source * @return a Collection of XSDTypeDefinition (could be complex or simple type) instances -- no * duplicates */ public static Collection<XSDTypeDefinition> getAllReferencedTypes( XSDComplexTypeDefinition source, boolean includeAnonymous) { if (source == null) { return Collections.emptySet(); } List<XSDTypeDefinition> results = new ArrayList<XSDTypeDefinition>(); XSDTypeDefinition elementType = null; for (Iterator<XSDParticleContent> i = getChildElements(source).iterator(); i.hasNext(); ) { XSDFeature next = (XSDFeature) i.next(); elementType = getResolvedType(next); // Only add non-null, non-duplicate, non-primitive types. If includeAnonymous is false, // anonymous types should be filtered out as well if (elementType != null && !results.contains(elementType) && !XSDConstants.isSchemaForSchemaNamespace(elementType.getTargetNamespace()) && (includeAnonymous || elementType.eContainer() != next)) { results.add(elementType); } } return results; }
protected Node processElementDeclaration(XSDElementDeclaration decl, Node parentNode) throws RepositoryException { if (decl == null) { return null; } logger.debug( "Element declaration: '{0}' in ns '{1}' ", decl.getName(), decl.getTargetNamespace()); Node declarationNode; if (decl.getName() != null) { // Normal element declaration ... declarationNode = parentNode.addNode(decl.getName(), XsdLexicon.ELEMENT_DECLARATION); declarationNode.setProperty(XsdLexicon.NC_NAME, decl.getName()); declarationNode.setProperty(XsdLexicon.NAMESPACE, decl.getTargetNamespace()); } else { assert decl.isFeatureReference() : "expected element reference"; XSDElementDeclaration resolved = decl.getResolvedElementDeclaration(); declarationNode = parentNode.addNode(resolved.getName(), XsdLexicon.ELEMENT_DECLARATION); declarationNode.setProperty(XsdLexicon.REF_NAME, resolved.getName()); declarationNode.setProperty(XsdLexicon.REF_NAMESPACE, resolved.getTargetNamespace()); setReference( declarationNode, XsdLexicon.REF, ELEMENT_DECLARATION, resolved.getTargetNamespace(), resolved.getName()); } if (decl.isGlobal()) { registerForSymbolSpace( ELEMENT_DECLARATION, decl.getTargetNamespace(), decl.getName(), declarationNode.getIdentifier()); } declarationNode.setProperty(XsdLexicon.ABSTRACT, decl.isAbstract()); declarationNode.setProperty(XsdLexicon.NILLABLE, decl.isNillable()); XSDTypeDefinition type = decl.getType(); if (type != null) { declarationNode.setProperty(XsdLexicon.TYPE_NAME, type.getName()); declarationNode.setProperty(XsdLexicon.TYPE_NAMESPACE, type.getTargetNamespace()); setReference( declarationNode, XsdLexicon.TYPE_REFERENCE, TYPE_DEFINITIONS, type.getTargetNamespace(), type.getName()); } if (decl.getAnonymousTypeDefinition() == type) { // It's anonymous, so we need to process the definition here ... if (type instanceof XSDComplexTypeDefinition) { processComplexTypeDefinition((XSDComplexTypeDefinition) type, declarationNode); } else if (type instanceof XSDSimpleTypeDefinition) { processSimpleTypeDefinition((XSDSimpleTypeDefinition) type, declarationNode); } } processEnumerator(decl.getForm(), declarationNode, XsdLexicon.FORM); @SuppressWarnings("unchecked") List<XSDProhibitedSubstitutions> finals = decl.getLexicalFinal(); processEnumerators(finals, declarationNode, XsdLexicon.FINAL); @SuppressWarnings("unchecked") List<XSDProhibitedSubstitutions> blocks = decl.getBlock(); processEnumerators(blocks, declarationNode, XsdLexicon.BLOCK); processAnnotation(decl.getAnnotation(), declarationNode); processNonSchemaAttributes(type, declarationNode); return declarationNode; }
protected void processTypeFacets( XSDSimpleTypeDefinition type, Node typeNode, XSDTypeDefinition baseType) throws RepositoryException { if (baseType == null) { baseType = type.getBaseType(); } if (baseType == type) { // The base type is the anytype ... baseType = type.getSchema() .getSchemaForSchema() .resolveSimpleTypeDefinition("http://www.w3.org/2001/XMLSchema", "anyType"); } if (baseType != null) { typeNode.setProperty(XsdLexicon.BASE_TYPE_NAME, baseType.getName()); typeNode.setProperty(XsdLexicon.BASE_TYPE_NAMESPACE, baseType.getTargetNamespace()); setReference( typeNode, XsdLexicon.BASE_TYPE_REFERENCE, TYPE_DEFINITIONS, baseType.getTargetNamespace(), baseType.getName()); } processFacet( type.getEffectiveMaxLengthFacet(), typeNode, XsdLexicon.MAX_LENGTH, PropertyType.LONG); processFacet(type.getMaxLengthFacet(), typeNode, XsdLexicon.MAX_LENGTH, PropertyType.LONG); processFacet( type.getEffectiveMinLengthFacet(), typeNode, XsdLexicon.MIN_LENGTH, PropertyType.LONG); processFacet(type.getMinLengthFacet(), typeNode, XsdLexicon.MIN_LENGTH, PropertyType.LONG); processFacet( type.getEffectiveMaxFacet(), typeNode, XsdLexicon.MAX_VALUE_EXCLUSIVE, PropertyType.LONG); processFacet( type.getMaxExclusiveFacet(), typeNode, XsdLexicon.MAX_VALUE_EXCLUSIVE, PropertyType.LONG); processFacet( type.getEffectiveMinFacet(), typeNode, XsdLexicon.MIN_VALUE_EXCLUSIVE, PropertyType.LONG); processFacet( type.getMinExclusiveFacet(), typeNode, XsdLexicon.MIN_VALUE_EXCLUSIVE, PropertyType.LONG); processFacet( type.getMaxInclusiveFacet(), typeNode, XsdLexicon.MAX_VALUE_INCLUSIVE, PropertyType.LONG); processFacet( type.getMinInclusiveFacet(), typeNode, XsdLexicon.MIN_VALUE_INCLUSIVE, PropertyType.LONG); processFacet( type.getEffectiveTotalDigitsFacet(), typeNode, XsdLexicon.TOTAL_DIGITS, PropertyType.LONG); processFacet(type.getTotalDigitsFacet(), typeNode, XsdLexicon.TOTAL_DIGITS, PropertyType.LONG); processFacet( type.getEffectiveFractionDigitsFacet(), typeNode, XsdLexicon.FRACTION_DIGITS, PropertyType.LONG); processFacet( type.getFractionDigitsFacet(), typeNode, XsdLexicon.FRACTION_DIGITS, PropertyType.LONG); processFacet( type.getEffectiveWhiteSpaceFacet(), typeNode, XsdLexicon.WHITESPACE, PropertyType.STRING); processFacet(type.getWhiteSpaceFacet(), typeNode, XsdLexicon.WHITESPACE, PropertyType.STRING); processFacet( type.getEffectivePatternFacet(), typeNode, XsdLexicon.PATTERN, PropertyType.STRING); @SuppressWarnings("unchecked") List<XSDPatternFacet> patternFacets = type.getPatternFacets(); processFacetsList(patternFacets, typeNode, XsdLexicon.PATTERN); processFacet( type.getEffectiveEnumerationFacet(), typeNode, XsdLexicon.ENUMERATED_VALUES, PropertyType.STRING); @SuppressWarnings("unchecked") List<XSDEnumerationFacet> enumFacets = type.getEnumerationFacets(); processFacetsList(enumFacets, typeNode, XsdLexicon.ENUMERATED_VALUES); @SuppressWarnings("unchecked") List<XSDSimpleFinal> finalFacets2 = type.getFinal(); processEnumerators(finalFacets2, typeNode, XsdLexicon.FINAL); processAnnotation(type.getAnnotation(), typeNode); }
/** * Creates an {@link AttributeType} that matches the xsd type definition as much as possible. * * <p>The original type definition given by the {@link XSDTypeDefinition} is kept as * AttributeType's metadata stored as a "user data" property using <code>XSDTypeDefinition.class * </code> as key. * * <p>If it is a complex attribute, it will contain all the properties declared in the <code> * typeDefinition</code>, as well as all the properties declared in its super types. TODO: handle * the case where the extension mechanism is restriction. * * @param assignedName * @param typeDefinition * @return */ private AttributeType createType( final Name assignedName, final XSDTypeDefinition typeDefinition, CoordinateReferenceSystem crs, boolean anonymous) { AttributeType attType; // ///////// if (processingTypes.contains(assignedName)) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Recursion found for type " + assignedName + ". Proxying it."); } attType = createProxiedType( assignedName, typeDefinition, anonymous ? anonTypeRegistry : typeRegistry); return attType; } processingTypes.push(assignedName); // ////////// final XSDTypeDefinition baseType = typeDefinition.getBaseType(); AttributeType superType = null; if (baseType != null) { String targetNamespace = baseType.getTargetNamespace(); String name = baseType.getName(); if (name != null) { Name baseTypeName = new NameImpl(targetNamespace, name); superType = getAttributeType(baseTypeName, baseType, crs); } } else { LOGGER.warning(assignedName + " has no super type"); } if (typeDefinition instanceof XSDComplexTypeDefinition) { XSDComplexTypeDefinition complexTypeDef; complexTypeDef = (XSDComplexTypeDefinition) typeDefinition; boolean includeParents = true; List<XSDElementDeclaration> children = Schemas.getChildElementDeclarations(typeDefinition, includeParents); final Collection<PropertyDescriptor> schema = new ArrayList<PropertyDescriptor>(children.size()); XSDElementDeclaration childDecl; AttributeDescriptor descriptor; for (Iterator it = children.iterator(); it.hasNext(); ) { childDecl = (XSDElementDeclaration) it.next(); try { descriptor = createAttributeDescriptor(complexTypeDef, childDecl, crs); } catch (NoSuchElementException e) { String msg = "Failed to create descriptor for '" + childDecl.getTargetNamespace() + "#" + childDecl.getName() + " from container '" + typeDefinition.getTargetNamespace() + "#" + typeDefinition.getName() + "'"; NoSuchElementException nse = new NoSuchElementException(msg); nse.initCause(e); throw nse; } schema.add(descriptor); } if (includeAttributes) { for (XSDAttributeUse attgcontent : complexTypeDef.getAttributeUses()) { XSDAttributeDeclaration att = attgcontent.getContent(); descriptor = createAttributeDescriptor( getXmlAttributeType(), null, new NameImpl(null, "@" + att.getName()), 0, 1, false, null); schema.add(descriptor); } } // set substitution group for descriptors here for (XSDElementDeclaration elemDecl : children) { if (elemDecl.isElementDeclarationReference()) { elemDecl = elemDecl.getResolvedElementDeclaration(); } PropertyDescriptor att = null; for (PropertyDescriptor desc : schema) { if (desc.getName().getLocalPart().equals(elemDecl.getName()) && desc.getName().getNamespaceURI().equals(elemDecl.getTargetNamespace())) { att = desc; break; } } setSubstitutionGroup(complexTypeDef, elemDecl, att, crs); } attType = createComplexAttributeType(assignedName, schema, complexTypeDef, superType); } else { Class<?> binding = String.class; boolean isIdentifiable = false; boolean isAbstract = false; List<Filter> restrictions = Collections.emptyList(); InternationalString description = null; attType = typeFactory.createAttributeType( assignedName, binding, isIdentifiable, isAbstract, restrictions, superType, description); } attType.getUserData().put(XSDTypeDefinition.class, typeDefinition); processingTypes.pop(); // even if the type is anonymous, it still has to be registered somewhere because // it's needed for the proxied types to find them. That's why we have 2 registries, // typeRegistry // and anonTypeRegistry. TypeRegistry is the global one, since anonymous types are meant to // be // local and shouldn't be searchable. register(attType, anonymous); return attType; }
/** * If the type of elemDecl is annonymous creates a new type with the same name than the atrribute * and returns it. If it is not anonymous, looks it up on the registry and in case the type does * not exists in the registry uses a proxy. * * @param elemDecl * @return */ private AttributeType getTypeOf(XSDElementDeclaration elemDecl, CoordinateReferenceSystem crs) { XSDTypeDefinition typeDefinition; // TODO REVISIT, I'm not sure this is the way to find out if the // element's type is defined in line (an thus no need to register it // as a global type) if (elemDecl.isElementDeclarationReference()) { elemDecl = elemDecl.getResolvedElementDeclaration(); } boolean hasToBeRegistered = false; typeDefinition = elemDecl.getAnonymousTypeDefinition(); if (typeDefinition == null) { // anonymous types already has type definition inline in the element // so the handling is different hasToBeRegistered = true; typeDefinition = elemDecl.getTypeDefinition(); } if (typeDefinition == null) { // last resort.. look in the lazy schemas QName qname = Types.toQName(Types.typeName(elemDecl.getTargetNamespace(), elemDecl.getName())); for (SchemaIndex schemaIndex : schemas) { elemDecl = schemaIndex.getElementDeclaration(qname); if (elemDecl != null) { break; } } if (elemDecl != null) { if (elemDecl.isElementDeclarationReference()) { elemDecl = elemDecl.getResolvedElementDeclaration(); } typeDefinition = elemDecl.getAnonymousTypeDefinition(); if (typeDefinition == null) { typeDefinition = elemDecl.getTypeDefinition(); } } } if (typeDefinition == null) { String msg = "The element declaration " + elemDecl.getTargetNamespace() + "#" + elemDecl.getName() + " has a null type definition, can't continue, fix it on the schema"; LOGGER.warning(msg); throw new NoSuchElementException(msg); } AttributeType type; if (hasToBeRegistered) { String targetNamespace = typeDefinition.getTargetNamespace(); String name = typeDefinition.getName(); Name typeName = Types.typeName(targetNamespace, name); type = getAttributeType(typeName, typeDefinition, crs); if (type == null) { type = createType(typeName, typeDefinition, crs, false); } } else { String name = elemDecl.getName(); String targetNamespace = elemDecl.getTargetNamespace(); Name overrideName = Types.typeName(targetNamespace, name); type = createType(overrideName, typeDefinition, crs, true); } return type; }
private void setSubstitutionGroup( XSDComplexTypeDefinition container, XSDElementDeclaration elemDecl, PropertyDescriptor descriptor, CoordinateReferenceSystem crs) { if (descriptor.getUserData().get("substitutionGroup") != null) { // this has been done before return; } List<AttributeDescriptor> substitutionGroup = new ArrayList<AttributeDescriptor>(); descriptor.getUserData().put("substitutionGroup", substitutionGroup); int minOccurs = Schemas.getMinOccurs(container, elemDecl); int maxOccurs = Schemas.getMaxOccurs(container, elemDecl); boolean nillable = elemDecl.isNillable(); Iterator substitutions = elemDecl.getSubstitutionGroup().iterator(); XSDElementDeclaration sub; while (substitutions.hasNext()) { sub = (XSDElementDeclaration) substitutions.next(); if (!(sub.getName().equals(elemDecl.getName())) || !(sub.getTargetNamespace().equals(elemDecl.getTargetNamespace()))) { Name elemName = Types.typeName(sub.getTargetNamespace(), sub.getName()); AttributeType type = getTypeOf(sub, crs); if (type != null) { substitutionGroup.add( createAttributeDescriptor(type, crs, elemName, minOccurs, maxOccurs, nillable, null)); } } } XSDTypeDefinition typeDef = elemDecl.getType(); if (typeDef instanceof XSDComplexTypeDefinition) { Name typeName = Types.typeName(typeDef.getTargetNamespace(), typeDef.getName()); AttributeType attType = typeRegistry.get(typeName); if (!processingTypes.contains(typeName)) { // ignore processingTypes to avoid endless recursion if (attType == null || attType instanceof AbstractLazyComplexTypeImpl) { // type is not yet registered or it's a lazy type from foundation types // recreate lazy type to ensure everything is loaded // it will eventually call this method so substitution groups will be set then LOGGER.finest("Creating attribute type " + typeName); createType(typeName, typeDef, crs, false); LOGGER.finest("Registering attribute type " + typeName); } else if (attType instanceof ComplexType) { // ensure substitution groups are set for children including non lazy foundation // types ComplexType complexType = (ComplexType) attType; Collection<PropertyDescriptor> children = complexType.getDescriptors(); List<XSDParticle> childParticles = Schemas.getChildElementParticles(typeDef, true); for (XSDParticle particle : childParticles) { XSDElementDeclaration element = (XSDElementDeclaration) particle.getContent(); if (element.isElementDeclarationReference()) { element = element.getResolvedElementDeclaration(); } PropertyDescriptor childDesc = null; for (PropertyDescriptor desc : children) { if (desc.getName().getLocalPart().equals(element.getName()) && desc.getName().getNamespaceURI().equals(element.getTargetNamespace())) { childDesc = desc; break; } } if (childDesc != null) { setSubstitutionGroup((XSDComplexTypeDefinition) typeDef, element, childDesc, crs); } } } } } }
public void encode(Object object, QName name, ContentHandler handler) throws IOException, SAXException { // maintain a stack of (encoding,element declaration pairs) Stack encoded = null; try { serializer = handler; if (!inline) { serializer.startDocument(); } if (namespaceAware) { // write out all the namespace prefix value mappings for (Enumeration e = namespaces.getPrefixes(); e.hasMoreElements(); ) { String prefix = (String) e.nextElement(); String uri = namespaces.getURI(prefix); if ("xml".equals(prefix)) { continue; } serializer.startPrefixMapping(prefix, uri); } for (Iterator itr = schema.getQNamePrefixToNamespaceMap().entrySet().iterator(); itr.hasNext(); ) { Map.Entry entry = (Map.Entry) itr.next(); String pre = (String) entry.getKey(); String ns = (String) entry.getValue(); if (XSDUtil.SCHEMA_FOR_SCHEMA_URI_2001.equals(ns)) { continue; } serializer.startPrefixMapping(pre, ns); serializer.endPrefixMapping(pre); namespaces.declarePrefix((pre != null) ? pre : "", ns); } // ensure a default namespace prefix set if (namespaces.getURI("") == null) { namespaces.declarePrefix("", schema.getTargetNamespace()); } } // create the document DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); try { doc = docFactory.newDocumentBuilder().newDocument(); } catch (ParserConfigurationException e) { new IOException().initCause(e); } encoded = new Stack(); // add the first entry XSDElementDeclaration root = index.getElementDeclaration(name); if (root == null) { // check for context hint, this is only used when running the encoder // in test mode QName typeDefintion = (QName) context.getComponentInstance("http://geotools.org/typeDefinition"); if (typeDefintion != null) { XSDTypeDefinition type = index.getTypeDefinition(typeDefintion); if (type == null) { throw new NullPointerException(); } // create a mock element declaration root = XSDFactory.eINSTANCE.createXSDElementDeclaration(); root.setName(name.getLocalPart()); root.setTargetNamespace(name.getNamespaceURI()); root.setTypeDefinition(type); } } if (root == null) { String msg = "Could not find element declaration for:" + name; throw new IllegalArgumentException(msg); } encoded.add(new EncodingEntry(object, root, null)); while (!encoded.isEmpty()) { EncodingEntry entry = (EncodingEntry) encoded.peek(); if (entry.encoding != null) { // element has been started, get the next child if (!entry.children.isEmpty()) { Object[] child = (Object[]) entry.children.get(0); XSDElementDeclaration element = (XSDElementDeclaration) child[0]; Iterator itr = (Iterator) child[1]; if (itr.hasNext()) { Object next = itr.next(); if (next == null) { logger.warning("Iterator returned null for " + element.getName()); } // here we check for instanceof EncoderDelegate if (next instanceof EncoderDelegate) { // do not add entry to the stack, just delegate to encode try { ((EncoderDelegate) next).encode(handler); } catch (Exception e) { throw new RuntimeException(e); } } else { // add the next object to be encoded to the stack encoded.push(new EncodingEntry(next, element, entry)); } } else { // iterator done, close it Object source = child[2]; closeIterator(itr, source); // this child is done, remove from child list entry.children.remove(0); } } else { // no more children, finish the element end(entry.encoding); encoded.pop(); // clean up the entry entry.object = null; entry.element = null; entry.encoding = null; entry.children = null; entry.parent = null; } } else { // start the encoding of the entry // first make sure the element is not abstract if (entry.element.isAbstract()) { // look for a non abstract substitute - substitution groups are subject to // changes over time, so we make a copy to avoid being hit with a // ConcurrentModificationException List sub = safeCopy(entry.element.getSubstitutionGroup()); if (sub.size() > 0) { // match up by type List matches = new ArrayList(); for (Iterator s = sub.iterator(); s.hasNext(); ) { XSDElementDeclaration e = (XSDElementDeclaration) s.next(); if (e == null || e.equals(entry.element)) { continue; } if (e.getName() == null) { continue; } // look up hte binding Binding binding = bindingLoader.loadBinding( new QName(e.getTargetNamespace(), e.getName()), context); if (binding == null) { // try the type XSDTypeDefinition type = e.getType(); if (type == null || type.getName() == null) { continue; } binding = bindingLoader.loadBinding( new QName(type.getTargetNamespace(), type.getName()), context); } if (binding == null) { continue; } if (binding.getType() == null) { logger.warning("Binding: " + binding.getTarget() + " returns null type."); continue; } // match up the type if (binding.getType().isAssignableFrom(entry.object.getClass())) { // we have a match, store as an (element,binding) tuple matches.add(new Object[] {e, binding}); } } // if one, we are gold if (matches.size() == 1) { entry.element = (XSDElementDeclaration) ((Object[]) matches.get(0))[0]; } // if multiple we have a problem else if (matches.size() > 0) { if (logger.isLoggable(Level.FINE)) { StringBuffer msg = new StringBuffer("Found multiple non-abstract bindings for "); msg.append(entry.element.getName()).append(": "); for (Iterator m = matches.iterator(); m.hasNext(); ) { msg.append(m.next().getClass().getName()); msg.append(", "); } logger.fine(msg.toString()); } // try sorting by the type of the binding Collections.sort( matches, new Comparator() { public int compare(Object o1, Object o2) { Object[] match1 = (Object[]) o1; Object[] match2 = (Object[]) o2; Binding b1 = (Binding) match1[1]; Binding b2 = (Binding) match2[1]; if (b1.getType() != b2.getType()) { if (b2.getType().isAssignableFrom(b1.getType())) { return -1; } if (b1.getType().isAssignableFrom(b2.getType())) { return 1; } } // use binding comparability if (b1 instanceof Comparable) { return ((Comparable) b1).compareTo(b2); } if (b2 instanceof Comparable) { return -1 * ((Comparable) b2).compareTo(b1); } return 0; } }); } if (matches.size() > 0) { entry.element = (XSDElementDeclaration) ((Object[]) matches.get(0))[0]; } // if zero, just use the abstract element } } if (entry.element.isAbstract()) { logger.fine(entry.element.getName() + " is abstract"); } entry.encoding = entry.parent != null ? (Element) encode(entry.object, entry.element, entry.parent.element.getType()) : (Element) encode(entry.object, entry.element); // add any more attributes List attributes = index.getAttributes(entry.element); for (Iterator itr = attributes.iterator(); itr.hasNext(); ) { XSDAttributeDeclaration attribute = (XSDAttributeDeclaration) itr.next(); // do not encode the attribute if it has already been // encoded by the parent String ns = attribute.getTargetNamespace(); String local = attribute.getName(); if ((entry.encoding.getAttributeNS(ns, local) != null) && !"".equals(entry.encoding.getAttributeNS(ns, local))) { continue; } // get the object(s) for this attribute GetPropertyExecutor executor = new GetPropertyExecutor(entry.object, attribute); BindingVisitorDispatch.walk(object, bindingWalker, entry.element, executor, context); if (executor.getChildObject() != null) { // encode the attribute Attr attr = (Attr) encode(executor.getChildObject(), attribute); if (attr != null) { entry.encoding.setAttributeNodeNS(attr); } } } // write out the leading edge of the element if (schemaLocations != null) { // root element, add schema locations if set if (!schemaLocations.isEmpty()) { // declare the schema instance mapping serializer.startPrefixMapping("xsi", XSDUtil.SCHEMA_INSTANCE_URI_2001); serializer.endPrefixMapping("xsi"); namespaces.declarePrefix("xsi", XSDUtil.SCHEMA_INSTANCE_URI_2001); StringBuffer schemaLocation = new StringBuffer(); for (Iterator e = schemaLocations.entrySet().iterator(); e.hasNext(); ) { Map.Entry tuple = (Map.Entry) e.next(); String namespaceURI = (String) tuple.getKey(); String location = (String) tuple.getValue(); schemaLocation.append(namespaceURI + " " + location); if (e.hasNext()) { schemaLocation.append(" "); } } entry.encoding.setAttributeNS( XSDUtil.SCHEMA_INSTANCE_URI_2001, "xsi:schemaLocation", schemaLocation.toString()); } schemaLocations = null; } start(entry.encoding, entry.element); // TODO: this method of getting at properties wont maintain order very well, need // to come up with a better system that is capable of hanlding feature types for (Iterator pe = propertyExtractors.iterator(); pe.hasNext(); ) { PropertyExtractor propertyExtractor = (PropertyExtractor) pe.next(); if (propertyExtractor.canHandle(entry.object)) { List extracted = propertyExtractor.properties(entry.object, entry.element); O: for (Iterator e = extracted.iterator(); e.hasNext(); ) { Object[] tuple = (Object[]) e.next(); XSDParticle particle = (XSDParticle) tuple[0]; XSDElementDeclaration child = (XSDElementDeclaration) particle.getContent(); // check for a comment if ((child != null) && (COMMENT.getNamespaceURI().equals(child.getTargetNamespace())) && COMMENT.getLocalPart().equals(child.getName())) { comment(child.getElement()); continue; } if (child.isElementDeclarationReference()) { child = child.getResolvedElementDeclaration(); } // do not encode the element if the parent has already // been encoded by the parent String ns = child.getTargetNamespace(); String local = child.getName(); for (int i = 0; i < entry.encoding.getChildNodes().getLength(); i++) { Node node = entry.encoding.getChildNodes().item(i); if (node instanceof Element) { if (ns != null) { if (ns.equals(node.getNamespaceURI()) && local.equals(node.getLocalName())) { continue O; } } else { if (local.equals(node.getLocalName())) { continue O; } } } } Object obj = tuple[1]; if (obj == null) { if (particle.getMinOccurs() == 0) { // cool } else { // log an error logger.fine("Property " + ns + ":" + local + " not found but minoccurs > 0 "); } // skip this regardless continue; } // figure out the maximum number of occurences int maxOccurs = 1; if (particle.isSetMaxOccurs()) { maxOccurs = particle.getMaxOccurs(); } else { // look the containing group if (particle.eContainer() instanceof XSDModelGroup) { XSDModelGroup group = (XSDModelGroup) particle.eContainer(); if (group.eContainer() instanceof XSDParticle) { XSDParticle cParticle = (XSDParticle) group.eContainer(); if (cParticle.isSetMaxOccurs()) { maxOccurs = cParticle.getMaxOccurs(); } } } } if ((maxOccurs == -1) || (maxOccurs > 1)) { // may have a collection or array, unwrap it Iterator iterator = null; if (obj instanceof Iterator) { iterator = (Iterator) obj; } else if (obj.getClass().isArray()) { Object[] array = (Object[]) obj; iterator = Arrays.asList(array).iterator(); } else if (obj instanceof Collection) { Collection collection = (Collection) obj; iterator = collection.iterator(); } else if (obj instanceof FeatureCollection) { FeatureCollection collection = (FeatureCollection) obj; iterator = collection.iterator(); } else { iterator = new SingleIterator(obj); } entry.children.add(new Object[] {child, iterator, obj}); } else { // only one, just add the object entry.children.add(new Object[] {child, new SingleIterator(obj), obj}); } } } } } } if (!inline) { serializer.endDocument(); } } finally { // cleanup index.destroy(); // close any iterators still present in the stack, this will only occur in an exception // case if (encoded != null) { while (!encoded.isEmpty()) { EncodingEntry entry = (EncodingEntry) encoded.pop(); if (!entry.children.isEmpty()) { Object[] child = (Object[]) entry.children.get(0); Iterator itr = (Iterator) child[1]; try { closeIterator(itr, child[2]); } catch (Exception e) { // ignore, we are already in an error case. } } } } // TODO: there are probably other refences to elements of XSDScheam objects, we should // kill them too } }