/* * RapidMiner * * Copyright (C) 2001-2011 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.operator.nio.xml; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.swing.AbstractListModel; import javax.swing.SwingUtilities; 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.Element; import org.w3c.dom.NodeList; import com.rapidminer.tools.I18N; import com.rapidminer.tools.xml.MapBasedNamespaceContext; /** * A model which holds the result of XPath expression on an XML document. * * @author Marius Helf * */ public class XPathMatchesListModel extends AbstractListModel { public static interface XPathMatchesResultListener { public void informStateChange(String message, boolean error); } private static final long serialVersionUID = 5596412058073512745L; private Document document; private XPath xpath; private NodeList exampleNodes; private List<XPathMatchesResultListener> listeners = new LinkedList<XPathMatchesListModel.XPathMatchesResultListener>(); private int maxElements; /** * Creates a new XPathMatchesListModel. * @param document The XML Document to which this model refers. * @param namespaceMap Maps namespace IDs to namespace URIs. * @param defaultNamespaceURI The default namespace URI. * @param maxElements The maximum number of provided elements. */ public XPathMatchesListModel(Document document, Map<String, String> namespaceMap, String defaultNamespaceURI, int maxElements) { this.document = document; this.xpath = XPathFactory.newInstance().newXPath(); this.maxElements = maxElements; xpath.setNamespaceContext(new MapBasedNamespaceContext(namespaceMap, defaultNamespaceURI)); } public void setXPathExpression(String expression) { XPathExpression exampleExpression = null; try { exampleExpression = xpath.compile(expression); } catch (XPathExpressionException e1) { fireStateChange(I18N.getGUILabel("xml_reader.wizard.illegal_xpath", e1), true); } if (exampleExpression != null) { try { final int oldSize = getSize(); exampleNodes = (NodeList) exampleExpression.evaluate(document, XPathConstants.NODESET); // check that only elements, no attributes are contained in the xpath results: List<String> illegalElements = new LinkedList<String>(); for (int i = 0; i < exampleNodes.getLength(); ++i) { if (!(exampleNodes.item(i) instanceof Element)) { illegalElements.add(exampleNodes.item(i).getNodeName()); } } if (!illegalElements.isEmpty()) { fireStateChange(I18N.getGUILabel("xml_reader.wizard.xpath_non_element_nodes", illegalElements.toString()), true); exampleNodes = null; return; } SwingUtilities.invokeLater(new Runnable() { public void run() { fireContentsChanged(this, 0, Math.min(oldSize, exampleNodes.getLength())); if (oldSize > exampleNodes.getLength()) { fireIntervalRemoved(this, exampleNodes.getLength(), oldSize - 1); } else if (oldSize < exampleNodes.getLength()) { fireIntervalAdded(this, oldSize, exampleNodes.getLength() - 1); } fireStateChange(I18N.getGUILabel("xml_reader.wizard.xpath_result", exampleNodes.getLength()), exampleNodes.getLength() == 0); } }); } catch (final XPathExpressionException e) { exampleNodes = null; SwingUtilities.invokeLater(new Runnable() { public void run() { fireStateChange(I18N.getGUILabel("xml_reader.wizard.illegal_xpath", e.getMessage()), true); } }); } } else { exampleNodes = null; } } /* (non-Javadoc) * @see javax.swing.ListModel#getSize() * Returns the number of matched nodes (without subnodes). */ @Override public int getSize() { if (exampleNodes == null) { return 0; } if (exampleNodes.getLength() > maxElements) { return maxElements; } return exampleNodes.getLength(); } @Override public Object getElementAt(int index) { return exampleNodes.item(index); } public void addListener(XPathMatchesResultListener listener) { listeners.add(listener); } public void removeListener(XPathMatchesResultListener listener) { listeners.remove(listener); } /** * Informs all XPathMatchesResultListener of this model about a state change. * @param message * @param error */ private void fireStateChange(String message, boolean error) { for (XPathMatchesResultListener listener : listeners) { listener.informStateChange(message, error); } } }