/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.webservice.procedure; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.xsd.XSDAttributeDeclaration; import org.eclipse.xsd.XSDConcreteComponent; import org.eclipse.xsd.XSDConstraint; import org.eclipse.xsd.XSDFeature; import org.eclipse.xsd.XSDModelGroup; import org.teiid.core.designer.util.CoreStringUtil; /** * @since 8.0 */ public class DocumentGenerator implements CoreStringUtil.Constants { // =========================================================================================================================== // Constants public static final DocumentGenerator SHARED = new DocumentGenerator(); private static final int INDENT = 4; private static final String XML_DECL = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; //$NON-NLS-1$ // =========================================================================================================================== // Methods private void add(StringBuffer document, XsdInstanceNode node, int depth, int declarationIndex, Map namespacesToPrefixes, List<String> paramValues) { indentChild(document, depth); int attrIndent = document.length(); document.append('<'); XSDConcreteComponent comp = node.getResolvedXsdComponent(); boolean choice = (comp instanceof XSDModelGroup); addCommentStartIfChoice(document, choice); String pfx; if (declarationIndex == 0) { addName(document, node, EMPTY_STRING); declarationIndex = document.length(); pfx = updateNamespaceDeclarations(document, node, declarationIndex, namespacesToPrefixes); } else { pfx = updateNamespaceDeclarations(document, node, declarationIndex, namespacesToPrefixes); addName(document, node, pfx); } attrIndent = document.length() - attrIndent; boolean attrAdded = false; boolean childAdded = false; XsdInstanceNode[] nodes = node.getChildren(); for (int nodeNdx = 0; nodeNdx < nodes.length; nodeNdx++) { XsdInstanceNode child = nodes[nodeNdx]; XSDConcreteComponent childComp = child.getResolvedXsdComponent(); if (childComp instanceof XSDAttributeDeclaration) { if (attrAdded) { document.append('\n'); indent(document, attrIndent); } else { attrAdded = true; } document.append(' '); String attrPfx = updateNamespaceDeclarations(document, child, declarationIndex, namespacesToPrefixes); addName(document, child, attrPfx); document.append("=\""); //$NON-NLS-1$ addFixedValue(document, childComp); document.append('"'); } else { if (!childAdded) { childAdded = true; addCommentEndIfChoice(document, choice); document.append(">\n"); //$NON-NLS-1$ } add(document, child, depth + 1, declarationIndex, namespacesToPrefixes, paramValues); } } if (childAdded) { if (comp instanceof XSDFeature) { XSDFeature feature = (XSDFeature)comp; if (feature.getConstraint() == XSDConstraint.FIXED_LITERAL) { indentChild(document, depth + 1); document.append(feature.getLexicalValue()); document.append('\n'); } } indentChild(document, depth); } else { document.append(">"); //$NON-NLS-1$ if (!addFixedValue(document, comp)) { if ((paramValues != null) && !paramValues.isEmpty()) { document.append(paramValues.remove(0)); } } } document.append('<'); addCommentStartIfChoice(document, choice); document.append('/'); addName(document, node, pfx); addCommentEndIfChoice(document, choice); document.append(">\n"); //$NON-NLS-1$ } private boolean addFixedValue(StringBuffer document, XSDConcreteComponent component) { if (component instanceof XSDFeature) { XSDFeature feature = (XSDFeature)component; if (feature.getConstraint() == XSDConstraint.FIXED_LITERAL) { document.append(feature.getLexicalValue()); return true; } } return false; } private void addCommentEndIfChoice(StringBuffer document, boolean choice) { if (choice) { document.append(" --"); //$NON-NLS-1$ } } private void addCommentStartIfChoice(StringBuffer document, boolean choice) { if (choice) { document.append("!-- "); //$NON-NLS-1$ } } private void addName(StringBuffer document, XsdInstanceNode node, String prefix) { if (prefix.length() > 0 && node.isNamespaceQualifiedInDocument()) { document.append(prefix); document.append(':'); } document.append(node.getName()); } public String generate(XsdInstanceNode node, List<String> paramValues) { StringBuffer doc = new StringBuffer(XML_DECL); add(doc, node, 0, 0, new HashMap(), paramValues); return doc.toString(); } public String generate(XsdInstanceNode node) { List<String> emptyList = Collections.emptyList(); return generate(node, emptyList); } private void indentChild(StringBuffer document, int depth) { indent(document, depth * INDENT); } private void indent(StringBuffer buffer, int indent) { for (int ndx = indent; --ndx >= 0;) { buffer.append(' '); } } private String updateNamespaceDeclarations(StringBuffer document, XsdInstanceNode node, int declarationIndex, Map namespacesToPrefixes) { String ns = node.getTargetNamespace(); String pfx = (String)namespacesToPrefixes.get(ns); if (pfx == null) { StringBuffer decl = new StringBuffer(); decl.append(" xmlns"); //$NON-NLS-1$ int count = namespacesToPrefixes.size(); if (count == 0) { pfx = EMPTY_STRING; } else { pfx = "ns" + count; //$NON-NLS-1$ decl.append(':'); decl.append(pfx); } decl.append("=\""); //$NON-NLS-1$ decl.append(ns); decl.append('"'); if (document.length() > declarationIndex && document.charAt(declarationIndex) == ' ') { decl.append('\n'); indent(decl, declarationIndex - XML_DECL.length()); } document.insert(declarationIndex, decl); namespacesToPrefixes.put(ns, pfx); } return pfx; } }