package com.yahoo.dtf.xml; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.yahoo.dtf.exception.DTFException; import com.yahoo.dtf.exception.ParseException; public class XSDHandler { public static long ATTRIB_REQUIRED = 0; public static long ATTRIB_OPTIONAL = 1; private Document _document = null; public XSDHandler(InputStream dtdIs) throws DTFException { try { _document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(dtdIs); } catch (IOException e) { throw new ParseException("error loading xsd file.", e); } catch (SAXException e) { throw new ParseException("error loading xsd file.", e); } catch (ParserConfigurationException e) { throw new ParseException("error loading xsd file.", e); } } public synchronized String generateChildrenString(String elementName) { elementName = elementName.toLowerCase(); Node element = findElement(elementName); if (element != null) return findAllDirectChildren(element," ",-1,false); return null; } private int SEQ = 0; private int CHO = 1; private boolean findAnyPreviousSibling(Node aux) { while ( aux != null ) { Node prev = aux.getPreviousSibling(); if ( prev == null ) break; if ( prev.getNodeType() == Node.ELEMENT_NODE ) return true; aux = prev; } return false; } private String findAllDirectChildren(Node element, String sep, int prev, boolean flag) { StringBuffer result = new StringBuffer(); Node aux = element.getFirstChild(); while ( aux != null ) { if (aux.getNodeName().equals("xs:element")) { NamedNodeMap attributes = aux.getAttributes(); Node name = attributes.getNamedItem("name"); String prefix = sep; /* * If there is no previous element then we might as well not * put the prefix separator because it will just look wrong. */ if ( !findAnyPreviousSibling(aux) && !flag ) prefix = ""; if ( name != null ) { result.append(prefix + name.getNodeValue()); } else { Node ref = attributes.getNamedItem("ref"); result.append(prefix + ref.getNodeValue()); } } else if (aux.getNodeName().equals("xs:group")) { NamedNodeMap attributes = aux.getAttributes(); Node ref = attributes.getNamedItem("ref"); String minOccurs = null; String maxOccurs = null; Node aux2 = attributes.getNamedItem("minOccurs"); if ( aux2 != null ) minOccurs = aux2.getNodeValue(); aux2 = attributes.getNamedItem("maxOccurs"); if ( aux2 != null ) maxOccurs = aux2.getNodeValue(); if ( maxOccurs != null && maxOccurs.equals("unbounded") ) maxOccurs = "*"; String suffix = ""; if ( minOccurs != null && maxOccurs != null ) { suffix = "{" + minOccurs + "," + maxOccurs + "} "; } if ( ref != null ) { Node group = findGroup(ref.getNodeValue()); if ( group != null ) { result.append(findAllDirectChildren(group, sep, prev, true) + suffix); } } else { result.append(findAllDirectChildren(aux, sep, prev, true) + suffix); } } else if (aux.getNodeName().equals("xs:sequence")) { NamedNodeMap attributes = aux.getAttributes(); String minOccurs = "1"; String maxOccurs = "1"; Node aux2 = attributes.getNamedItem("minOccurs"); if ( aux2 != null ) minOccurs = aux2.getNodeValue(); aux2 = attributes.getNamedItem("maxOccurs"); if ( aux2 != null ) maxOccurs = aux2.getNodeValue(); if ( maxOccurs.equals("unbounded") ) maxOccurs = "*"; if ( prev == SEQ ) { result.append(findAllDirectChildren(aux," . ",CHO,false)); } else { if ( minOccurs.equals("1") && maxOccurs.equals("1") ) { result.append(findAllDirectChildren(aux, " . ", SEQ, false)); } else { result.append("(" + findAllDirectChildren(aux," . ", SEQ,false) + "){" + minOccurs + "," + maxOccurs + "} "); } } } else if (aux.getNodeName().equals("xs:choice")) { NamedNodeMap attributes = aux.getAttributes(); String minOccurs = "1"; String maxOccurs = "1"; Node aux2 = attributes.getNamedItem("minOccurs"); if ( aux2 != null ) minOccurs = aux2.getNodeValue(); aux2 = attributes.getNamedItem("maxOccurs"); if ( aux2 != null ) maxOccurs = aux2.getNodeValue(); if ( maxOccurs.equals("unbounded") ) maxOccurs = "*"; if ( prev == CHO ) { result.append(findAllDirectChildren(aux," | ",CHO,false)); } else { if ( minOccurs.equals("1") && maxOccurs.equals("1") ) { result.append("(" + findAllDirectChildren(aux, " | ", CHO,false) + ") "); } else { result.append("(" + findAllDirectChildren(aux, " | ", CHO,false) + "){" + minOccurs + "," + maxOccurs + "} "); } } } else { result.append(findAllDirectChildren(aux,sep,prev,false)); } aux = aux.getNextSibling(); } return result.toString(); } private ArrayList<String> findRequiredAttributes(Node element) { return findAttributes(element, "required"); } private ArrayList<String> findOptionalAttributes(Node element) { return findAttributes(element, "optional"); } private ArrayList<String> findFixedAttributes(Node element) { return findAttributes(element, "fixed"); } private ArrayList<String> findAttributes(Node element,String use) { ArrayList<String> result = new ArrayList<String>(); Node aux = element.getFirstChild(); NamedNodeMap attribs = element.getAttributes(); if ( attribs != null ) { Node type = attribs.getNamedItem("type"); if ( type != null ) { // need to find correct complextType with this name String typeName = type.getNodeValue(); NodeList types = _document.getElementsByTagName("xs:complexType"); for (int i = 0; i < types.getLength(); i++) { Node node = types.item(i); NamedNodeMap attribs2 = node.getAttributes(); Node name = attribs2.getNamedItem("name"); if ( name != null ) { if ( name.getNodeValue().equals(typeName) ) { aux = node.getFirstChild(); break; } } } } } while ( aux != null ) { if (aux.getNodeName().equals("xs:attribute")) { NamedNodeMap attributes = aux.getAttributes(); Node name = attributes.getNamedItem("name"); if ( name != null ) { Node attrib = attributes.getNamedItem("use"); if (attrib != null && (use == null || attrib.getNodeValue().equals(use))) { result.add(name.getNodeValue()); } } } else if (aux.getNodeName().equals("xs:attributeGroup")) { NamedNodeMap attributes = aux.getAttributes(); Node name = attributes.getNamedItem("ref"); if ( name != null ) { Node group = findAttributeGroup(name.getNodeValue()); if ( group != null ) { result.addAll(findAttributes(group,use)); } } } else { if ( !aux.getNodeName().equals("xs:element") ) result.addAll(findAttributes(aux,use)); } aux = aux.getNextSibling(); } return result; } public synchronized ArrayList<String> getAttributes(String elementName) { ArrayList<String> result = new ArrayList<String>(); elementName = elementName.toLowerCase(); Node element = findElement(elementName); if (element != null) { result = findAttributes(element,null); } return result; } public synchronized ArrayList<String> getRequiredAttributes(String elementName) { ArrayList<String> result = new ArrayList<String>(); elementName = elementName.toLowerCase(); Node element = findElement(elementName); if (element != null) { result = findRequiredAttributes(element); } return result; } public synchronized ArrayList<String> getOptionalAttributes(String elementName) { ArrayList<String> result = new ArrayList<String>(); elementName = elementName.toLowerCase(); Node element = findElement(elementName); if (element != null) { result = findOptionalAttributes(element); } return result; } public synchronized ArrayList<String> getFixedAttributes(String elementName) { ArrayList<String> result = new ArrayList<String>(); elementName = elementName.toLowerCase(); Node element = findElement(elementName); if (element != null) { result = findFixedAttributes(element); } return result; } private Node findGroup(String elementName) { NodeList list = _document.getElementsByTagName("xs:group"); for (int i = 0; i < list.getLength(); i++) { NamedNodeMap attributes = list.item(i).getAttributes(); if (attributes != null) { Node attribute = attributes.getNamedItem("name"); if (attribute != null && attribute.getNodeValue().equals(elementName)) { return list.item(i); } } } return null; } private Node find(String name, String elementName) { NodeList list = _document.getElementsByTagName(name); for (int i = 0; i < list.getLength(); i++) { NamedNodeMap attributes = list.item(i).getAttributes(); if (attributes != null) { Node attribute = attributes.getNamedItem("name"); if (attribute != null && attribute.getNodeValue().equals(elementName)) { return list.item(i); } } } return null; } private Node findElement(String elementName) { // have to make sure to get the top level elements, not any other // elements by the same name at an inner level of the XSD tree. NodeList list = _document.getElementsByTagName("xs:schema").item(0). getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node aux = list.item(i); if ( aux.getNodeName().equals("xs:element")) { NamedNodeMap attributes = aux.getAttributes(); if (attributes != null) { Node attribute = attributes.getNamedItem("name"); if (attribute != null && attribute.getNodeValue().equalsIgnoreCase(elementName)) { return list.item(i); } } } } return null; } private Node findAttributeGroup(String name) { NodeList list = _document.getElementsByTagName("xs:attributeGroup"); for (int i = 0; i < list.getLength(); i++) { NamedNodeMap attributes = list.item(i).getAttributes(); if (attributes != null) { Node attribute = attributes.getNamedItem("name"); if (attribute != null && attribute.getNodeValue().equals(name)) { return list.item(i); } } } return null; } }