/*********************************************************************************************************************** | |
* Copyright (c) 2008, 2011 Attensity Europe GmbH and brox IT Solutions GmbH. All rights reserved. This program and the | |
* accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this | |
* distribution, and is available at http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: Daniel Stucky (empolis GmbH) - initial API and implementation | |
* Andreas Weber (Attensity Europe GmbH) - data model simplification | |
**********************************************************************************************************************/ | |
package org.eclipse.smila.processing.pipelets.xmlprocessing; | |
import javax.xml.transform.TransformerException; | |
import org.apache.xpath.XPathAPI; | |
import org.apache.xpath.objects.XObject; | |
import org.eclipse.smila.blackboard.Blackboard; | |
import org.eclipse.smila.datamodel.Any; | |
import org.eclipse.smila.datamodel.Value; | |
import org.eclipse.smila.processing.ProcessingException; | |
import org.eclipse.smila.processing.parameters.ParameterAccessor; | |
import org.eclipse.smila.processing.pipelets.xmlprocessing.util.XPathUtils; | |
import org.eclipse.smila.utils.xml.XMLUtils; | |
import org.w3c.dom.Document; | |
import org.w3c.dom.Element; | |
import org.w3c.dom.Node; | |
import org.w3c.dom.NodeList; | |
/** | |
* Pipelet that filters elements by XPath (either include or exclude mode). The possible properties are: | |
*/ | |
public class XPathFilterPipelet extends AXmlTransformationPipelet { | |
/** | |
* The XPathFilerMode, either include or exclude. | |
* | |
* @author stuc07 | |
* | |
*/ | |
public enum XPathFilterMode { | |
/** | |
* Inlcude Xpath expressions. | |
*/ | |
INCLUDE, | |
/** | |
* Exclude XPath expressions. | |
*/ | |
EXCLUDE | |
} | |
/** | |
* The name of the XSLT file used for the transformation. | |
*/ | |
public static final String PROP_XPATH = "xpath"; | |
/** | |
* Property for the XPathFilerMode to execute. | |
*/ | |
public static final String PROP_FILTER_MODE = "filterMode"; | |
/** | |
* The separator property. | |
*/ | |
public static final String PROP_SEPARATOR = "separator"; | |
/** | |
* The rootElement property. Only valid for filter mode include. | |
*/ | |
public static final String PROP_NAMESPACE = "namespace"; | |
/** | |
* The namespace property. | |
*/ | |
public static final String PROP_ROOT_ELEMENT = "rootElement"; | |
@Override | |
protected void processRecord(final Blackboard blackboard, final ParameterAccessor paramAccessor, final String id) | |
throws Exception { | |
final Any xpaths = paramAccessor.getParameterAny(PROP_XPATH); | |
if (xpaths == null || xpaths.size() == 0) { | |
throw new ProcessingException("Property " + PROP_XPATH + " must not be <null> or an empty String"); | |
} | |
final String mode = paramAccessor.getParameter(PROP_FILTER_MODE, null); | |
XPathFilterMode filterMode = XPathFilterMode.INCLUDE; | |
if (mode != null) { | |
filterMode = XPathFilterMode.valueOf(mode); | |
} | |
String root = null; | |
if (XPathFilterMode.INCLUDE.equals(filterMode)) { | |
root = paramAccessor.getRequiredParameter(PROP_ROOT_ELEMENT); | |
} | |
final String namespace = paramAccessor.getParameter(PROP_NAMESPACE, ""); | |
final Element namespaceElement = createNamespaceElement(namespace); | |
final Document inputDocument = createDocument(blackboard, id, paramAccessor); | |
Document result; | |
if (inputDocument != null) { | |
if (XPathFilterMode.INCLUDE.equals(filterMode)) { | |
result = includeElements(inputDocument, xpaths, namespaceElement, root); | |
} else { | |
result = excludeElements(inputDocument, xpaths, namespaceElement); | |
} | |
storeDocument(blackboard, id, result, paramAccessor); | |
} | |
} | |
/** | |
* Include selected elements by XPath. | |
* | |
* @param inputDocument | |
* the input Document | |
* @return a Document | |
* @throws ProcessingException | |
* if any error occurs | |
*/ | |
private Document includeElements(final Document inputDocument, final Any xpaths, final Element namespaceElement, | |
final String root) throws ProcessingException { | |
final Document doc = XMLUtils.getDocument(); | |
Element rootElement; | |
rootElement = doc.createElement(root); | |
doc.appendChild(rootElement); | |
try { | |
for (final Any xpath : xpaths) { | |
final XObject xobj = XPathAPI.eval(inputDocument, ((Value) xpath).asString(), namespaceElement); | |
final NodeList nl = xobj.nodelist(); | |
for (int i = 0; i < nl.getLength(); i++) { | |
final Node n = nl.item(i); | |
rootElement.appendChild(doc.importNode(n, true)); | |
} // for | |
} // for | |
} catch (final TransformerException e) { | |
throw new ProcessingException("Transformer exception: " + e.getMessage()); | |
} | |
return doc; | |
} | |
/** | |
* Exclude selected elements by XPath. | |
* | |
* @param inputDocument | |
* the input Document | |
* @return a Document | |
*/ | |
private Document excludeElements(final Document inputDocument, final Any xpaths, final Element namespaceElement) { | |
for (final Any xpath : xpaths) { | |
XPathUtils.removeNodesByXPath(inputDocument, ((Value) xpath).asString(), namespaceElement); | |
} | |
return inputDocument; | |
} | |
/** | |
* @return namespace Element created from namespace string. | |
*/ | |
private Element createNamespaceElement(final String namespace) throws ProcessingException { | |
final Document doc = XMLUtils.getDocument(); | |
final Element namespaceElement = doc.createElement("NamespaceDef"); | |
final String[] namespaces = namespace.split(" "); | |
for (int i = 0; i < namespaces.length; i++) { | |
if (!"".equals(namespaces[i].trim())) { | |
final String[] nsItems = namespaces[i].split("="); | |
if (nsItems.length != 2) { | |
throw new ProcessingException("Property " + PROP_NAMESPACE | |
+ " in invalid format [Namespace;ns1=val ns2=val]"); | |
} | |
namespaceElement.setAttribute("xmlns:" + nsItems[0], nsItems[1]); | |
} | |
} | |
return namespaceElement; | |
} | |
} |