View Javadoc

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