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