AbstractXPathExpressionEngine.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- package org.openspcoop2.utils.xml;
- import java.io.Reader;
- import java.io.StringReader;
- import java.util.ArrayList;
- import java.util.Enumeration;
- import java.util.List;
- import javax.xml.soap.SOAPElement;
- import org.openspcoop2.utils.LoggerWrapperFactory;
- import org.openspcoop2.utils.SemaphoreLock;
- import org.openspcoop2.utils.Utilities;
- import org.openspcoop2.utils.UtilsException;
- import org.openspcoop2.utils.UtilsMultiException;
- import org.slf4j.Logger;
- import org.w3c.dom.Attr;
- import org.w3c.dom.CharacterData;
- import org.w3c.dom.Comment;
- import org.w3c.dom.Document;
- import org.w3c.dom.Element;
- import org.w3c.dom.EntityReference;
- import org.w3c.dom.NamedNodeMap;
- import org.w3c.dom.Node;
- import org.w3c.dom.NodeList;
- /**
- * Classe utilizzabile per ricerche effettuate tramite espressioni XPath
- *
- * @author Andrea Poli (apoli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public abstract class AbstractXPathExpressionEngine {
-
-
- private static Logger logger = LoggerWrapperFactory.getLogger(AbstractXPathExpressionEngine.class);
- public static void setLogger(Logger logger) {
- AbstractXPathExpressionEngine.logger = logger;
- }
-
-
- /*
-
- Per la sintassi vedi: http://www.w3.org/TR/xpath
- Esempio1: /rubrica/persone/nome/text()
- restituisce il valore del tag nome partendo dalla radice del xml (path assoluto)
- Esempio2:
- //nome/text()
- restituisce il valore del tag nome (path relativo)
- Esempio3
- /rubrica/persone/* /text()
- restituisce il valore di tutti i nodi figli del tag persone
- Esempio4
- //citta/@targa
- restituisce per ogni tag citta il valore dell'attributo targa
- Esempio5
- //persona[position()=3]/text()
- restituisce il terzo nodo persona
- Esempio6
- //citta[@targa='mi']/text()
- restituisce il valore della citta che ha come valore dell'attributo targa, mi
-
- Esempio7
- http://saxon.sourceforge.net/saxon6.5.3/expressions.html
- Ci sono le funzioni per content based
- substring-after(name(//soap:Body/*),":")
- Prende il nome dell'elemento dopo il Body. Sbustring per non prendere il namespace
- Devono essere usati per il nome di un elemento.
-
- Altri esempi per avere il nome del primo child.
- Il piu' corretto e' il seguente, il quale non richiede di conoscere ne namespace del soap envelope, ne namespace del primo child, e funziona sia che il child possiede che non possieda un prefix:*/
- // Viene preso il local name del primo elemento figlio dell'ultimo figlio dell'envelope. L'ultimo figlio dell'envelope e' chiaramente il Body (per evitare casi in cui nel messaggio vi sia l'header)
- //ESPRESSIONE: local-name(/*/*[last()]/*)
-
- // Anche la seguente funziona per trovare il child pero' funziona SOLO se il child possiede un prefix.
- // substring-after(name(/*/*[last()]/*),":")
-
- /*
- Esempio8
- Per concatenare piu' risultati
- concat(//citta[@targa='mi']/text(),//citta[@targa='bo']/text())
- */
-
- // Altri esempi:
- // http://msdn.microsoft.com/en-us/library/ms256086.aspx
-
-
- /* ---------- METODI RITORNANO STRINGHE -------------- */
-
- /**
- * Estrae dal contenuto passato come parametro, l'oggetto identificato dal parametro pattern e dal tipo returnType
- *
- * @param element Elemento SOAP da cui estrarre l'oggetto
- * @param dnc DynamicNamespaceContext
- * @param pattern Pattern che identifica l'oggetto
- * @return Oggetto identificato dal parametro pattern e dal tipo returnType
- * @throws XPathException
- * @throws XPathNotFoundException
- */
- public String getStringMatchPattern(SOAPElement element, DynamicNamespaceContext dnc,String pattern)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
- return (String) this.getMatchPattern(element, dnc, pattern, XPathReturnType.STRING);
- }
-
- /**
- * Estrae dal contenuto passato come parametro, l'oggetto identificato dal parametro pattern e dal tipo returnType
- *
- * @param document Document da cui estrarre l'oggetto
- * @param dnc DynamicNamespaceContext
- * @param pattern Pattern che identifica l'oggetto
- * @return Oggetto identificato dal parametro pattern e dal tipo returnType
- * @throws XPathException
- * @throws XPathNotFoundException
- */
- public String getStringMatchPattern(Document document, DynamicNamespaceContext dnc,String pattern)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
- return (String) this.getMatchPattern(document.getDocumentElement(), dnc, pattern, XPathReturnType.STRING);
- }
-
- /**
- * Estrae dal contenuto passato come parametro, l'oggetto identificato dal parametro pattern e dal tipo returnType
- *
- * @param element Elemento da cui estrarre l'oggetto
- * @param dnc DynamicNamespaceContext
- * @param pattern Pattern che identifica l'oggetto
- * @return Oggetto identificato dal parametro pattern e dal tipo returnType
- * @throws XPathException
- * @throws XPathNotFoundException
- */
- public String getStringMatchPattern(Element element, DynamicNamespaceContext dnc,String pattern)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
- return (String) this.getMatchPattern(element, dnc, pattern, XPathReturnType.STRING);
- }
-
- /**
- * Estrae dal contenuto passato come parametro, l'oggetto identificato dal parametro pattern e dal tipo returnType
- *
- * @param contenuto Contenuto da cui estrarre l'oggetto
- * @param dnc DynamicNamespaceContext
- * @param pattern Pattern che identifica l'oggetto
- * @return Oggetto identificato dal parametro pattern e dal tipo returnType
- * @throws XPathException
- * @throws XPathNotFoundException
- */
- public String getStringMatchPattern(String contenuto, DynamicNamespaceContext dnc,String pattern)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
- return (String) this.getMatchPattern(contenuto, dnc, pattern, XPathReturnType.STRING);
- }
-
-
-
- /* ---------- METODI GENERICI -------------- */
-
- public abstract String getAsString(SOAPElement element);
- public abstract AbstractXMLUtils getXMLUtils();
-
- /**
- * Estrae dal contenuto passato come parametro, l'oggetto identificato dal parametro pattern e dal tipo returnType
- *
- * @param element Elemento SOAP da cui estrarre l'oggetto
- * @param dnc DynamicNamespaceContext
- * @param pattern Pattern che identifica l'oggetto
- * @param returnType Tipo dell'oggetto ritornato
- * @return Oggetto identificato dal parametro pattern e dal tipo returnType
- * @throws XPathException
- * @throws XPathNotFoundException
- */
- public Object getMatchPattern(SOAPElement element, DynamicNamespaceContext dnc,String pattern, XPathReturnType returnType)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
-
- if(element==null)
- throw new XPathException("element xml undefined");
-
- return this._engine_getMatchPattern(element, null, dnc, pattern, returnType);
- }
-
- /**
- * Estrae dal contenuto passato come parametro, l'oggetto identificato dal parametro pattern e dal tipo returnType
- *
- * @param document Document da cui estrarre l'oggetto
- * @param dnc DynamicNamespaceContext
- * @param pattern Pattern che identifica l'oggetto
- * @param returnType Tipo dell'oggetto ritornato
- * @return Oggetto identificato dal parametro pattern e dal tipo returnType
- * @throws XPathException
- * @throws XPathNotFoundException
- */
- public Object getMatchPattern(Document document, DynamicNamespaceContext dnc,String pattern, XPathReturnType returnType)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
-
- if(document==null)
- throw new XPathException("document xml undefined");
- if(document.getDocumentElement()==null)
- throw new XPathException("document.element xml undefined");
-
- return this._engine_getMatchPattern(document.getDocumentElement(), null, dnc, pattern, returnType);
-
- }
-
- /**
- * Estrae dal contenuto passato come parametro, l'oggetto identificato dal parametro pattern e dal tipo returnType
- *
- * @param element Elemento da cui estrarre l'oggetto
- * @param dnc DynamicNamespaceContext
- * @param pattern Pattern che identifica l'oggetto
- * @param returnType Tipo dell'oggetto ritornato
- * @return Oggetto identificato dal parametro pattern e dal tipo returnType
- * @throws XPathException
- * @throws XPathNotFoundException
- */
- public Object getMatchPattern(Element element, DynamicNamespaceContext dnc,String pattern, XPathReturnType returnType)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
-
- if(element==null)
- throw new XPathException("element xml undefined");
-
- return this._engine_getMatchPattern(element, null, dnc, pattern, returnType);
- }
-
- /**
- * Estrae dal contenuto passato come parametro, l'oggetto identificato dal parametro pattern e dal tipo returnType
- *
- * @param content Contenuto da cui estrarre l'oggetto
- * @param dnc DynamicNamespaceContext
- * @param pattern Pattern che identifica l'oggetto
- * @param returnType Tipo dell'oggetto ritornato
- * @return Oggetto identificato dal parametro pattern e dal tipo returnType
- * @throws XPathException
- * @throws XPathNotFoundException
- */
- public Object getMatchPattern(String content, DynamicNamespaceContext dnc,String pattern, XPathReturnType returnType)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
-
- if(content==null)
- throw new XPathException("content undefined");
-
- return this._engine_getMatchPattern(null, content, dnc, pattern, returnType);
-
- }
-
-
-
- /* ---------- ENGINE -------------- */
-
- public abstract Element readXPathElement(Element contenutoAsElement);
-
- //private static Integer synchronizedObjectForBugFWK005ParseXerces = Integer.valueOf(1); // vedi test TestBugFWK005ParseXerces
- private static final org.openspcoop2.utils.Semaphore lockObjectForBugFWK005ParseXerces = new org.openspcoop2.utils.Semaphore("BugFWK005ParseXerces");
- private Object _engine_getMatchPattern(
- Element contenutoAsElement, String contenutoAsString,
- DynamicNamespaceContext dncPrivate,String pattern, XPathReturnType returnType)
- throws XPathException,XPathNotFoundException,XPathNotValidException{
- if( (pattern == null) || (pattern.length() == 0))
- throw new XPathNotFoundException("Pattern di ricerca non fornito");
- if(contenutoAsElement == null && contenutoAsString==null)
- throw new XPathNotFoundException("Contenuto su cui effettuare la ricerca non fornito");
- if(contenutoAsElement != null && contenutoAsString!=null)
- throw new XPathNotFoundException("Contenuto su cui effettuare la ricerca ambiguo");
-
- // Validazione espressione XPAth fornita
- pattern = pattern.trim();
- this.validate(pattern);
-
-
- try{
-
- // 1. Instantiate an XPathFactory.
- javax.xml.xpath.XPathFactory factory = this.getXMLUtils().getXPathFactory();
-
- // 2. Use the XPathFactory to create a new XPath object
- javax.xml.xpath.XPath xpath = factory.newXPath();
- if(xpath==null){
- throw new Exception("Costruzione xpath non riuscita");
- }
-
- // 3. Set the Namespaces
-
- // 3.1. Clone dnc, verra' modificato in convertNamespaces
- DynamicNamespaceContext dnc = null;
- if(dncPrivate!=null){
- dnc = (DynamicNamespaceContext) dncPrivate.clone();
- }
-
- // 3.2 // Risoluzione namespace {http:///}
- // NOTA: da utilizzare con {http://namespace}localName
- // BugFix: se per errore viene utilizzato {http://namespace}:localName prima di effettuare la risoluzione del namespace viene eliminato il ':'
- if(dnc!=null){
- pattern = pattern.replaceAll("}:", "}");
- pattern = this.convertNamespaces(pattern, dnc);
- }
- //System.out.println("PATTERN: ["+pattern+"]");
- // 3.3 set dnc in xpath
- if(dnc!=null)
- xpath.setNamespaceContext(dnc);
-
- // 3.4
- // Bug fix: se il contenuto possiede una namespace associato al prefix di default, poi l'xpath engine non trova l'elemento.
- // es. <prova xmlns="www.namespace">TEST</prova> con xpath /prova/text() non funziona.
- // if(dnc.getNamespaceURI(javax.xml.XMLConstants.DEFAULT_NS_PREFIX).equals(javax.xml.XMLConstants.NULL_NS_URI) == false ){
- // //System.out.println("PATCH CONTENUTO PER NAMESPACE DEFAULT: "+dnc.getNamespaceURI(javax.xml.XMLConstants.DEFAULT_NS_PREFIX));
- // contenuto = contenuto.replace("xmlns=\""+dnc.getNamespaceURI(javax.xml.XMLConstants.DEFAULT_NS_PREFIX)+"\"", "");
- // }
- // !!!! NOTA Il fix sopra indicato non era corretto.
- // e' giusto che non lo trova se viene fornito un xpath senza prefisso, poiche' si sta cercando un elemento che non appartiene a nessun namespace.
- // L'xpath sopra funzionera' su un xml definito come <prova>TEST</prova>
- //
- // Ulteriore spiegazione:
- // But since the nodes you are trying to get use a default namespace, without a prefix, using plain XPath,
- // you can only access them by the local-name() and namespace-uri() attributes. Examples:
- // *[local-name()="HelloWorldResult"]/text()
- // Or:
- // *[local-name()="HelloWorldResult" and namespace-uri()='http://tempuri.org/']/text()
- // Or:
- //*[local-name()="HelloWorldResponse" and namespace-uri()='http://tempuri.org/']/*[
- //
- // Siccome la modalita' di utilizzare il local-name e il namespace-uri in un xpath e' elaborioso, abbiamo aggiunto in openspcoop2
- // la possibilita' di indicare il namespace {namespace} che verra' convertito in un prefix interno utile al funzionamento dell'xpath.
- // Il pattern da fornire che funziona sull'xml indicato sopra e' /{www.namespace}prova/text()
- // Per ulteriori dettagli vedi metodo convertNamespaces utilizzato in 3.2, all'interno del metodo viene fornita una descrizione dettagliata.
-
-
- // Concatenazione openspcoop.
- if(pattern.startsWith("concat_openspcoop") && pattern.endsWith(")")){
-
- // Check compatibilita' concat_openspcoop
- if(returnType.equals(XPathReturnType.STRING)==false){
- throw new XPathException("Funzione concat_openspcoop non compatibile con un tipo di ritorno: "+returnType.toString());
- }
-
- // Fix , la funzione concat non ritorna eccezione se non riesce a risolvere qualche espressione, e contiene cmq delle costanti.
- // La concatenazione openspcoop, invece ritornera' errore.
- String param = pattern.substring("concat_openspcoop(".length(),pattern.length()-1);
- String [] params =param.split(",");
- StringBuilder bfResult = new StringBuilder();
- for(int i=0; i<params.length;i++){
-
- // Check se abbiamo una costante od una espressione da valutare
- if(params[i].startsWith("\"") && params[i].endsWith("\"")){
-
- // COSTANTE
- bfResult.append(params[i].substring(1,(params[i].length()-1)));
-
- }else{
-
- // 4. Reader
- Reader reader = null;
- if(contenutoAsString!=null){
- try{
- reader = new StringReader(contenutoAsString);
- }catch(Exception e){
- try{
- if( reader != null )
- reader.close();
- } catch(Exception er) {
- // close
- }
- throw e;
- }
- }
-
- // ESPRESSIONE
- // 5. Compile an XPath string into an XPathExpression
- javax.xml.xpath.XPathExpression expression = null;
- try{
- expression = xpath.compile(params[i]);
- }catch(Exception e){
- if(Utilities.existsInnerMessageException(e, "Prefix must resolve to a namespace", true)){
- // e' stato usato un prefisso nell'espressione XPath che non e' risolvibile accedendo ai namespaces del messaggio (dnc)
- throw new XPathNotFoundException("Espressione XPATH contenuta in concat_openspcoop ("+params[i]+") non applicabile al messaggio: "+Utilities.getInnerMessageException(e, "Prefix must resolve to a namespace", true));
- }
- else if(Utilities.existsInnerException(e,javax.xml.transform.TransformerException.class)){
- throw new Exception("Compilazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+Utilities.getInnerException(e, javax.xml.transform.TransformerException.class).getMessage()+")",e);
- }else{
- if(e.getCause()!=null){
- throw new Exception("Compilazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+(Utilities.getLastInnerException(e.getCause())).getMessage()+")",e);
- }else{
- throw new Exception("Compilazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+e.getMessage()+")",e);
- }
- }
- }
- if(expression==null){
- throw new Exception("Costruzione XPathExpression non riuscita per espressione contenuta in concat_openspcoop ("+params[i]+")");
- }
-
-
- // 6. Evaluate the XPath expression on an input document
- String result = null;
- try{
- if(reader!=null) {
- //synchronized (AbstractXPathExpressionEngine.synchronizedObjectForBugFWK005ParseXerces) { // vedi test TestBugFWK005ParseXerces
- SemaphoreLock lock = lockObjectForBugFWK005ParseXerces.acquire("concat_openspcoopEvaluate");
- try {
- result = expression.evaluate(new org.xml.sax.InputSource(reader));
- }finally {
- lockObjectForBugFWK005ParseXerces.release(lock, "concat_openspcoopEvaluate");
- }
- }
- else {
- result = expression.evaluate(this.readXPathElement(contenutoAsElement));
- }
- }catch(Exception e){
- if(Utilities.existsInnerException(e,"com.sun.org.apache.xpath.internal.XPathException")){
- throw new Exception("Valutazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+Utilities.getInnerException(e, "com.sun.org.apache.xpath.internal.XPathException").getMessage()+")",e);
- }
- else if(Utilities.existsInnerException(e,org.apache.xpath.XPathException.class)){
- throw new Exception("Valutazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+Utilities.getInnerException(e, org.apache.xpath.XPathException.class).getMessage()+")",e);
- }
- else{
- if(e.getCause()!=null){
- throw new Exception("Valutazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+(Utilities.getLastInnerException(e.getCause())).getMessage()+")",e);
- }else{
- throw new Exception("Valutazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+e.getMessage()+")",e);
- }
- }
- }
- if(reader!=null)
- reader.close();
-
- if(result == null || "".equals(result)){
- // DEVE ESSERE LANCIATA ECCEZIONE, E' PROPRIO LA FUNZIONALITA DI OPENSPCOOP!
- // Il Concat normale non lancia eccezione e ritorna stringa vuota.
- // Verificato con cxf soap engine
- AbstractXPathExpressionEngine.logger.debug("nessun match trovato per l'espressione xpath contenuta in concat_openspcoop ("+params[i]+")");
- throw new XPathNotFoundException("nessun match trovato per l'espressione xpath contenuta in concat_openspcoop ("+params[i]+")");
- }
- else{
- bfResult.append(result);
- }
- }
- }
-
- if(bfResult.length()<=0){
- StringBuilder bfDNC = new StringBuilder();
- Enumeration<?> en = dnc.getPrefixes();
- while (en.hasMoreElements()) {
- String prefix = (String) en.nextElement();
- bfDNC.append("\n\t- ");
- bfDNC.append("[").append(prefix).append("]=[").append(dnc.getNamespaceURI(prefix)).append("]");
- }
- throw new XPathNotFoundException("nessun match trovato per l'espressione xpath (concat_openspcoop) ["+pattern+"] DynamicNamespaceContext:"+bfDNC.toString());
-
- }else{
- return bfResult.toString();
- }
- }else{
-
- // 4. Reader
- Reader reader = null;
- if(contenutoAsString!=null){
- try{
- reader = new StringReader(contenutoAsString);
- }catch(Exception e){
- try{
- if( reader != null )
- reader.close();
- } catch(Exception er) {
- // close
- }
- throw e;
- }
- }
-
-
- // 5. Compile an XPath string into an XPathExpression
- javax.xml.xpath.XPathExpression expression = null;
- try{
- expression = xpath.compile(pattern);
- }catch(Exception e){
- if(Utilities.existsInnerMessageException(e, "Prefix must resolve to a namespace", true)){
- // e' stato usato un prefisso nell'espressione XPath che non e' risolvibile accedendo ai namespaces del messaggio (dnc)
- throw new XPathNotFoundException("Espressione XPATH non applicabile al messaggio: "+Utilities.getInnerMessageException(e, "Prefix must resolve to a namespace", true));
- }
- else if(Utilities.existsInnerException(e,javax.xml.transform.TransformerException.class)){
- throw new Exception("Compilazione dell'espressione XPATH ha causato un errore ("+Utilities.getInnerException(e, javax.xml.transform.TransformerException.class).getMessage()+")",e);
- }else{
- if(e.getCause()!=null){
- throw new Exception("Compilazione dell'espressione XPATH ha causato un errore ("+(Utilities.getLastInnerException(e.getCause())).getMessage()+")",e);
- }else{
- throw new Exception("Compilazione dell'espressione XPATH ha causato un errore ("+e.getMessage()+")",e);
- }
- }
- }
- if(expression==null){
- throw new Exception("Costruzione XPathExpression non riuscita");
- }
-
- // 6. Evaluate the XPath expression on an input document
- Object result = null;
- try{
- if(reader!=null) {
- //synchronized (AbstractXPathExpressionEngine.synchronizedObjectForBugFWK005ParseXerces) { // vedi test TestBugFWK005ParseXerces
- SemaphoreLock lock = lockObjectForBugFWK005ParseXerces.acquire("standardEvaluate");
- try {
- result = expression.evaluate(new org.xml.sax.InputSource(reader),returnType.getValore());
- }finally {
- lockObjectForBugFWK005ParseXerces.release(lock, "standardEvaluate");
- }
- }else{
- result = expression.evaluate(this.readXPathElement(contenutoAsElement),returnType.getValore());
- }
- }catch(Exception e){
- if(Utilities.existsInnerException(e,"com.sun.org.apache.xpath.internal.XPathException")){
- throw new Exception("Valutazione dell'espressione XPATH ha causato un errore ("+Utilities.getInnerException(e, "com.sun.org.apache.xpath.internal.XPathException").getMessage()+")",e);
- }
- else if(Utilities.existsInnerException(e,org.apache.xpath.XPathException.class)){
- throw new Exception("Valutazione dell'espressione XPATH ha causato un errore ("+Utilities.getInnerException(e, org.apache.xpath.XPathException.class).getMessage()+")",e);
- }
- else{
- if(e.getCause()!=null){
- throw new Exception("Valutazione dell'espressione XPATH ha causato un errore ("+(Utilities.getLastInnerException(e.getCause())).getMessage()+")",e);
- }else{
- throw new Exception("Valutazione dell'espressione XPATH ha causato un errore ("+e.getMessage()+")",e);
- }
- }
- }
- if(reader!=null)
- reader.close();
-
- boolean notFound = false;
- if(result == null){
- notFound = true;
- }
- else if(result instanceof String){
- if("".equals(result)){
- notFound = true;
- }
- }
- else if( (XPathReturnType.NODESET.equals(returnType)) && (result instanceof NodeList)){
- if(((NodeList)result).getLength()<=0){
- notFound=true;
- }
- }
-
- if(notFound){
- //log.info("ContentBased, nessun match trovato");
- StringBuilder bfDNC = new StringBuilder();
- Enumeration<?> en = dnc.getPrefixes();
- while (en.hasMoreElements()) {
- String prefix = (String) en.nextElement();
- bfDNC.append("\n\t- ");
- bfDNC.append("[").append(prefix).append("]=[").append(dnc.getNamespaceURI(prefix)).append("]");
- }
- throw new XPathNotFoundException("nessun match trovato per l'espressione xpath ["+pattern+"] DynamicNamespaceContext:"+bfDNC.toString());
- }
-
- return result;
-
- }
-
- }catch(XPathNotFoundException ex){
- throw ex;
- }catch(Exception e){
- throw new XPathException("getMatchPattern pattern["+pattern+"] error: "+e.getMessage(),e);
- }
- }
-
-
-
-
-
- /* ---------- VALIDATORE -------------- */
-
- public void validate(String path) throws XPathNotValidException{
- try{
-
- path = path.trim();
-
- // Instantiate an XPathFactory.
- javax.xml.xpath.XPathFactory factory = this.getXMLUtils().getXPathFactory();
-
- // Use the XPathFactory to create a new XPath object
- javax.xml.xpath.XPath xpath = factory.newXPath();
- if(xpath==null){
- throw new Exception("Costruzione xpath non riuscita");
- }
-
- // 3. Repleace the Namespaces:
- path = path.replaceAll("}:", "}");
- int index = 0;
- while (path.indexOf("{")!=-1){
- int indexStart = path.indexOf("{");
- int indexEnd = path.indexOf("}");
- if(indexEnd==-1){
- throw new Exception("{ utilizzato senza la rispettiva chiusura }");
- }
- String namespace = path.substring(indexStart+"{".length(),indexEnd);
- if(namespace==null || namespace.equals("")){
- throw new Exception("Namespace non indicato tra {}");
- }
- String prefix = "a"+index+":";
- index++;
- path = path.replace("{"+namespace+"}", prefix);
- }
- //System.out.println("PATTERN PER VALIDAZIONE: ["+path+"]");
-
- if(path.startsWith("concat_openspcoop")){
- // funzione concat
- String param = path.substring("concat_openspcoop(".length(),path.length()-1);
- String [] params =param.split(",");
- for(int i=0; i<params.length;i++){
-
- // Check se abbiamo una costante od una espressione da valutare
- if(params[i].startsWith("\"") && params[i].endsWith("\"")){
-
- // COSTANTE
-
- }else{
-
- javax.xml.xpath.XPathExpression expression = null;
- try{
- expression = xpath.compile(params[i]);
- }catch(Exception e){
- if(Utilities.existsInnerException(e,javax.xml.transform.TransformerException.class)){
- throw new Exception("Compilazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+Utilities.getInnerException(e, javax.xml.transform.TransformerException.class).getMessage()+")",e);
- }else{
- if(e.getCause()!=null){
- throw new Exception("Compilazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+(Utilities.getLastInnerException(e.getCause())).getMessage()+")",e);
- }else{
- throw new Exception("Compilazione dell'espressione XPATH contenuta in concat_openspcoop ("+params[i]+") ha causato un errore ("+e.getMessage()+")",e);
- }
- }
- }
- if(expression==null){
- throw new Exception("Costruzione XPathExpression non riuscita per espressione contenuta in concat_openspcoop ("+params[i]+")");
- }
-
- }
- }
- }
- else{
- // Compile an XPath string into an XPathExpression
- javax.xml.xpath.XPathExpression expression = null;
- try{
- expression = xpath.compile(path);
- }catch(Exception e){
- if(Utilities.existsInnerException(e,javax.xml.transform.TransformerException.class)){
- throw new Exception("Compilazione dell'espressione XPATH ha causato un errore ("+Utilities.getInnerException(e, javax.xml.transform.TransformerException.class).getMessage()+")",e);
- }else{
- if(e.getCause()!=null){
- throw new Exception("Compilazione dell'espressione XPATH ha causato un errore ("+(Utilities.getLastInnerException(e.getCause())).getMessage()+")",e);
- }else{
- throw new Exception("Compilazione dell'espressione XPATH ha causato un errore ("+e.getMessage()+")",e);
- }
- }
- }
- if(expression==null){
- throw new Exception("Costruzione XPathExpression non riuscita");
- }
- }
- }catch(Exception e){
- throw new XPathNotValidException("Validazione dell'xpath indicato ["+path+"] fallita: "+e.getMessage(),e);
- }
- }
-
-
-
-
-
-
-
-
-
- /* -------------- UTILITIES PUBBLICHE ------------------- */
-
- /**
- * Ritorna la rappresentazione testuale di una lista di nodi
- *
- * @param rootNode
- * @return rappresentazione testuale di una lista di nodi
- */
- public String toString(NodeList rootNode){
-
- StringBuilder resultBuffer = new StringBuilder();
- this.toString(rootNode,resultBuffer,1);
- return resultBuffer.toString();
-
- }
- public List<String> toList(NodeList rootNode){
-
- return this.toList(rootNode,1);
-
- }
-
-
- /* -------------- UTILITIES PRIVATE ------------------- */
- private int _prefixIndex = 0;
- private synchronized int _getNextPrefixIndex(){
- this._prefixIndex++;
- return this._prefixIndex;
- }
- private static final String AUTO_PREFIX = "_op2PrefixAutoGeneratedIndex";
- private String convertNamespaces(String path,DynamicNamespaceContext dnc)throws UtilsException{
- while (path.indexOf("{")!=-1){
- int indexStart = path.indexOf("{");
- int indexEnd = path.indexOf("}");
- if(indexEnd==-1){
- throw new UtilsException("Errore durante l'interpretazione del valore ["+path+"]: { utilizzato senza la rispettiva chiusura }");
- }
- String namespace = path.substring(indexStart+"{".length(),indexEnd);
- String prefix = dnc.getPrefix(namespace);
- //System.out.println("PREFIX["+prefix+"]->NS["+namespace+"]");
- if(prefix!=null && !javax.xml.XMLConstants.NULL_NS_URI.equals(prefix)){
- prefix = prefix+":";
- }
- else{
- // aggiungo un prefisso nuovo anche nel caso di prefix "" per gestire la problematica che si presente in questo caso:
- // String xmlCampione = "<prova xmlns=\"www.namespace\">TEST</prova>";
- // NON FUNZIONA con un pattern = "/prova/text()"; (poiche' l'elemento prova ha un namespace, quello di default, mentre nell'xpath non viene indicato)
- // Questo pattern sarebbe quello generato anche dopo la conversione dei namespace se il prefisso e' javax.xml.XMLConstants.NULL_NS_URI
- // FUNZIONA con un pattern = "*[local-name()='prova' and namespace-uri()='www.namespace']/text()"; ma e' piu' elaborato
- // FUNZIONA se registriamo un nuovo prefix da utilizzare solo nel pattern, ad esempio con un pattern = "/_op2PrefixAutoGeneratedIndexNUMBER:prova/text()"
- // dove il prefisso auto-generato _op2PrefixAutoGeneratedIndexNUMBER e' associato al namespace www.namespace nel dnc.
- prefix = AbstractXPathExpressionEngine.AUTO_PREFIX + this._getNextPrefixIndex();
- dnc.addNamespace(prefix, namespace);
- prefix = prefix+":";
- //System.out.println("CASO SPECIALEEEEEEEEEEEEEEEE");
- }
- path = path.replace("{"+namespace+"}", prefix);
- }
- return path;
- }
-
- private void toString(NodeList rootNode,StringBuilder resultBuffer, int livello){
-
- // for(int index = 0; index < rootNode.getLength();index ++){
- // Node aNode = rootNode.item(index);
- // try {
- // System.out.println("DEBUG (livello:"+livello+"): "+getXMLUtils().toString(aNode));
- // }catch(Exception e) {}
- // }
-
- if (rootNode.getLength()==1 &&
- (rootNode.item(0).getNodeType()==Node.TEXT_NODE || rootNode.item(0).getNodeType()==Node.ATTRIBUTE_NODE) &&
- resultBuffer.length()==0){
- //System.out.println("TEXT ["+rootNode.item(0).getNodeType()+"] confronto con ["+Node.TEXT_NODE+"] or ["+Node.ATTRIBUTE_NODE+"]");
- // BugEntityReferences: il metodo getTextContent e anche getNodeValue risolve le entity references
- //String textNodeValue = rootNode.item(0).getTextContent();
- String textNodeValue = null;
- try {
- textNodeValue = _getTextValue_fixEntityReferencies(rootNode.item(0));
- }catch(Throwable t) {
- textNodeValue = rootNode.item(0).getTextContent();
- }
- resultBuffer.append(textNodeValue);
- return;
- }
- boolean findElementoRisultatoMultiplo = false;
- for(int index = 0; index < rootNode.getLength();index ++){
- Node aNode = rootNode.item(index);
- //System.out.println("NODE["+index+"] ["+aNode.getNodeType()+"] confronto con ["+Node.ELEMENT_NODE+"]");
- if (aNode.getNodeType() == Node.ELEMENT_NODE){
- NodeList childNodes = aNode.getChildNodes();
-
- if (childNodes.getLength() > 0){
-
- boolean hasChildNodes = false;
- for(int i=0;i<childNodes.getLength();i++){
- // elimino i text node che possono contenere "\n" con axiom
- Node n = childNodes.item(i);
- if(n.hasChildNodes()){
- hasChildNodes = true;
- break;
- }
- }
-
- if (hasChildNodes){
- resultBuffer.append("<"+aNode.getNodeName());
- this.printAttributes(aNode,resultBuffer);
- resultBuffer.append(">");
-
- this.toString(aNode.getChildNodes(), resultBuffer, (livello+1));
- resultBuffer.append("</"+aNode.getNodeName()+">");
- }
- else {
- resultBuffer.append("<"+aNode.getNodeName());
-
- this.printAttributes(aNode,resultBuffer);
-
- // BugEntityReferences: il metodo getTextContent e anche getNodeValue risolve le entity references
- // String textNodeValue = aNode.getTextContent();
- String textNodeValue = null;
- try {
- textNodeValue = _getTextValue_fixEntityReferencies(aNode);
- }catch(Throwable t) {
- textNodeValue = aNode.getTextContent();
- }
-
- resultBuffer.append(">")
- .append(textNodeValue)
- .append("</").append(aNode.getNodeName()).append(">");
- }
- }
- }
- // Risultati multipli per uno stesso elemento
- else if ( (livello==1) && (aNode.getNodeType() == Node.TEXT_NODE || aNode.getNodeType() == Node.ATTRIBUTE_NODE) ){
- if(findElementoRisultatoMultiplo){
- resultBuffer.append(", ");
- }
- else {
- findElementoRisultatoMultiplo = true;
- }
- // BugEntityReferences: il metodo getTextContent e anche getNodeValue risolve le entity references
- //String textNodeValue = aNode.getTextContent();
- String textNodeValue = null;
- try {
- textNodeValue = _getTextValue_fixEntityReferencies(aNode);
- }catch(Throwable t) {
- textNodeValue = aNode.getTextContent();
- }
- resultBuffer.append("["+index+"]="+textNodeValue);
- }
- }
- }
-
- private String _getTextValue_fixEntityReferencies(Node valueEle) throws Exception {
-
- StringBuilder sb = new StringBuilder();
-
- if(valueEle.getNodeType()==Node.TEXT_NODE || valueEle.getNodeType()==Node.ATTRIBUTE_NODE) {
- //sb.append(valueEle.getTextContent());
- // FIX:
- sb.append(getXMLUtils().toString(valueEle,true));
- }
- else {
- NodeList nl = valueEle.getChildNodes();
- for (int i = 0; i < nl.getLength(); i++) {
- Node item = nl.item(i);
- if ((item instanceof CharacterData && !(item instanceof Comment)) || item instanceof EntityReference) {
- //sb.append(item.getNodeValue());
- // FIX:
- sb.append(getXMLUtils().toString(item,true));
- }
- }
- }
- return sb.toString();
- }
-
- private List<String> toList(NodeList rootNode,int livello){
-
- List<String> l = new ArrayList<>();
-
- if (rootNode.getLength()==1 && rootNode.item(0).getNodeType()==Node.TEXT_NODE){
- //System.out.println("TEXT ["+rootNode.item(0).getNodeType()+"] confronto con ["+Node.TEXT_NODE+"]");
- l.add(rootNode.item(0).getTextContent());
- return l;
- }
- for(int index = 0; index < rootNode.getLength();index ++){
- Node aNode = rootNode.item(index);
- //System.out.println("NODE["+index+"] ["+aNode.getNodeType()+"] confronto con ["+Node.ELEMENT_NODE+"]");
- if (aNode.getNodeType() == Node.ELEMENT_NODE){
- NodeList childNodes = aNode.getChildNodes();
-
- if (childNodes.getLength() > 0){
-
- StringBuilder resultBuffer = new StringBuilder();
-
- boolean hasChildNodes = false;
- for(int i=0;i<childNodes.getLength();i++){
- // elimino i text node che possono contenere "\n" con axiom
- Node n = childNodes.item(i);
- if(n.hasChildNodes()){
- hasChildNodes = true;
- break;
- }
- }
-
- if (hasChildNodes){
- resultBuffer.append("<"+aNode.getNodeName());
- this.printAttributes(aNode,resultBuffer);
- resultBuffer.append(">");
-
- this.toString(aNode.getChildNodes(), resultBuffer, (livello+1));
- resultBuffer.append("</"+aNode.getNodeName()+">");
- }
- else {
- resultBuffer.append("<"+aNode.getNodeName());
-
- this.printAttributes(aNode,resultBuffer);
-
- resultBuffer.append(">"+aNode.getTextContent()+ "</"+aNode.getNodeName()+">");
- }
-
- l.add(resultBuffer.toString());
- }
- }
- // Risultati multipli per uno stesso elemento
- else if ( (livello==1) && (aNode.getNodeType() == Node.TEXT_NODE) ){
- l.add(aNode.getTextContent());
- }
- }
-
- return l;
- }
-
- private void printAttributes(Node aNode,StringBuilder resultBuffer){
- NamedNodeMap attr = aNode.getAttributes();
- for (int i=0;i<attr.getLength();i++){
- Node item = attr.item(i);
- if(item instanceof Attr){
- Attr attribute = (Attr) item;
- //System.out.println("PREFIX["+attribute.getPrefix()+"] LOCALNAME=["+attribute.getLocalName()+"] NAMESPACE["+attribute.getNodeValue()+"]");
- String prefix = attribute.getPrefix();
- if(prefix!=null && !"".equals(prefix)){
- prefix = prefix + ":";
- }else{
- prefix = "";
- }
- // BugEntityReferences: il metodo getTextContent e anche getNodeValue risolve le entity references
- //String value = attribute.getNodeValue();
- String value = null;
- try {
- value = _getTextValue_fixEntityReferencies(attribute);
- }catch(Throwable t) {
- value = attribute.getNodeValue();
- }
- resultBuffer.append(" "+prefix+attribute.getLocalName()+"=\""+value+"\"");
- }else{
- resultBuffer.append(" "+item.toString());
- }
- }
- }
-
-
- public static String extractAndConvertResultAsString(String contentAsString,DynamicNamespaceContext dnc,AbstractXPathExpressionEngine xPathEngine, String pattern, Logger log) throws Exception {
- return AbstractXPathExpressionEngine._extractAndConvertResultAsString(null, contentAsString,
- dnc, xPathEngine, pattern, log);
- }
- public static String extractAndConvertResultAsString(Element element,AbstractXPathExpressionEngine xPathEngine, String pattern, Logger log) throws Exception {
- DynamicNamespaceContext dnc = new DynamicNamespaceContext();
- dnc.findPrefixNamespace(element);
- return AbstractXPathExpressionEngine._extractAndConvertResultAsString(element, null,
- dnc, xPathEngine, pattern, log);
- }
- public static String extractAndConvertResultAsString(Element element,DynamicNamespaceContext dnc,AbstractXPathExpressionEngine xPathEngine, String pattern, Logger log) throws Exception {
- return AbstractXPathExpressionEngine._extractAndConvertResultAsString(element, null,
- dnc, xPathEngine, pattern, log);
- }
- private static String _extractAndConvertResultAsString(Element element,String contentAsString,
- DynamicNamespaceContext dnc,AbstractXPathExpressionEngine xPathEngine, String pattern, Logger log) throws Exception {
-
- // Provo a cercarlo prima come Node
- NodeList nodeList = null;
- Exception exceptionNodeSet = null;
- String risultato = null;
- try{
- if(element!=null) {
- nodeList = (NodeList) xPathEngine.getMatchPattern(element, dnc, pattern,XPathReturnType.NODESET);
- }
- else {
- nodeList = (NodeList) xPathEngine.getMatchPattern(contentAsString, dnc, pattern,XPathReturnType.NODESET);
- }
- if(nodeList!=null){
- risultato = xPathEngine.toString(nodeList);
- }
- }catch(Exception e){
- exceptionNodeSet = e;
- }
-
- // Se non l'ho trovato provo a cercarlo come string (es. il metodo sopra serve per avere l'xml, ma fallisce in caso di concat, in caso di errori di concat_openspcoop....)
- // Insomma il caso dell'xml sopra e' quello speciale, che pero' deve essere eseguito prima, perche' altrimenti il caso string sotto funziona sempre, e quindi non si ottiene mai l'xml.
- if(risultato==null || "".equals(risultato)){
- try{
- if(element!=null) {
- risultato = xPathEngine.getStringMatchPattern(element, dnc, pattern);
- }
- else {
- risultato = xPathEngine.getStringMatchPattern(contentAsString, dnc, pattern);
- }
- }catch(Exception e){
- if(exceptionNodeSet!=null){
- log.debug("Errore avvenuto durante la getStringMatchPattern("+pattern
- +") ("+e.getMessage()+") invocata in seguito all'errore dell'invocazione getMatchPattern("+
- pattern+",NODESET): "+exceptionNodeSet.getMessage(),exceptionNodeSet);
- }
- // lancio questo errore e se presente anche quello con la ricerca notset nodoset.
- if(exceptionNodeSet!=null) {
- throw new UtilsMultiException(e,exceptionNodeSet);
- }
- else {
- throw e;
- }
- }
- }
-
- if(risultato == null || "".equals(risultato)){
- if(exceptionNodeSet!=null){
- log.debug("Non sono stati trovati risultati tramite l'invocazione del metodo getStringMatchPattern("+pattern
- +") invocato in seguito all'errore dell'invocazione getMatchPattern("+
- pattern+",NODESET): "+exceptionNodeSet.getMessage(),exceptionNodeSet);
- // lancio questo errore.
- // Questo errore puo' avvenire perche' ho provato a fare xpath con nodeset
- //throw exceptionNodeSet;
- }
- }
-
- return risultato;
- }
-
-
-
- public static List<String> extractAndConvertResultAsList(String contentAsString,DynamicNamespaceContext dnc,AbstractXPathExpressionEngine xPathEngine, String pattern, Logger log) throws Exception {
- return AbstractXPathExpressionEngine._extractAndConvertResultAsList(null, contentAsString,
- dnc, xPathEngine, pattern, log);
- }
- public static List<String> extractAndConvertResultAsList(Element element,AbstractXPathExpressionEngine xPathEngine, String pattern, Logger log) throws Exception {
- DynamicNamespaceContext dnc = new DynamicNamespaceContext();
- dnc.findPrefixNamespace(element);
- return AbstractXPathExpressionEngine._extractAndConvertResultAsList(element, null,
- dnc, xPathEngine, pattern, log);
- }
- public static List<String> extractAndConvertResultAsList(Element element,DynamicNamespaceContext dnc,AbstractXPathExpressionEngine xPathEngine, String pattern, Logger log) throws Exception {
- return AbstractXPathExpressionEngine._extractAndConvertResultAsList(element, null,
- dnc, xPathEngine, pattern, log);
- }
- private static List<String> _extractAndConvertResultAsList(Element element,String contentAsString,
- DynamicNamespaceContext dnc,AbstractXPathExpressionEngine xPathEngine, String pattern, Logger log) throws Exception {
-
-
- // Provo a cercarlo prima come Node
- NodeList nodeList = null;
- Exception exceptionNodeSet = null;
- List<String> risultato = new ArrayList<>();
- try{
- if(element!=null) {
- nodeList = (NodeList) xPathEngine.getMatchPattern(element, dnc, pattern,XPathReturnType.NODESET);
- }
- else {
- nodeList = (NodeList) xPathEngine.getMatchPattern(contentAsString, dnc, pattern,XPathReturnType.NODESET);
- }
- if(nodeList!=null){
- risultato = xPathEngine.toList(nodeList);
- }
- }catch(Exception e){
- exceptionNodeSet = e;
- }
-
- // Se non l'ho trovato provo a cercarlo come string (es. il metodo sopra serve per avere l'xml, ma fallisce in caso di concat, in caso di errori di concat_openspcoop....)
- // Insomma il caso dell'xml sopra e' quello speciale, che pero' deve essere eseguito prima, perche' altrimenti il caso string sotto funziona sempre, e quindi non si ottiene mai l'xml.
- if(risultato==null || risultato.isEmpty()){
- try{
- String s = null;
- if(element!=null) {
- s = xPathEngine.getStringMatchPattern(element, dnc, pattern);
- }
- else {
- s = xPathEngine.getStringMatchPattern(contentAsString, dnc, pattern);
- }
- if(risultato==null) {
- risultato = new ArrayList<>();
- }
- risultato.add(s);
- }catch(Exception e){
- if(exceptionNodeSet!=null){
- log.debug("Errore avvenuto durante la getStringMatchPattern("+pattern
- +") ("+e.getMessage()+") invocata in seguito all'errore dell'invocazione getMatchPattern("+
- pattern+",NODESET): "+exceptionNodeSet.getMessage(),exceptionNodeSet);
- }
- // lancio questo errore e se presente anche quello con la ricerca notset nodoset.
- if(exceptionNodeSet!=null) {
- throw new UtilsMultiException(e,exceptionNodeSet);
- }
- else {
- throw e;
- }
- }
- }
-
- if(risultato == null || risultato.isEmpty()){
- if(exceptionNodeSet!=null){
- log.debug("Non sono stati trovati risultati tramite l'invocazione del metodo getStringMatchPattern("+pattern
- +") invocato in seguito all'errore dell'invocazione getMatchPattern("+
- pattern+",NODESET): "+exceptionNodeSet.getMessage(),exceptionNodeSet);
- // lancio questo errore.
- // Questo errore puo' avvenire perche' ho provato a fare xpath con nodeset
- //throw exceptionNodeSet;
- }
- }
-
- return risultato;
- }
- }