package sushi.xml.importer; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import sushi.DateUtils; import sushi.FileUtils; import sushi.edifact.importer.EdifactImporter; import sushi.event.SushiEvent; import sushi.event.SushiEventType; import sushi.event.attribute.SushiAttribute; import sushi.event.collection.SushiMapTree; /** * This class parses events from XML files. */ public class XMLParser extends AbstractXMLParser { private static SushiMapTree<String, Serializable> eventValueTree; /** * Parses a single event from a XML file from the given file path. * @param filePath * @return * @throws XMLParsingException */ public static SushiEvent generateEventFromXML(String filePath) throws XMLParsingException { Document doc = readXMLDocument(filePath); return generateEvent(doc, null); } /** * Parses a single event from a XML file from the given file path under consideration of the given XSD. * The XSD defines the contained nodes and attributes of the XML file. * @param filePath * @return * @throws XMLParsingException */ public static SushiEvent generateEventFromXML(String filePath, String pathToXSD) throws XMLParsingException { Document doc = readXMLDocument(filePath); return generateEvent(doc, pathToXSD); } /** * Parses a single event from a {@link Document}. * @param filePath * @return * @throws XMLParsingException */ public static SushiEvent generateEventFromDoc(Document xmlDoc) throws XMLParsingException { return generateEvent(xmlDoc, null); } /** * Parses a single event from a {@link Document} under consideration of the given XSD. * The XSD defines the contained nodes and attributes of the XML file. * @param filePath * @return * @throws XMLParsingException */ private static SushiEvent generateEvent(Document doc, String pathToXSD) throws XMLParsingException { XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new XSDNameSpaceContext()); // XPath Query for showing all nodes value XPathExpression rootElementExpression = null; try { rootElementExpression = xPath.compile("/./child::*"); } catch (XPathExpressionException e) { e.printStackTrace(); } Object rootElementsResult = null; try { rootElementsResult = rootElementExpression.evaluate(doc, XPathConstants.NODESET); } catch (XPathExpressionException e) { e.printStackTrace(); } NodeList rootElementNodes = (NodeList) rootElementsResult; assert(rootElementNodes.getLength() == 1); Node actualRootElement = rootElementNodes.item(0); eventValueTree = new SushiMapTree<String, Serializable>(); SushiEventType eventType = null; if (pathToXSD == null){ String XSDName = getXSDNameFromNode(actualRootElement); if (XSDName == null) { //do stuff for getting eventType for edifact eventType = EdifactImporter.getInstance().getEventTypeForEdifact(doc); } else { eventType = SushiEventType.findBySchemaName(XSDName); } } else { eventType = SushiEventType.findBySchemaName(FileUtils.getFileNameWithoutExtension(pathToXSD)); if (eventType == null) eventType = XSDParser.generateEventTypeFromXSD(pathToXSD, FileUtils.getFileNameWithoutExtension(pathToXSD)); } // eventValueTree befuellen generateEventTreeFromElement(actualRootElement); if(eventType == null){ throw new XMLParsingException("No matching eventtype was found; please upload corresponding XSD"); } else { Date eventTimestamp; // Timestamp richtig einlesen String timestampName = eventType.getTimestampNameAsXPath(); String time = ""; if(timestampName == null || timestampName.equals(AbstractXMLParser.CURRENT_TIMESTAMP) || timestampName.equals(AbstractXMLParser.GENERATED_TIMESTAMP_COLUMN_NAME)){ eventTimestamp = new Date(); } else { // Timestamp aus XML-Doc holen try { XPathExpression timeElementExpression = xPath.compile("/" + actualRootElement.getNodeName() + timestampName); Object timeElementsResult = timeElementExpression.evaluate(doc, XPathConstants.NODE); Node timeNode = (Node) timeElementsResult; time = timeNode.getTextContent(); System.out.println(time); } catch (XPathExpressionException e) { e.printStackTrace(); } catch (NullPointerException e1) { e1.printStackTrace(); } eventTimestamp = (DateUtils.parseDate(time) != null) ? DateUtils.parseDate(time) : new Date(); } ArrayList<String> attributeExpressions = new ArrayList<String>(); for (SushiAttribute attribute : eventType.getValueTypes()) { attributeExpressions.add(attribute.getAttributeExpression()); } eventValueTree.retainAllByAttributeExpression(attributeExpressions); return new SushiEvent(eventType, eventTimestamp, eventValueTree); } } private static void generateEventTreeFromElement(Node actualRootElement) { getChildNodesFromEvent(actualRootElement, true); } /** * Parses the attributes of the event from the given {@link Node}. * @param actualRootElement */ private static SushiMapTree<String, Serializable> getChildNodesFromEvent(Node actualRootElement, Boolean shouldBeRoot) { NodeList childNodeList = actualRootElement.getChildNodes(); for(int i = 0; i < childNodeList.getLength(); i++){ Node childNode = childNodeList.item(i); if (childNode.getNodeType() == Node.ELEMENT_NODE) { // String nodeName = childNode.getNodeName().replace(":", "_"); String nodeName = childNode.getNodeName().trim().replaceAll(" +","_").replaceAll("[^a-zA-Z0-9_]+",""); String nodeText = null; if(!hasRealChildNodes(childNode)){ nodeText = childNode.getTextContent(); } if(shouldBeRoot){ eventValueTree.addChild(null, nodeName, nodeText); } else{ // eventValueTree.addChild(actualRootElement.getNodeName().replace(":", "_"), nodeName, nodeText); eventValueTree.addChild(actualRootElement.getNodeName().trim().replaceAll(" +","_").replaceAll("[^a-zA-Z0-9_]+",""), nodeName, nodeText); } getChildNodesFromEvent(childNode, false); } } return eventValueTree; } /** * Returns true, if this node has child nodes from the Node.ELEMENT_NODE type. * @param node * @return */ private static boolean hasRealChildNodes(Node node) { boolean hasChildNodes = false; NodeList childNodeList = node.getChildNodes(); for(int i = 0; i < childNodeList.getLength(); i++){ Node childNode = childNodeList.item(i); if (childNode.getNodeType() == Node.ELEMENT_NODE) { hasChildNodes = true; } } return hasChildNodes; } /** * Returns the XSD name for a given node. * @param element * @return */ private static String getXSDNameFromNode(Node element) { Node xsdAttribute = element.getAttributes().getNamedItem("xsi:noNamespaceSchemaLocation"); if (xsdAttribute == null) { System.err.println("no xsd stated in xml"); return null; }; String filePath = xsdAttribute.getNodeValue(); int begin = filePath.lastIndexOf("/"); int end = filePath.lastIndexOf("."); return filePath.substring(begin + 1, end); } /** * Returns the first child with the given name from a given node. * @param name * @param parentNode * @return */ public static Node getFirstChildWithNameFromNode(String name, Node parentNode){ NodeList list = parentNode.getChildNodes(); for(int i = 0; i < list.getLength(); i++){ if(list.item(i).getNodeName().equals(name)){ return list.item(i); } } return null; } /** * Returns the last child with the given name from a given node. * @param name * @param parentNode * @return */ public static Node getLastChildWithNameFromNode(String name, Node parentNode){ NodeList list = parentNode.getChildNodes(); Node namedNode = null; for(int i = 0; i < list.getLength(); i++){ if(list.item(i).getNodeName().equals(name)){ namedNode = list.item(i); } } return namedNode; } /** * Returns all childs with the given name from a given node. * @param name * @param parentNode * @return */ public static List<Node> getAllChildWithNameFromNode(String name, Node parentNode){ List<Node> resultList = new ArrayList<Node>(); NodeList list = parentNode.getChildNodes(); for(int i = 0; i < list.getLength(); i++){ if(list.item(i).getNodeName().equals(name)){ resultList.add(list.item(i)); } } return resultList; } }