View Javadoc

1   /*
2    * $Id: XPathExtractor.java 22412 2011-07-14 07:28:59Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.xml.transformer;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.context.MuleContextAware;
15  import org.mule.api.expression.ExpressionRuntimeException;
16  import org.mule.api.lifecycle.InitialisationException;
17  import org.mule.api.registry.RegistrationException;
18  import org.mule.api.transformer.TransformerException;
19  import org.mule.config.i18n.CoreMessages;
20  import org.mule.config.i18n.MessageFactory;
21  import org.mule.module.xml.util.NamespaceManager;
22  import org.mule.transformer.AbstractTransformer;
23  import org.mule.transformer.types.DataTypeFactory;
24  
25  import java.util.Arrays;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.Map;
30  
31  import javax.xml.namespace.NamespaceContext;
32  import javax.xml.namespace.QName;
33  import javax.xml.xpath.XPath;
34  import javax.xml.xpath.XPathConstants;
35  import javax.xml.xpath.XPathExpressionException;
36  import javax.xml.xpath.XPathFactory;
37  
38  import org.xml.sax.InputSource;
39  
40  /**
41   * Simple transformer for using the JAXP XPath library to extract an XPath value from
42   * an XPath expression.
43   *
44   * @author Ryan Heaton
45   */
46  public class XPathExtractor extends AbstractTransformer implements MuleContextAware
47  {
48      /**
49       * Result type.
50       */
51      public enum ResultType
52      {
53          NODESET,
54          NODE,
55          STRING,
56          BOOLEAN,
57          NUMBER
58      }
59  
60      private volatile XPath xpath = XPathFactory.newInstance().newXPath();
61      private volatile Map<String, String> prefixToNamespaceMap = null;
62      private volatile String expression;
63      private volatile ResultType resultType = ResultType.STRING;
64      private NamespaceManager namespaceManager;
65  
66      public XPathExtractor()
67      {
68          registerSourceType(DataTypeFactory.create(org.w3c.dom.Node.class));
69          registerSourceType(DataTypeFactory.create(InputSource.class));
70      }
71  
72      @Override
73      public void setMuleContext(MuleContext context)
74      {
75          this.muleContext = context;
76          try
77          {
78              namespaceManager = muleContext.getRegistry().lookupObject(NamespaceManager.class);
79          }
80          catch (RegistrationException e)
81          {
82              throw new ExpressionRuntimeException(CoreMessages.failedToLoad("NamespaceManager"), e);
83          }
84      }
85  
86      @Override
87      public void initialise() throws InitialisationException
88      {
89          super.initialise();
90  
91          if (expression == null)
92          {
93              throw new InitialisationException(
94                  MessageFactory.createStaticMessage("An expression must be supplied to the StandardXPathExtractor"),
95                  this);
96          }
97  
98          if (namespaceManager != null)
99          {
100             if (prefixToNamespaceMap == null)
101             {
102             	prefixToNamespaceMap = new HashMap<String, String>(namespaceManager.getNamespaces());
103             }
104             else
105             {
106             	prefixToNamespaceMap.putAll(namespaceManager.getNamespaces());
107             }
108         }
109 
110         getXpath().setNamespaceContext(new NamespaceContext()
111         {
112         	@Override
113             public String getNamespaceURI(String prefix)
114         	{
115         		return prefixToNamespaceMap.get(prefix);
116         	}
117 
118         	@Override
119             public String getPrefix(String namespaceURI)
120         	{
121 
122         		for (Map.Entry<String, String> entry : prefixToNamespaceMap.entrySet())
123         		{
124         			if (namespaceURI.equals(entry.getValue()))
125         			{
126         				return entry.getKey();
127         			}
128         		}
129 
130         		return null;
131         	}
132 
133         	@Override
134             public Iterator<?> getPrefixes(String namespaceURI)
135         	{
136         		String prefix = getPrefix(namespaceURI);
137         		if (prefix == null)
138         		{
139         			return Collections.emptyList().iterator();
140         		}
141         		else
142         		{
143         			return Arrays.asList(prefix).iterator();
144         		}
145         	}
146         });
147     }
148 
149     @Override
150     public Object doTransform(Object src, String encoding) throws TransformerException
151     {
152         QName resultType;
153         switch (getResultType())
154         {
155             case BOOLEAN :
156                 resultType = XPathConstants.BOOLEAN;
157                 break;
158             case NODE :
159                 resultType = XPathConstants.NODE;
160                 break;
161             case NODESET :
162                 resultType = XPathConstants.NODESET;
163                 break;
164             case NUMBER :
165                 resultType = XPathConstants.NUMBER;
166                 break;
167             default :
168                 resultType = XPathConstants.STRING;
169                 break;
170         }
171 
172         try
173         {
174             if (src instanceof InputSource)
175             {
176                 return xpath.evaluate(expression, (InputSource) src, resultType);
177             }
178             else
179             {
180                 return xpath.evaluate(expression, src, resultType);
181             }
182         }
183         catch (XPathExpressionException e)
184         {
185             throw new TransformerException(this, e);
186         }
187     }
188 
189     /**
190      * @return Returns the expression.
191      */
192     public String getExpression()
193     {
194         return expression;
195     }
196 
197     /**
198      * @param expression The expression to set.
199      */
200     public void setExpression(String expression)
201     {
202         this.expression = expression;
203     }
204 
205     /**
206      * Result type from this transformer.
207      *
208      * @return Result type from this transformer.
209      */
210     public ResultType getResultType()
211     {
212         return resultType;
213     }
214 
215     /**
216      * Result type from this transformer.
217      *
218      * @param resultType Result type from this transformer.
219      */
220     public void setResultType(ResultType resultType)
221     {
222         this.resultType = resultType;
223     }
224 
225     /**
226      * The XPath evaluator.
227      *
228      * @return The XPath evaluator.
229      */
230     public XPath getXpath()
231     {
232         return xpath;
233     }
234 
235     /**
236      * The XPath evaluator.
237      *
238      * @param xPath The XPath evaluator.
239      */
240     public void setXpath(XPath xPath)
241     {
242         this.xpath = xPath;
243     }
244 
245     /**
246      * The prefix-to-namespace map.
247      *
248      * @return The prefix-to-namespace map.
249      */
250     public Map<String, String> getNamespaces()
251     {
252         return prefixToNamespaceMap;
253     }
254 
255     /**
256      * The prefix-to-namespace map.
257      *
258      * @param prefixToNamespaceMap The prefix-to-namespace map.
259      */
260     public void setNamespaces(Map<String, String> prefixToNamespaceMap)
261     {
262         this.prefixToNamespaceMap = prefixToNamespaceMap;
263     }
264 }