Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


Clean Up Your Schema for SOAP : Page 3

As your repository of schemas grows, you need tools to manipulate and manage your schemas. The Eclipse XSD Schema Infoset Model has powerful querying and editing capabilities. This article shows you how to update a schema for use with SOAP by automatically converting attribute uses into element declarations.




Application Security Testing: An Integral Part of DevOps

Creating Element Declarations
Once we've found some complexTypes that we want to update, we need to get concrete. For each complexType we'll iterate over the getAttributeContents() list of concrete attribute uses that the type has. For each attribute use we first ensure that we're pointing at the real declaration of the attribute—even if it's a reference to a declaration elsewhere. Then we want to create an elementDeclaration that has the same name and type as each attribute use—this turns out to be quite straightforward to do. We'll also put the elementDeclaration inside a new particle's getContents(), since we will want to add this particle to our complexType later.

if (attrDecl.isAttributeDeclarationReference()) attrDecl = attrDecl.getResolvedAttributeDeclaration(); // Create a blank element and simply copy over the // pertient data about the attribute XSDElementDeclaration elemDecl = XSDFactory.eINSTANCE.createXSDElementDeclaration(); elemDecl.setName(attrDecl.getName()); elemDecl.setTypeDefinition(attrType); // Note that since an annotation's elements are only modeled // in the concrete tree that we must explicitly ask to clone them if (null != attrDecl.getAnnotation()) { cloneAnnotation(attrDecl, elemDecl); } // Wrap this element in a particle XSDParticle particle = XSDFactory.eINSTANCE.createXSDParticle(); particle.setContent(elemDecl);

This is an area that clearly shows the difference between the concrete model and the abstract model. You may be wondering what a 'particle' is if you're looking at your schemaDocument.xsd files, since you probably don't see any xsd:particle elements. You can read the specification for a particle, although it's quite detailed. A particle is essentially the abstract container of an element declaration, model group, or any (wildcard); the particle is what defines it's min/maxOccurs constraints at that particular place in the schema. Since the Model can express both the concrete and abstract representations of a schema, it's easy to work with either kind of representation.

Annotations are the one kind of schema component that are only modeled in the concrete representation of the model, so they require slightly special handling. In this code sample, we will copy over any annotations from the attribute declaration into the new element declaration we just created. We use the DOM cloneNode() method to actually clone or copy over the contents of the annotation component, and then add the annotation itself to the new element declaration.

XSDAnnotation oldAnnotation = attrDecl.getAnnotation(); XSDAnnotation newAnnotation = XSDFactory.eINSTANCE.createXSDAnnotation(); try { Element oldAnnElem = oldAnnotation.getElement(); // Use the DOM method to do a deep clone of the element Element newAnnElem = (Element)oldAnnElem.cloneNode(true); newAnnotation.setElement(newAnnElem); elemDecl.setAnnotation(newAnnotation); } catch (Exception e) { // Report the error and return }

Now that we've got a new element declaration to replace our attribute use, we need to swap the two in our complexType component. Since we were careful to use the concrete containment relationship of complexType.getAttributeContents() in our loop, we can simply go add the new elementDeclaration, and then call attrContentsIter.remove() to remove the actual attribute use from our type.

// Use this concrete relationship, since we're going to // actually remove the attributes from this type for (ListIterator iter = complexType.getAttributeContents().listIterator(); iter.hasNext(); /* no-op */ ) { if (changeAttributeIntoElement(complexType, (XSDAttributeGroupContent)iter.next(), changedAttrs)) { // Note that list manipulation calls like remove() // will only work properly on concrete lists; // attempting to manipulate 'abstract' lists will // either throw an exception or will silently fail iter.remove(); } else { // Report the error and continue... }

Writing Out the Schema
The MakeSoapCompatible sample program will print its status to System.out as it executes. If we detect that there are no attributes actively used in the schema, we report that no changes were made, and exit. Otherwise, we write out a modified schema document to a new name, and report our status: either a list of attributes successfully changed into elements, or a warning about which attributes had name conflicts, and were left unchanged.

Presuming that we've changed at least some attribute declarations into equivalent element declarations, we want to save the schema for later use with your SOAP application. The EMF framework that the Model is built on top of provides Resource handling services for loading and saving schema documents in a variety of ways. This code sample shows one very simple way to serialize directly to a URI, in this case an output file on disk named after our original input file.

File outFile = new File(newLocation); FileOutputStream fos = new FileOutputStream(outFile); // Ensure that the abstract model is synchronized with the // concrete tree: this will ensure that the Model has // updated the concrete Element in the schema document // with any changes that may have been made in the // abstract model schema.updateElement(); // Simply ask the XSDResourceImpl to serialize the schema to // a document for us; this is just one way we can easily use // the XSD/EMF framework to manage resources for us XSDResourceImpl.serialize(fos, schema.getElement()); fos.close();

As we've seen, performing a conceptually simple editing operation on schema documents (turning attributes into elements) can entail a fair amount of work. However the power of the Schema Infoset Model's representation of both the abstract Infoset of a schema and its concrete representation of the schema documents make this a manageable task. The Model also includes simple tools for loading and saving schema documents to a variety of sources, making it a complete solution for managing your schema repository programmatically.

Some users might ask, "Why not use XSLT or another XML-aware application to edit schema documents?" While XSLT can easily process the concrete model of a set of schema documents, it can't easily see any of the abstract relationships within the overall schema that they represent. For example, suppose that you need to update any enumerated simpleTypes to include a new 'UNK' enumeration value meaning unknown. Of course, you only want to update enumerations that fit this format of using strings of length 3; you would not want to update numeric or other enumerations.

While XSLT could find all of the simpleType declarations, it cannot understand the relationship between types and base types, or easily evaluate the meanings of facets on those types. The Model's representation of the abstract Infoset relationships within a schema includes things like simpleType.getEffectiveEnumerationFacets() which takes into account base types, references, and other relationships within the schema. It will return the complete list of enumerations on that simpleType that you can easily query and update with your new value, if appropriate. The Model also includes powerful support for managing namespaces and resolving other types at any point within your schema that would be very difficult to do with other tools.

About the Sample Code
The sample program, MakeSoapCompatible.java, shows the example in this article; anyone interested in exploring further should definitely read the comments there. A simple schema document MakeSoapCompatible.xsd is also included to show a basic purchase order with attributes to be changed into elements. The sample program can also be run against any other schema documents you have. IT requires at least the XSD Schema Infoset Model and the EMF Eclipse Modeling Framework to run standalone.

You can download the sample program and the following utility programs in the sample zip file.

Copies of two other utility .java files normally shipped with the Schema Infoset Model (version 1.0.1 and later) are also attached with commented code showing several other useful techniques. These include:
  • XSDSchemaQueryTools.java showcases a number of other ways to perform advanced queries on schema components.
  • XSDSchemaBuildingTools.java has convenience methods for building schemas programmatically.

  • Shane Curcuru has been a developer and quality engineer at Lotus and IBM for 12 years and is a member of the Apache Software Foundation. He has worked on such diverse projects as Lotus 1-2-3, Lotus eSuite, Apache's Xalan-J XSLT processor, and a variety of XML Schema tools. Reach him via e-mail at shane_curcuru@us.ibm.com.
    Comment and Contribute






    (Maximum characters: 1200). You have 1200 characters left.



    Thanks for your registration, follow us on our social networks to keep up-to-date