package eu.europa.ec.markt.dss.applet.component.model; import com.sun.xml.xsom.*; import com.sun.xml.xsom.impl.ComplexTypeImpl; import com.sun.xml.xsom.parser.XSOMParser; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; import java.math.BigInteger; import java.net.URL; import java.util.*; /** * Created by kaczmani on 10/04/2014. */ public abstract class XmlDomTreeModelAdapter implements TreeModel { protected List<TreeModelListener> listeners = new ArrayList<TreeModelListener>(); //XmlDom doc to view as a tree private Document document; private final Map<XsdNode, Object> xsdTree; public Document getDocument() { return document; } public void setDocument(Document document) { this.document = document; } //constructor used to set the document to view public XmlDomTreeModelAdapter(Document doc, URL xsdTree) { document = doc; this.xsdTree = getXsdElements(xsdTree); } public Map<XsdNode, Object> getXsdTree() { return xsdTree; } /** * Get XSD schema in hashMap tree * * @return HashMap<String, Object> * @param xsdUrl */ private Map<XsdNode, Object> getXsdElements(URL xsdUrl) { XSSchema xsSchema = loadXsd(xsdUrl); //--- Map<XsdNode, Object> result = new LinkedHashMap<XsdNode, Object>(); Map<XsdNode, Object> hashMap = new LinkedHashMap<XsdNode, Object>(); Iterator<XSElementDecl> itre = xsSchema.iterateElementDecls(); //--- String path = ""; while (itre.hasNext()) { XSElementDecl xsElementDecl = itre.next(); final XsdNode xsdNode = new XsdNode(xsElementDecl.getName(), XsdNodeType.ELEMENT, XsdNodeCardinality.ONCE_EXACTLY); result.put(xsdNode, hashMap); path = xsElementDecl.getName(); XSComplexType xsComplexType = xsElementDecl.getType().asComplexType(); if (xsComplexType != null) { XSContentType xsContentType = xsComplexType.getContentType(); XSParticle xsParticle = xsContentType.asParticle(); getElementsRecursively(path, hashMap, xsParticle); } } return result; } /* * recursive helper method of getXmlElements * note that since we don't know the "deepness" of the * schema a recursive way of implementation was necessary */ private void getElementsRecursively(String path, Map<XsdNode, Object> hm, XSParticle xsParticle) { if (xsParticle != null) { XSTerm term = xsParticle.getTerm(); if (term.isElementDecl()) { final XSElementDecl xsElementDecl = term.asElementDecl(); final String xsElementDeclName = xsElementDecl.getName(); path = path + "/" + xsElementDeclName; XSComplexType xsComplexType = xsElementDecl.getType().asComplexType(); //--- if (xsComplexType == null) { XsdNodeCardinality xsdNodeCardinality = getXmlItemCardinality(xsParticle); // subchild has a text node final XsdNode childNode = new XsdNode(path, XsdNodeType.ELEMENT, xsdNodeCardinality); if (xsElementDecl.getType().isSimpleType()) { final Map<XsdNode, Object> subMap = new LinkedHashMap<XsdNode, Object>(1); subMap.put(new XsdNode(path, XsdNodeType.TEXT, XsdNodeCardinality.ONCE_EXACTLY), null); hm.put(childNode, subMap); } else { hm.put(childNode, null); } } else { XSContentType xscont = xsComplexType.getContentType(); XSParticle particle = xscont.asParticle(); Map<XsdNode, Object> newHm = new LinkedHashMap<XsdNode, Object>(); final XsdNode childNode = new XsdNode(path, XsdNodeType.ELEMENT, getXmlItemCardinality(xsParticle)); //Attributes Collection<? extends XSAttributeUse> attributeList = xsComplexType.getAttributeUses(); for (XSAttributeUse attr : attributeList) { XSAttributeDecl attrInfo = attr.getDecl(); final XsdNode grandChildNode = new XsdNode(path + "/" + attrInfo.getName(), XsdNodeType.ATTRIBUTE, XsdNodeCardinality.ONCE_OPTIONALY); newHm.put(grandChildNode, null); } getElementsRecursively(path, newHm, particle); if (((ComplexTypeImpl) xsComplexType).getType().getBaseType().getName().equalsIgnoreCase("string")) { newHm.put(new XsdNode(path, XsdNodeType.TEXT, XsdNodeCardinality.ONCE_EXACTLY), null); } hm.put(childNode, newHm); } //--- } else if (term.isModelGroup()) { XSModelGroup model = term.asModelGroup(); XSParticle[] parr = model.getChildren(); for (XSParticle partemp : parr) { getElementsRecursively(path, hm, partemp); } } } } private XsdNodeCardinality getXmlItemCardinality(XSParticle xsParticle) { if (xsParticle.getMinOccurs().compareTo(BigInteger.valueOf(0)) == 0) { // minOccurs == 0 if (xsParticle.getMaxOccurs().compareTo(BigInteger.valueOf(XSParticle.UNBOUNDED)) != 0) { // maxOccurs != UNBOUNDED return XsdNodeCardinality.ONCE_OPTIONALY; } else { // maxOccurs == UNBOUNDED return XsdNodeCardinality.ZERO_OR_MORE; } } else { return XsdNodeCardinality.ONCE_EXACTLY; } } /** * Load xsd from file .xsd * * @return XSOM.XSSchema * @param xsdUrl */ private XSSchema loadXsd(URL xsdUrl) { XSOMParser parser = new XSOMParser(); XSSchemaSet xsSchemaSet = null; try { // System.out.println("##########" + xsdUrl.toString()); parser.parse(xsdUrl.openStream()); xsSchemaSet = parser.getResult(); } catch (Exception e) { e.printStackTrace(); } Object[] schemaArray = xsSchemaSet.getSchemas().toArray(); XSSchema s = null; if (schemaArray.length > 1) { s = (XSSchema) xsSchemaSet.getSchemas().toArray()[1]; } return s; } //override from TreeModel public Object getRoot() { if(document == null) return null; return new XmlDomAdapterNode(null, document.getDocumentElement(),false); } //override from TreeModel public Object getChild(Object parent, int index) { XmlDomAdapterNode node = (XmlDomAdapterNode) parent; return node.child(index); } //override from TreeModel public int getIndexOfChild(Object parent, Object child) { XmlDomAdapterNode node = (XmlDomAdapterNode) parent; return node.index((XmlDomAdapterNode) child); } //override from TreeModel public int getChildCount(Object parent) { XmlDomAdapterNode xmlDomNode = (XmlDomAdapterNode)parent; return xmlDomNode.childCount(); } //override from TreeModel public boolean isLeaf(Object node) { boolean isLeaf = false; XmlDomAdapterNode xmlDomNode = (XmlDomAdapterNode)node; if(xmlDomNode.isAttribute()){ return false; } if(xmlDomNode.node.getChildNodes() == null ){ isLeaf = true; }else{ if(xmlDomNode.node.getChildNodes().getLength() == 1){ //String data = xmlDomNode.node.getFirstChild().getNodeValue(); if(xmlDomNode.node instanceof Attr){ isLeaf = true; // xmlDomNode.setText(true); }else if(xmlDomNode.node instanceof Element){ isLeaf = false; } }else { int nbAttribute = 0; if(xmlDomNode.node.getAttributes() != null){ nbAttribute = xmlDomNode.node.getAttributes().getLength(); } isLeaf = (xmlDomNode.node.getChildNodes().getLength() + nbAttribute) == 0; } } return isLeaf; } //override from TreeModel public void valueForPathChanged(TreePath path, Object newValue) { // Null. We won't be making changes in the GUI // If we did, we would ensure the new value was really new, // adjust the model, and then fire a TreeNodesChanged event. } /* * Use these methods to add and remove event listeners. * (Needed to satisfy TreeModel interface, but not used.) */ // override from TreeModel public void addTreeModelListener(TreeModelListener listener) { if (listener != null && !listeners.contains(listener)) { listeners.add(listener); } } // override from TreeModel public void removeTreeModelListener(TreeModelListener listener) { if (listener != null) { listeners.remove(listener); } } /* * Invoke these methods to inform listeners of changes. * Methods taken from TreeModelSupport class described at * http://java.sun.com/products/jfc/tsc/articles/jtree/index.html That * architecture (produced by Tom Santos and Steve Wilson) is more elegant. */ public void fireTreeNodesChanged(TreeModelEvent e) { Iterator listenersIt = listeners.iterator(); while (listenersIt.hasNext()) { TreeModelListener listener = (TreeModelListener) listenersIt.next(); listener.treeNodesChanged(e); } } public void fireTreeNodesInserted(TreeModelEvent e) { Iterator listenersIt = listeners.iterator(); while (listenersIt.hasNext()) { TreeModelListener listener = (TreeModelListener) listenersIt.next(); listener.treeNodesInserted(e); } } public void fireTreeNodesRemoved(TreeModelEvent e) { Iterator listenersIt = listeners.iterator(); while (listenersIt.hasNext()) { TreeModelListener listener = (TreeModelListener) listenersIt.next(); listener.treeNodesRemoved(e); } } public void fireTreeStructureChanged(TreeModelEvent e) { Iterator listenersIt = listeners.iterator(); while (listenersIt.hasNext()) { TreeModelListener listener = (TreeModelListener) listenersIt.next(); listener.treeStructureChanged(e); } } }