/**
* Copyright © 2008-2012 NetAllied Systems GmbH, Ravensburg, Germany.
*
* Licensed under the MIT Open Source License,
* for details please see LICENSE file or the website
* http://www.opensource.org/licenses/mit-license.php
*/
package de.netallied.xsd2cppsax;
import java.util.HashSet;
import java.util.Set;
import org.apache.xerces.xs.XSComplexTypeDefinition;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSElementDeclaration;
import org.apache.xerces.xs.XSModel;
import org.apache.xerces.xs.XSModelGroup;
import org.apache.xerces.xs.XSNamedMap;
import org.apache.xerces.xs.XSObject;
import org.apache.xerces.xs.XSObjectList;
import org.apache.xerces.xs.XSParticle;
import org.apache.xerces.xs.XSTerm;
import org.apache.xerces.xs.XSTypeDefinition;
import org.apache.xerces.xs.XSWildcard;
/**
* Traverses Xerces XS data structure.
*
*/
public abstract class AbstractXSTraverser {
/** Code generator configuration. */
protected Config config;
/**
* To avoid traversing of sub-trees multiple times when <xs:element ref="">
* is used excessively
*/
private Set<XSElementDeclaration> handledElements = new HashSet<XSElementDeclaration>();
/** Model being traversed. */
private XSModel model;
/**
* Constructor.
*/
public AbstractXSTraverser(Config config) {
this.config = config;
}
/**
* Searches given model for a top level element with given name.
*
* @param model
* Model to search.
* @param rootElementName
* Root element name.
* @return Root element.
*/
public XSElementDeclaration findRootElement(XSModel model, String rootElementName) {
XSNamedMap elementMap = model.getComponents(XSConstants.ELEMENT_DECLARATION);
for (int i = 0; i < elementMap.getLength(); i++) {
XSObject item = elementMap.item(i);
if (item.getType() == XSConstants.ELEMENT_DECLARATION) {
if (item.getName().equals(rootElementName)) {
return (XSElementDeclaration) item;
}
}
}
return null;
}
/**
* @return Code generator configuration.
*/
protected Config getConfig() {
return config;
}
/**
* @return Model being traversed.
*/
public XSModel getModel() {
return model;
}
/**
* Handles an element,
*
* @param element
* Element to handle.
* @return True if traversing shall continue, false for abort.
*/
public boolean handleElement(XSElementDeclaration element) {
if (!handledElements.contains(element)) {
handledElements.add(element);
XSTypeDefinition typeDefinition = element.getTypeDefinition();
return handleTypeDefinition(typeDefinition);
}
return true;
}
/**
* Handles a model group.
*
* @param modelGroup
* Model group to handle.
* @return True if traversing shall continue, false for abort.
*/
public boolean handleModelGroup(XSModelGroup modelGroup) {
XSObjectList particles = modelGroup.getParticles();
for (int i = 0; i < particles.getLength(); i++) {
XSParticle particle = (XSParticle) particles.item(i);
boolean success = handleParticle(particle);
if (!success) {
return false;
}
}
return true;
}
/**
* Handles a particle.
*
* @param particle
* Particle to handle.
* @return True if traversing shall continue, false for abort.
*/
public boolean handleParticle(XSParticle particle) {
if (particle == null) {
return true;
}
XSTerm term = particle.getTerm();
if (term instanceof XSModelGroup) {
XSModelGroup modelGroup = (XSModelGroup) term;
if (!handleModelGroup(modelGroup)) {
return false;
}
XSObjectList particles = modelGroup.getParticles();
for (int i = 0; i < particles.getLength(); i++) {
if (particles.item(i) instanceof XSParticle) {
if (!handleParticle((XSParticle) particles.item(i))) {
return false;
}
}
}
} else if (term instanceof XSElementDeclaration) {
return handleElement((XSElementDeclaration) term);
} else if (term instanceof XSWildcard) {
return handleWildcard((XSWildcard) term);
}
return true;
}
/**
* Handles a XSD type
*
* @param typeDefinition
* Type to handle.
* @return True if traversing shall continue, false for abort.
*/
protected boolean handleTypeDefinition(XSTypeDefinition typeDefinition) {
if (isTypeComplex(typeDefinition)) {
XSComplexTypeDefinition complexTypeDefi = (XSComplexTypeDefinition) typeDefinition;
boolean success = handleParticle(complexTypeDefi.getParticle());
if (!success) {
return false;
}
}
XSTypeDefinition baseType = typeDefinition.getBaseType();
if (baseType != null) {
if (!Constants.XSD_ANYTYPE_NAME.equals(baseType.getName())
&& !getConfig().getXSNamespace().equals(baseType.getNamespace())) {
return handleTypeDefinition(baseType);
}
}
return true;
}
/**
* Handles a wildcard.
*
* @param wildcard
* Wildcard to handle.
* @return True if traversing shall continue, false for abort.
*/
public boolean handleWildcard(XSWildcard wildcard) {
return true;
}
public boolean isTypeComplex(XSTypeDefinition type) {
return type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE;
}
/**
* @param model
* Model being traversed.
*/
protected void setModel(XSModel model) {
this.model = model;
}
/**
* Starts traversing.
*
* @param model
* Model to traverse.
*/
public void start(XSModel model) {
this.model = model;
XSNamedMap elementMap = model.getComponents(XSConstants.ELEMENT_DECLARATION);
for (int i = 0; i < elementMap.getLength(); i++) {
XSObject item = elementMap.item(i);
if (item.getType() == XSConstants.ELEMENT_DECLARATION) {
handleElement((XSElementDeclaration) item);
}
}
}
/**
* Starts traversing with given root element.
*
* @param model
* Model to traverse.
* @param rootElementName
* Name of element to start with.
*/
public void startWithRootElement(XSModel model, String rootElementName) {
this.model = model;
XSElementDeclaration rootElement = findRootElement(model, rootElementName);
if (handleElement(rootElement)) {
start(model);
}
}
}