blob: 1978380766044ee3403aa48b22c76015cb949337 [file] [log] [blame]
/***********************************************************************************************************************
* 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;
}
}