From: <ker...@us...> - 2013-11-06 07:09:51
|
Revision: 23316 http://jedit.svn.sourceforge.net/jedit/?rev=23316&view=rev Author: kerik-sf Date: 2013-11-06 07:09:37 +0000 (Wed, 06 Nov 2013) Log Message: ----------- Clicking node-set result shows element in editor - Saxon only! - this is done by letting saxon parse from SAX by itself, so the XPathAdapter interface is extended to let the adapter load the document. - data type displayed is more concise now (returns element(), not the actual qname of the element). - data model of the Node-set summary uses the results directly Modified Paths: -------------- plugins/XSLT/trunk/docs/users-guide.xml plugins/XSLT/trunk/xslt/NodeSetTableModel.java plugins/XSLT/trunk/xslt/Saxon9XPathAdapter.java plugins/XSLT/trunk/xslt/XMLFragmentsString.java plugins/XSLT/trunk/xslt/XPathAdapter.java plugins/XSLT/trunk/xslt/XPathExpressionPanel.java plugins/XSLT/trunk/xslt/XPathTool.java plugins/XSLT/trunk/xslt/XalanXPathAdapter.java plugins/XSLT/trunk/xslt/XalanXPathNode.java plugins/XSLT/trunk/xslt/XsltSettings.java Added Paths: ----------- plugins/XSLT/trunk/xslt/DOMXPathAdapter.java Modified: plugins/XSLT/trunk/docs/users-guide.xml =================================================================== --- plugins/XSLT/trunk/docs/users-guide.xml 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/docs/users-guide.xml 2013-11-06 07:09:37 UTC (rev 23316) @@ -329,18 +329,17 @@ <para>Press Ctrl-Enter when in the XPath expression text area to invoke the "Evaluate XPath" action.</para> </listitem> - </itemizedlist> - </para> - <para> - The following improvements should eventually be made to XPath Tool. - <itemizedlist> - <listitem> - <para> - When the result of an evaluation is a Node set, it would be nice - to have a "Hyper Search" type of result. In other words, each - node in the list could be clicked to highlight the relevant portion - of the XML doc in the current buffer. - </para> + <listitem><para>Select a node in the Node-set summary table to move current's + edit pane caret to the location of the node in the buffer. The file + will be opened if necessary.</para> + <para>This only works for nodes actually coming + from the source document: if you compute 1 + 1, it will not work.</para> + <para>This only work for the Saxon XPath engine. There may be a way to + implement it also for Xalan, but I've not found an obvious one.</para> + <para>The location information provided by the engine is not much: only + a line and column number, corresponding to the end of the parent element + start tag. So it's not easy to select the node, only to place the caret + at the relevant location.</para> </listitem> </itemizedlist> </para> @@ -462,6 +461,9 @@ <itemizedlist> <listitem><para>XPath tool: press Ctrl+Enter from expression panel to trigger evaluating the XPath expression.</para></listitem> <listitem><para>XPath tool: also grab default namespace from input document (xmlns=...).</para></listitem> + <listitem><para>XPath tool: selecting node results from the Node-set summary + opens the buffer if necessary and moves the caret to the location in the document. + This only works with Saxon XPath engine.</para></listitem> </itemizedlist> </para> <para> Added: plugins/XSLT/trunk/xslt/DOMXPathAdapter.java =================================================================== --- plugins/XSLT/trunk/xslt/DOMXPathAdapter.java (rev 0) +++ plugins/XSLT/trunk/xslt/DOMXPathAdapter.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -0,0 +1,113 @@ +/* + * DOMXPathAdapter.java - common code for DOM based XPathAdapters + * + * Copyright (c) 2013 Eric Le Lay + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +package xslt; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +import java.util.Map; +import java.util.HashMap; +import java.util.Collections; + +import org.gjt.sp.jedit.Buffer; +import org.gjt.sp.util.Log; + +import xml.CharSequenceReader; +import xml.PathUtilities; + +/** + * Common code for XPathAdapters based on DOM input. + * There is only xalan for now, but it's mainly to extract + * standard DOM operations from Xalan specific class. + */ +public abstract class DOMXPathAdapter implements XPathAdapter { + + @Override + public Document buildDocument(Buffer source) + throws IOException,ParserConfigurationException,SAXException + { + CharSequence chars = source.getSegment(0,source.getLength()); + CharSequenceReader reader = new CharSequenceReader(chars); + InputSource ss = new InputSource(reader); + ss.setSystemId(PathUtilities.pathToURL(source.getPath())); + return XPathTool.parse(ss); + } + + @Override + public Document buildDocument(URI source) + throws IOException,ParserConfigurationException,SAXException + { + String sourceURL = source.toString(); + InputSource inputSource = xml.Resolver.instance().resolveEntity("",sourceURL); + return XPathTool.parse(inputSource); + } + + @Override + public Map<String,List<String>> grabNamespaces(Document document) + { + Map<String,List<String>> bindings = new HashMap<String,List<String>>(); + + if (document.getImplementation().hasFeature("traversal", "2.0")) { + DocumentTraversal traversable = (DocumentTraversal) document; + NodeIterator iterator = traversable.createNodeIterator( + document, NodeFilter.SHOW_ELEMENT,null, true); + + Node node; + while ((node = iterator.nextNode()) != null) { + NamedNodeMap attrs = node.getAttributes(); + for(int i=0;i<attrs.getLength();i++) { + Node a = attrs.item(i); + + if("xmlns".equals(a.getPrefix()) + || (a.getPrefix() == null && "xmlns".equals(a.getLocalName()))) { + String prefix = a.getPrefix() == null ? "" : a.getLocalName(); + String ns = a.getNodeValue(); + List l; + if(bindings.containsKey(prefix)){ + l = bindings.get(prefix); + } else { + l = new ArrayList<String>(); + bindings.put(prefix,l); + } + if(!l.contains(ns)) { + l.add(ns); + } + } + } + } + } else { + Log.log(Log.ERROR,this,"DomImplementation doesn't support DOM Traversal"); + } + return Collections.emptyMap(); + } +} Property changes on: plugins/XSLT/trunk/xslt/DOMXPathAdapter.java ___________________________________________________________________ Added: svn:keywords + Id Author Revision Date Modified: plugins/XSLT/trunk/xslt/NodeSetTableModel.java =================================================================== --- plugins/XSLT/trunk/xslt/NodeSetTableModel.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/NodeSetTableModel.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -2,6 +2,7 @@ * NodeSetTableModel.java - Table model for XPath node set results * * Copyright (c) 2002 Robert McKinnon + * Copyright (c) 2013 Eric Le Lay * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,9 +22,10 @@ package xslt; import org.gjt.sp.jedit.jEdit; +import org.gjt.sp.util.Log; import javax.swing.table.AbstractTableModel; - +import static xslt.XPathAdapter.XPathNode; /** * Table model for XPath node set results. * @@ -38,15 +40,15 @@ private static final int NAME_COL = 1; private static final int VALUE_COL = 2; - private static final String[] ALL_COLUMNS = {TYPE, NAME, VALUE}; - private static final String[] NO_NAME_COLUMN = {TYPE, VALUE}; - private static final String[] NO_VALUE_COLUMN = {TYPE, NAME}; - private static final String[] NO_NAME_OR_VALUE_COLUMN = {TYPE}; + private static final String[] ALL_COLUMNS_NAMES = {TYPE, NAME, VALUE}; + private static final int[] ALL_COLUMNS = {TYPE_COL, NAME_COL, VALUE_COL}; + private static final String EMPTY_STRING = ""; - private String[] columnNames = ALL_COLUMNS; - private Object[][] data; + private String[] columnNames = ALL_COLUMNS_NAMES; + private int[] columns = ALL_COLUMNS; + private XPathAdapter.Result data; /** @@ -64,7 +66,12 @@ if(data == null) { return 0; } else { - return data.length; + try { + return data.size(); + } catch(Exception e) { + Log.log(Log.WARNING, NodeSetTableModel.class, "Error getting result size", e); + return 0; + } } } @@ -73,16 +80,44 @@ * Implements method from interface {@link javax.swing.table.TableModel}. */ public Object getValueAt(int row, int col) { - Object cell = data[row][col]; - - if(cell == null) { - return EMPTY_STRING; - } else { - return cell; + try{ + if(row >= 0 && row < getRowCount()) { + XPathNode node = data.get(row); + if(col >= 0 && col < columns.length){ + switch(columns[col]){ + case TYPE_COL: + return node.getType(); + case NAME_COL: + return node.getName(); + case VALUE_COL: + return node.getDomValue(); + default: + throw new IllegalStateException("invalid column: "+columns[col]); + } + } } + }catch(Exception e){ + if(e instanceof IllegalStateException) throw (IllegalStateException)e; + else{ + Log.log(Log.WARNING, NodeSetTableModel.class, "Error getting result node info", e); + } + } + + return EMPTY_STRING; } + public XPathNode getValueAt(int row){ + if(row >= 0 && row < getRowCount()) { + try{ + return data.get(row); + }catch(Exception e){ + Log.log(Log.WARNING, NodeSetTableModel.class, "Error getting result node "+row, e); + } + } + return null; + } + /** * Overrides method from class {@link javax.swing.table.AbstractTableModel}. */ @@ -100,99 +135,53 @@ /** - * Overrides method from class {@link javax.swing.table.AbstractTableModel}. - */ - public void setValueAt(Object value, int row, int col) { - data[row][col] = value; - fireTableCellUpdated(row, col); - } - - - /** - * Sets the node type in the given row. - */ - public void setNodeType(String type, int row) { - setValueAt(type, row, TYPE_COL); - } - - - /** - * Sets the node name in the given row. - */ - public void setNodeName(String name, int row) { - setValueAt(name, row, NAME_COL); - } - - - /** - * Sets the node value in the given row. - */ - public void setNodeValue(String value, int row) { - setValueAt(value, row, VALUE_COL); - } - - - /** * Deletes current model rows, puts all columns back in model if necessary and * adds new rows equal to the given new row count. */ - public void resetRows(int newRowCount) { + public void resetRows(XPathAdapter.Result result) throws Exception { if(getRowCount() > 0) { fireTableRowsDeleted(0, getRowCount() - 1); } - if(columnNames != ALL_COLUMNS) { - setAllColumns(); - fireTableStructureChanged(); - } + this.data = result; - this.data = new Object[newRowCount][getColumnCount()]; + if(result.isNodeSet()){ + boolean isNodeWithName = false; + boolean isNodeWithValue = false; + XPathAdapter.XPathNode node; - for(int i = 0; i < newRowCount; i++) { - this.data[i] = new String[columnNames.length]; - } + for (int i = 0; i < result.size(); i++) { + node = result.get(i); - if(newRowCount > 0) { - fireTableRowsInserted(0, newRowCount - 1); - } - } + if (node != null) { + isNodeWithName = isNodeWithName || node.hasExpandedName(); + isNodeWithValue = isNodeWithValue || node.hasDomValue(); + } + } + int[] tmpcols = new int[ALL_COLUMNS.length]; + tmpcols[0] = TYPE_COL; + int icol = 1; + if(isNodeWithName){ + tmpcols[icol++] = NAME_COL; + } + if(isNodeWithValue){ + tmpcols[icol++] = VALUE_COL; + } - private void setAllColumns() { - this.columnNames = ALL_COLUMNS; - fireTableStructureChanged(); - } + columns = new int[icol]; + columnNames = new String[icol]; + for(int i=0;i<columns.length;i++){ + columns[i] = tmpcols[i]; + columnNames[i] = ALL_COLUMNS_NAMES[tmpcols[i]]; + } + fireTableStructureChanged(); - /** - * Removes the node name column from the table model. - */ - public void removeNameColumn() { - // Need to put values from the last column into the middle column - for(int i = 0; i < getRowCount(); i++) { - data[i][NAME_COL] = data[i][VALUE_COL]; + if(result.size() > 0) { + fireTableRowsInserted(0, result.size() - 1); + } } - - this.columnNames = NO_NAME_COLUMN; - fireTableStructureChanged(); } - - /** - * Removes the node value column from the table model. - */ - public void removeValueColumn() { - this.columnNames = NO_VALUE_COLUMN; - fireTableStructureChanged(); - } - - - /** - * Removes the node name and node value columns from the table model. - */ - public void removeNameOrValueColumn() { - this.columnNames = NO_NAME_OR_VALUE_COLUMN; - fireTableStructureChanged(); - } - } \ No newline at end of file Modified: plugins/XSLT/trunk/xslt/Saxon9XPathAdapter.java =================================================================== --- plugins/XSLT/trunk/xslt/Saxon9XPathAdapter.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/Saxon9XPathAdapter.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -1,7 +1,7 @@ /* * Saxon9XPathAdapter.java - use the XPath 2.0 Saxon engine * - * Copyright (c) 2010 Eric Le Lay + * Copyright (c) 2010,2013 Eric Le Lay * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,14 +21,17 @@ import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathFactory; -import javax.xml.xpath.XPathExpressionException; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import org.gjt.sp.jedit.Buffer; + import org.w3c.dom.Document; -import org.w3c.dom.NodeList; -import org.w3c.dom.Node; +import org.xml.sax.SAXException; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; import java.util.Map; import java.util.HashMap; import java.util.List; @@ -36,49 +39,130 @@ import java.util.Iterator; import java.util.Collections; - +import net.sf.saxon.dom.NodeOverNodeInfo; +import net.sf.saxon.s9api.DocumentBuilder; +import net.sf.saxon.s9api.ItemTypeFactory; +import net.sf.saxon.s9api.Processor; +import net.sf.saxon.s9api.SaxonApiException; +import net.sf.saxon.s9api.XdmItem; +import net.sf.saxon.s9api.XdmNode; +import net.sf.saxon.s9api.XdmValue; +import net.sf.saxon.s9api.XPathCompiler; import net.sf.saxon.xpath.XPathFactoryImpl; -import net.sf.saxon.xpath.XPathExpressionImpl; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; -import net.sf.saxon.om.SequenceIterator; +import net.sf.saxon.type.ItemType; import net.sf.saxon.om.NodeInfo; -/*import net.sf.saxon.om.GroundedIterator; -import net.sf.saxon.om.GroundedValue; -*/ -import net.sf.saxon.om.Item; -import net.sf.saxon.dom.DocumentWrapper; -import net.sf.saxon.dom.DOMNodeWrapper; -import net.sf.saxon.dom.DOMNodeList; -import net.sf.saxon.value.SequenceExtent; -import net.sf.saxon.value.Cardinality; import net.sf.saxon.Configuration; -import net.sf.saxon.type.TypeHierarchy; -import net.sf.saxon.type.ItemType; +import org.gjt.sp.util.Log; + +import xml.CharSequenceReader; +import xml.PathUtilities; + /** * Implementation of XPathAdapter using the Saxon 9 engine */ public class Saxon9XPathAdapter implements XPathAdapter { - final XPathFactoryImpl factory = new XPathFactoryImpl(); - - public Result evaluateExpression(Document doc, Map<String,String> prefixes, String expression) throws XPathException,XPathExpressionException { - XPath xpath = factory.newXPath(); - xpath.setNamespaceContext(new NamespaceContextImpl(prefixes)); - - XPathExpressionImpl expr = (XPathExpressionImpl)xpath.compile(expression); - - return new SaxonResult(expr.rawIterator(new DocumentWrapper(doc,doc.getBaseURI(),expr.getConfiguration())),expr.getConfiguration()); + final XPathFactoryImpl factory; + final Configuration config; + final Processor processor; + + public Saxon9XPathAdapter() { + config = new Configuration(); + config.setLineNumbering(true); + factory = new XPathFactoryImpl(config); + processor = new Processor(config); } - - + + @Override + public Document buildDocument(Buffer source) throws IOException,SAXException,SaxonApiException { + CharSequence chars = source.getSegment(0,source.getLength()); + CharSequenceReader reader = new CharSequenceReader(chars); + StreamSource ss = new StreamSource(reader, PathUtilities.pathToURL(source.getPath())); + return buildWrappedDocument(ss); + } + + @Override + public Document buildDocument(URI source) throws IOException,SAXException,SaxonApiException { + //TODO: would it make sense to set the resolver to xml.Resolver ? + StreamSource ss = new StreamSource(source.toString()); + return buildWrappedDocument(ss); + } + + private Document buildWrappedDocument(Source source) throws SaxonApiException,IOException,SAXException { + try { + DocumentBuilder builder = processor.newDocumentBuilder(); + XdmNode doc = builder.build(source); + return (Document)NodeOverNodeInfo.wrap(doc.getUnderlyingNode()); + } catch(SaxonApiException e) { + if(e.getCause() instanceof IOException) { + throw (IOException)e.getCause(); + } else if(e.getCause() instanceof SAXException) { + throw (SAXException)e.getCause(); + } else { + throw e; + } + } + } + + + public Map<String,List<String>> grabNamespaces(Document doc) throws IllegalArgumentException { + if(!(doc instanceof NodeOverNodeInfo))throw new IllegalArgumentException("Document givent to Saxon9XPathAdapter.grabNamespaces not of the right class"); + XdmNode node = new XdmNode(((NodeOverNodeInfo)doc).getUnderlyingNodeInfo()); + + XPathCompiler comp = processor.newXPathCompiler(); + + Map<String,List<String>> bindings = new HashMap<String,List<String>>(); + + try{ + XdmValue res = comp.evaluate( + "for $n in //*/namespace::* return ($n/name(), string($n))" + , node); + + for(int i=0;i<res.size()-1;){ + String prefix = res.itemAt(i++).getStringValue(); + String ns = res.itemAt(i++).getStringValue(); + if(XMLConstants.XML_NS_URI.equals(ns))continue; + List<String> bound = bindings.get(prefix); + if(bound == null){ + bound = new ArrayList<String>(); + bindings.put(prefix, bound); + } + if(!bound.contains(ns)){ + bound.add(ns); + } + } + }catch(SaxonApiException e){ + Log.log(Log.ERROR,this,"known node query failed",e); + } + return bindings; + } + + @Override + public Result evaluateExpression(Document doc, Map<String,String> prefixes, String expression) + throws SaxonApiException,XPathException + { + if(!(doc instanceof NodeOverNodeInfo))throw new IllegalArgumentException("Document givent to Saxon9XPathAdapter.evaluateExpression not of the right class"); + XdmNode node = new XdmNode(((NodeOverNodeInfo)doc).getUnderlyingNodeInfo()); + XPathCompiler comp = processor.newXPathCompiler(); + for(Map.Entry<String,String> en: prefixes.entrySet()){ + comp.declareNamespace(en.getKey(),en.getValue()); + } + + XdmValue res = comp.evaluate(expression, node); + + return new SaxonResult(res, processor); + } + + static class SaxonXPathNode implements XPathNode { - private Item item; + private XdmItem item; private ItemType it; - SaxonXPathNode(Item i,TypeHierarchy hierarchy){ + SaxonXPathNode(XdmItem i,ItemType it){ this.item = i; - this.it = Type.getItemType(item,hierarchy); + this.it = it; } public boolean hasExpandedName(){ @@ -94,7 +178,7 @@ return false; } } - + public boolean hasDomValue(){ switch (it.getPrimitiveType()) { case Type.DOCUMENT: @@ -104,140 +188,128 @@ return true; } } - + public String getType(){ - return it.toString(); + // too much details if not calling getPrimitiveItemType (like "element(Q{urn:joe}hello)") + return it.getPrimitiveItemType().toString(); } - + public String getName(){ - if(item instanceof NodeInfo){ - return ((NodeInfo)item).getDisplayName(); + if(item.getUnderlyingValue() instanceof NodeInfo){ + return ((NodeInfo)item.getUnderlyingValue()).getDisplayName(); }else { return null; } } - + public String getDomValue() throws XPathException{ - return SequenceExtent.makeSequenceExtent(item.iterate()).getStringValue(); + return item.getStringValue(); } - + + /** + * @return the line number of the node + */ + public int getLineNumber(){ + if(item.getUnderlyingValue() instanceof NodeInfo){ + return ((NodeInfo)item.getUnderlyingValue()).getLineNumber(); + }else { + throw new UnsupportedOperationException("I told you I didn't have location information !"); + } + } + + /** + * @return the column number of the node + */ + public int getColumnNumber(){ + if(item.getUnderlyingValue() instanceof NodeInfo){ + return ((NodeInfo)item.getUnderlyingValue()).getColumnNumber(); + }else { + throw new UnsupportedOperationException("I told you I didn't have location information !"); + } + } + + /** + * @return true for nodes, false overwise + */ + public boolean hasLocation() { + return (item.getUnderlyingValue() instanceof NodeInfo); + } + } - + static class SaxonResult implements Result{ - private SequenceExtent se; - private Configuration config; - - SaxonResult(SequenceIterator si,Configuration c) throws XPathException{ - SequenceExtent se = new SequenceExtent(si); - ItemType it = se.getItemType(c.getTypeHierarchy()); + private XdmValue value; + private ItemTypeFactory typeFactory; - this.se = se; - this.config = c; + SaxonResult(XdmValue value, Processor processor) throws XPathException{ + this.value = value; + this.typeFactory = new ItemTypeFactory(processor); } - + public String getType(){ - ItemType it = se.getItemType(config.getTypeHierarchy()); - if(se.getLength()==0) { + if(value.size()==0) { return "empty sequence"; - } else if(se.getLength() == 1) { - return it.toString(); } else { - return "sequence of "+it.toString(); + XdmItem itm = value.itemAt(0); + // too much details if not calling getPrimitiveItemType (like "element(Q{urn:joe}hello)") + ItemType type = typeFactory.getItemType(itm).getUnderlyingItemType().getPrimitiveItemType(); + if(value.size() == 1){ + return type.toString(); + }else{ + return "sequence of "+type.toString(); + } } } - + public boolean isNodeSet(){ return true; } - - public String getStringValue() throws XPathException{ - return se.getStringValue(); + + public String getStringValue() throws XPathException { + if(value.size()==0) { + return "()"; + } else if(value.size() == 1) { + return value.itemAt(0).getStringValue(); + } else { + StringBuilder sb = new StringBuilder(); + sb.append('('); + for(int i=0; i< value.size(); i++){ + XdmItem itm = value.itemAt(i); + if(i>0){ + sb.append(','); + } + sb.append(itm.getStringValue()); + } + sb.append(')'); + return sb.toString(); + } } - + public int size(){ - return se.getLength(); + return value.size(); } - + public XPathNode get(int i){ - return new SaxonXPathNode(se.itemAt(i),config.getTypeHierarchy()); + XdmItem itm = value.itemAt(i); + return new SaxonXPathNode(itm, typeFactory.getItemType(itm).getUnderlyingItemType()); } - + public XMLFragmentsString toXMLFragmentsString() throws XPathException { - XMLFragmentsString res = new XMLFragmentsString(se.getLength()); - for(int i=0;i<se.getLength();i++) { - Item it = se.itemAt(i); - if(it instanceof DOMNodeWrapper) { - res.setNode(i,(Node)((DOMNodeWrapper)it).getRealNode()); + XMLFragmentsString res = new XMLFragmentsString(value.size()); + for(int i=0;i<value.size();i++) { + XdmItem it = value.itemAt(i); + if(it instanceof XdmNode) { + res.setNode(i,NodeOverNodeInfo.wrap(((XdmNode)it).getUnderlyingNode())); } else { res.setText(i,it.getStringValue()); } } return res; } - + public String toString(){ - return "Saxon9Adapter.Result{"+se+"}"; + return "Saxon9Adapter.Result{"+value+"}"; } } - - public static class NamespaceContextImpl implements NamespaceContext{ - private Map<String,String> mappings; - private Map<String,List<String>> reverseMappings; - - public NamespaceContextImpl(Map<String,String> mappings) { - this.mappings = mappings; - } - - public String getNamespaceURI(String prefix){ - if(XMLConstants.XML_NS_PREFIX.equals(prefix)) { - return XMLConstants.XML_NS_URI; - } else if(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) { - return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; - } else if(mappings.containsKey(prefix)) { - return mappings.get(prefix); - } else if(prefix == null){ - throw new IllegalArgumentException("null prefix"); - } else { - return XMLConstants.NULL_NS_URI; - } - } - - public String getPrefix(String namespaceURI){ - Iterator it = getPrefixes(namespaceURI); - if(it.hasNext()) return (String)it.next(); - else return null; - } - - public Iterator getPrefixes(String namespaceURI){ - if(reverseMappings == null) { - initReverseMappings(); - } - - if(XMLConstants.XML_NS_URI.equals(namespaceURI)) { - return Collections.singletonList(XMLConstants.XML_NS_PREFIX).iterator(); - } else if(XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) { - return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE).iterator(); - } else if(reverseMappings.containsKey(namespaceURI)) { - return Collections.unmodifiableList(reverseMappings.get(namespaceURI)).iterator(); - } else if(namespaceURI == null){ - throw new IllegalArgumentException("null namespaceURI"); - } else { - return Collections.emptyList().iterator(); - } - } - - private void initReverseMappings() { - reverseMappings = new HashMap<String,List<String>>(); - for(Map.Entry<String,String> entry: mappings.entrySet()) { - List<String> l; - if(reverseMappings.containsKey(entry.getValue())) { - l = reverseMappings.get(entry.getValue()); - } else { - l = new LinkedList<String>(); - reverseMappings.put(entry.getValue(),l); - } - l.add(entry.getKey()); - } - } - } + } Modified: plugins/XSLT/trunk/xslt/XMLFragmentsString.java =================================================================== --- plugins/XSLT/trunk/xslt/XMLFragmentsString.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/XMLFragmentsString.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -26,6 +26,7 @@ import org.w3c.dom.NodeList; import java.text.MessageFormat; +import javax.xml.XMLConstants; /** * Represents a sequence of XML fragments as a string. @@ -153,7 +154,7 @@ private void appendProcessingInstructionNode(Node node) { buffer.append("<?"); buffer.append(node.getNodeName()); - buffer.append(" "); + buffer.append(' '); buffer.append(node.getNodeValue()); buffer.append("?>"); buffer.append(NL); @@ -238,8 +239,11 @@ private void appendAttributes(NamedNodeMap attributes) { for(int i = 0; i < attributes.getLength(); i++) { + Node attr = attributes.item(i); + // skip ns declarations + if(XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attr.getNamespaceURI()))continue; buffer.append(' '); - appendAttribute(attributes.item(i)); + appendAttribute(attr); } } Modified: plugins/XSLT/trunk/xslt/XPathAdapter.java =================================================================== --- plugins/XSLT/trunk/xslt/XPathAdapter.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/XPathAdapter.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -19,25 +19,52 @@ */ package xslt; -import org.w3c.dom.Document; -import org.w3c.dom.NodeList; +import java.util.List; import java.util.Map; +import org.w3c.dom.Document; + +import org.gjt.sp.jedit.Buffer; +import java.net.URI; + /** * interface embodying all the services required for the XPath Tool */ public interface XPathAdapter { - + /** + * construct an adapter-specific document from given input. + * The XPathAdapter doesn't have to monitor the source to invalidate + * the cache or whatever. + * @return a document for faster later processing or null if not applicable + */ + public Document buildDocument(Buffer source) throws Exception; + + /** + * construct an adapter-specific document from given input. + * The XPathAdapter doesn't have to monitor the source to invalidate + * the cache or whatever. + * @return a document for faster later processing or null if not applicable + */ + public Document buildDocument(URI source) throws Exception; + + + /** * evaluate expression against doc, given prefixes - * @param doc source document + * @param doc source document from previous call to buildDocument (can be null) * @param prefixes prefix->namespace bindings * @param expression xpath expression to evaluate * @return result of the evaluation */ public Result evaluateExpression(Document doc, Map<String,String> prefixes, String expression) throws Exception; - + /** + * get all namespace bindings from source document + * + */ + public Map<String,List<String>> grabNamespaces(Document document); + + /** * result of an evaluation. * Provides methods to get type, size and contents of the result. */ @@ -50,19 +77,19 @@ public String getStringValue() throws Exception; /** @return number of items in the node-set/sequence */ public int size() throws Exception; - + /** * @param i index of the wanted item. Contrary to positions, i starts at 0 * @return ith item of the result */ public XPathNode get(int i) throws Exception; - + /** * @return an XMLFragmentsString configured to represent this result */ public XMLFragmentsString toXMLFragmentsString() throws Exception; } - + /** one component of the Result, used in the Node-set summary table of the XPath tool */ public static interface XPathNode{ /** @return has got a name (e.g. an element has a name) */ @@ -79,5 +106,23 @@ * @return string value of this item */ public String getDomValue()throws Exception; + + /** + * @return the line number of the node, if any (1-based) + * @throws UnsupportedOperationException if not supported + */ + public int getLineNumber() throws UnsupportedOperationException; + + /** + * @return the column number of the node, if any (1-based) + * @throws UnsupportedOperationException if not supported + */ + public int getColumnNumber() throws UnsupportedOperationException; + + /** + * @return is location information available + */ + public boolean hasLocation(); + } } Modified: plugins/XSLT/trunk/xslt/XPathExpressionPanel.java =================================================================== --- plugins/XSLT/trunk/xslt/XPathExpressionPanel.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/XPathExpressionPanel.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -36,7 +36,6 @@ import java.util.SortedSet; import java.util.TreeSet; -import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; @@ -203,7 +202,7 @@ if (wildCardExpr != null) { Document xdoc = null; try { - xdoc = xpathTool.getCurrentDocument(); + xdoc = xpathTool.getCurrentDocument(xpathTool.getXPath()); } catch (Exception e) { XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.buffer-unparseable"), XPathExpressionPanel.this); Modified: plugins/XSLT/trunk/xslt/XPathTool.java =================================================================== --- plugins/XSLT/trunk/xslt/XPathTool.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/XPathTool.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -3,6 +3,7 @@ * * Copyright (C) 2002 Greg Merrill * 2002, 2003, 2004 Robert McKinnon + * 2013 Eric Le Lay * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,12 +34,11 @@ import java.awt.event.ItemListener; import java.io.File; import java.io.IOException; -import java.lang.reflect.Constructor; import java.net.URL; +import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.ArrayList; import java.util.List; import javax.swing.ImageIcon; @@ -64,13 +64,14 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; -import org.apache.xpath.XPathAPI; -import org.apache.xpath.objects.XObject; import org.gjt.sp.jedit.buffer.JEditBuffer; import org.gjt.sp.jedit.Buffer; import org.gjt.sp.jedit.EBMessage; +import org.gjt.sp.jedit.EditBus; +import org.gjt.sp.jedit.EditPane; import org.gjt.sp.jedit.View; import org.gjt.sp.jedit.jEdit; +import org.gjt.sp.jedit.textarea.JEditTextArea; import org.gjt.sp.jedit.buffer.BufferAdapter; import org.gjt.sp.jedit.gui.DefaultFocusComponent; import org.gjt.sp.jedit.msg.BufferUpdate; @@ -80,16 +81,14 @@ import org.gjt.sp.util.Log; import org.gjt.sp.util.Task; import org.gjt.sp.util.ThreadUtilities; + +import static org.gjt.sp.jedit.EditBus.EBHandler; + import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.traversal.DocumentTraversal; -import org.w3c.dom.traversal.NodeFilter; -import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import xml.PathUtilities; +import static xslt.XPathAdapter.XPathNode; /** * GUI for evaluating XPath expressions. @@ -101,7 +100,7 @@ ActionListener, DefaultFocusComponent, ItemListener { public static final String XPATH_ADAPTER_PROP="xpath.adapter"; - + private View view; private final XsltAction grabNSAction = new GrabNSAction(); private final BufferOrFileVFSSelector inputSelectionPanel; @@ -112,10 +111,12 @@ private final ResultsPanel resultValuePanel = new ResultsPanel("xpath.result.value"); private final NodeSetResultsPanel nodeSetTablePanel = new NodeSetResultsPanel("xpath.result.node-set-summary"); private final XmlFragmentsPanel xmlFragmentsPanel = new XmlFragmentsPanel("xpath.result.xml-fragments"); - + private JPanel dataTypePanel; private boolean autoCompleteEnabled; private XPathAdapter adapter; + /* to be able to go to editor upon node-set summary selection */ + private String lastSourcePath; public XPathTool(View view) { super(new GridBagLayout()); @@ -124,7 +125,7 @@ expressionPanel = new XPathExpressionPanel(view); expressionPanel.addActionListener(this); nsPanel = new KeyValuePanel("xpath.ns"); - + inputSelectionPanel = new BufferOrFileVFSSelector(view,"xpath.source"); JPanel panel = new JPanel(new BorderLayout()); panel.add(new JLabel(jEdit.getProperty("xpath.result.data-type.label")), BorderLayout.NORTH); @@ -142,7 +143,7 @@ gbc.fill = GridBagConstraints.BOTH; gbc.weightx = gbc.weighty = 1; gbc.gridy = 2; - + JSplitPane exprNSSplit = getSplitPane(expressionPanel,nsPanel,70); add(exprNSSplit, gbc); @@ -157,7 +158,7 @@ gbc.weighty = 6; gbc.fill = GridBagConstraints.BOTH; add(getSplitPane(), gbc); - + } @@ -172,7 +173,7 @@ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setNamespaceAware(true); - + DocumentBuilder builder = factory.newDocumentBuilder(); builder.setEntityResolver(xml.Resolver.instance()); Document document = builder.parse(source); @@ -181,23 +182,6 @@ /** - * Returns string result of enclosing expression in a XPath <code>string</code> function and evaluating it. - */ - public static String evalString(Document document, String expression) throws TransformerException { - XObject xObject = XPathAPI.eval(document, "string(" + expression + ")"); - return xObject.xstr().toString(); - } - - - /** - * Returns string result of enclosing expression in a XPath <code>count</code> function and evaluating it. - */ - public static int evalCount(Document document, String expression) throws TransformerException { - XObject xObject = XPathAPI.eval(document, "count(" + expression + ")"); - return Integer.parseInt(xObject.xstr().toString()); - } - - /** * Clicks the evaluate XPath button. */ public void clickEvaluateButton() { @@ -205,9 +189,10 @@ } - private XPathAdapter getXPath() { + public XPathAdapter getXPath() { String xpath = jEdit.getProperty(XPATH_ADAPTER_PROP); if(adapter == null || !adapter.getClass().getName().equals(xpath)) { + DocumentCache.destroyCache(); try { adapter = (XPathAdapter)Class.forName(xpath).newInstance(); } catch(ClassNotFoundException e) { @@ -220,17 +205,22 @@ } return adapter; } - + public void actionPerformed(final ActionEvent event) { if(!inputSelectionPanel.isSourceFileDefined()) { GUIUtilities.message(this,"xpath.error.no-source",new Object[]{}); } else { ((JComponent)event.getSource()).setEnabled(false); ThreadUtilities.runInBackground(new Task(){ + @Override + public String getLabel() { + return jEdit.getProperty("xpath.evaluate.label"); + } + public void _run(){ try { evaluateExpression(); - + } catch (IllegalStateException e) { XSLTPlugin.processException(e, e.getMessage(), XPathTool.this); } catch (SAXException e) { // parse problem @@ -250,28 +240,37 @@ } - public Document getCurrentDocument() throws SAXException, ParserConfigurationException, IOException { + public Document getCurrentDocument(XPathAdapter xpath) throws Exception { if (inputSelectionPanel.isFileSelected()) { //take input from file String path = inputSelectionPanel.getSourceFile(); - return DocumentCache.getFromCache(path); + return DocumentCache.getFromCache(xpath,path); } else { // take input from active buffer - return DocumentCache.getFromCache(view.getBuffer()); + return DocumentCache.getFromCache(xpath,view.getBuffer()); } } private void evaluateExpression() throws Exception, IOException, SAXException, TransformerException { - Document document = getCurrentDocument(); + XPathAdapter xpath = getXPath(); + if(xpath != null) { - String expression = expressionPanel.getExpression(); + String sourcePath; + if (inputSelectionPanel.isFileSelected()) { //take input from file + sourcePath = inputSelectionPanel.getSourceFile(); + } else { // take input from active buffer + sourcePath = view.getBuffer().getPath(); + } - XPathAdapter xpath = getXPath(); - if(xpath != null) { + Document document = getCurrentDocument(xpath); + + String expression = expressionPanel.getExpression(); + XPathAdapter.Result result = xpath.evaluateExpression(document,nsPanel.getMap(),expression); Log.log(Log.DEBUG,this,"evaluateExpression returns : "+result); - + + lastSourcePath = sourcePath; expressionPanel.addToHistory(expression); - + dateTypeField.setText(result.getType()); setResultValue(result); setNodeSetResults(result); @@ -336,90 +335,32 @@ * Note: there are four data types in the XPath 1.0 data model: node-set, string, * number, and boolean. * - * @param xObject XObject containing results */ private void setNodeSetResults(XPathAdapter.Result result) throws Exception { NodeSetTableModel tableModel = nodeSetTablePanel.getTableModel(); - if (result.isNodeSet()) { - tableModel.resetRows(result.size()); - boolean isNodeWithName = false; - boolean isNodeWithValue = false; - XPathAdapter.XPathNode node; + tableModel.resetRows(result); + } - for (int i = 0; i < result.size(); i++) { - node = result.get(i); + private void grabNamespaces(){ + XPathAdapter xpath = getXPath(); + if(xpath != null){ + if(inputSelectionPanel.isSourceFileDefined()) { - if (node != null) { - isNodeWithName = isNodeWithName || node.hasExpandedName(); - isNodeWithValue = isNodeWithValue || node.hasDomValue(); - - tableModel.setNodeType(node.getType(), i); - tableModel.setNodeName(node.getName(), i); - tableModel.setNodeValue(node.getDomValue(), i); + Document document = null; + try { + document = getCurrentDocument(xpath); + } catch (SAXException e) { // parse problem + XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.buffer-unparseable"), XPathTool.this); + } catch (ParserConfigurationException e) { // parse problem + XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.buffer-unparseable"), XPathTool.this); + } catch (IOException e) { // parse problem + XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.buffer-unparseable"), XPathTool.this); + } catch (Exception e) { // catch-all + XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.unkown-problem"), XPathTool.this); } - } - if (!isNodeWithName && !isNodeWithValue) { - tableModel.removeNameOrValueColumn(); - } else if (!isNodeWithName) { - tableModel.removeNameColumn(); - } else if (!isNodeWithValue) { - tableModel.removeValueColumn(); - } - } else { - tableModel.resetRows(0); - } - } - - private void grabNamespaces(){ - if(inputSelectionPanel.isSourceFileDefined()) { - - Document document = null; - try { - document = getCurrentDocument(); - } catch (SAXException e) { // parse problem - XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.buffer-unparseable"), XPathTool.this); - } catch (ParserConfigurationException e) { // parse problem - XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.buffer-unparseable"), XPathTool.this); - } catch (IOException e) { // parse problem - XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.buffer-unparseable"), XPathTool.this); - } catch (Exception e) { // catch-all - XSLTPlugin.processException(e, jEdit.getProperty("xpath.result.message.unkown-problem"), XPathTool.this); - } - - if(document != null) { - Map<String,List<String>> bindings = new HashMap<String,List<String>>(); - - if (document.getImplementation().hasFeature("traversal", "2.0")) { - DocumentTraversal traversable = (DocumentTraversal) document; - NodeIterator iterator = traversable.createNodeIterator( - document, NodeFilter.SHOW_ELEMENT,null, true); - - Node node; - while ((node = iterator.nextNode()) != null) { - //Element e = (Element)node; - NamedNodeMap attrs = node.getAttributes(); - for(int i=0;i<attrs.getLength();i++) { - Node a = attrs.item(i); - - if("xmlns".equals(a.getPrefix()) - || (a.getPrefix() == null && "xmlns".equals(a.getLocalName()))) { - String prefix = a.getPrefix() == null ? "" : a.getLocalName(); - String ns = a.getNodeValue(); - List l; - if(bindings.containsKey(prefix)){ - l = bindings.get(prefix); - } else { - l = new ArrayList<String>(); - bindings.put(prefix,l); - } - if(!l.contains(ns)) { - l.add(ns); - } - } - } - } - + if(document != null) { + Map<String, List<String>> bindings = xpath.grabNamespaces(document); Map<String,String> finalMap = new HashMap<String,String>(); for(Map.Entry<String,List<String>> binding : bindings.entrySet()) { String prefix; @@ -430,7 +371,7 @@ } int len = binding.getValue().size(); if(!finalMap.containsKey(prefix) && len == 1) { - finalMap.put(prefix,binding.getValue().get(0)); + finalMap.put(prefix,binding.getValue().get(0)); } else { for(int i=0,j=0;i<len;j++){ String uniq = prefix+j; @@ -441,7 +382,7 @@ } } } - + Log.log(Log.DEBUG,this,"found:"+bindings); Log.log(Log.DEBUG,this,"found:"+finalMap); String[] keys = new String[finalMap.size()]; @@ -452,21 +393,94 @@ values[i] = binding.getValue(); i++; } - + nsPanel.setKeyValues(keys, values); - - } else { - Log.log(Log.ERROR,this,"DomImplementation doesn't support DOM Traversal"); } + + } else { + Log.log(Log.ERROR,this,"Source isn't defined"); + GUIUtilities.message(this,"xpath.ns.grab.error-no-source",new Object[]{}); } - - } else { - Log.log(Log.ERROR,this,"Source isn't defined"); - GUIUtilities.message(this,"xpath.ns.grab.error-no-source",new Object[]{}); } - } - + + private void gotoInEditor(int lineNumber, int columnNumber){ + new GotoDelayed(view.getEditPane(), lastSourcePath, lineNumber, columnNumber); + } + + static class GotoDelayed implements Runnable + { + private final EditPane editPane; + private volatile boolean loadedEventReceived = false; + private Buffer buffer; + private final int line; + private final int col; + + private GotoDelayed(EditPane editPane, String path, int line, int col) + { + this.editPane = editPane; + this.line = line; + this.col = col; + EditBus.addToBus(this); + buffer = getBuffer(editPane.getView(), path); + if(buffer == null) + { + EditBus.removeFromBus(this); + return; + } + editPane.setBuffer(buffer,false); + synchronized (this) + { + if (!loadedEventReceived && buffer.isLoaded()) + { + bufferLoaded(); + } + } + + } + + //{{{ getBuffer() method + private Buffer getBuffer(View view, String path) + { + if(buffer == null) + buffer = jEdit.openFile(view,path); + return buffer; + } //}}} + + public void run() + { + JEditTextArea textArea = editPane.getTextArea(); + // this will be the location of the end of the opening tag + // of the parent element + int pos = buffer.getLineStartOffset(line-1) + col - 1; + textArea.moveCaretPosition(pos); + textArea.requestFocus(); + } + + private void bufferLoaded() + { + synchronized (this) + { + if (!loadedEventReceived) + { + EditBus.removeFromBus(this); + loadedEventReceived = true; + ThreadUtilities.runInDispatchThread(this); + } + } + } + + @EBHandler + public void handleBufferUpdate(BufferUpdate msg) + { + if (msg.getWhat() == BufferUpdate.LOADED && + msg.getBuffer() == buffer) + { + bufferLoaded(); + } + } + } + /** * Panel housing the "Evaluate" button */ @@ -476,7 +490,7 @@ private JCheckBox autoCompleteCheck; EvaluatePanel() { - + grabNamespaces = grabNSAction.getButton(); String iconName = jEdit.getProperty("xpath.evaluate.button.icon"); @@ -492,7 +506,7 @@ button.setToolTipText(toolTipText); button.addActionListener(XPathTool.this); button.setName("xpath.evaluate"); - + Dimension dimension = new Dimension(76, 30); button.setMinimumSize(dimension); button.setPreferredSize(dimension); @@ -506,17 +520,17 @@ } private class GrabNSAction extends XsltAction { - + GrabNSAction(){ super("xpath.ns.grab"); } - + public void actionPerformed(ActionEvent e) { grabNamespaces(); } - + } - + /** * JTextArea that let's tab key change focus to the next component. */ @@ -543,10 +557,10 @@ int height = (int) textArea.getPreferredSize().getHeight(); this.textArea.setMinimumSize(new Dimension(width, height)); this.textArea.setName(name); - + add(label, BorderLayout.NORTH); add(new JScrollPane(this.textArea)); - + JPopupMenu popup = new JPopupMenu(); searchMenuItem = new JMenuItem("Hypersearch"); searchMenuItem.addActionListener(this); @@ -597,8 +611,13 @@ * implements interface {@link javax.swing.event.ListSelectionListener}. */ public void valueChanged(ListSelectionEvent event) { + if(event.getValueIsAdjusting())return; int selectedRow = this.nodeSetTablePanel.table.getSelectedRow(); this.xmlFragmentsPanel.highlightFragment(selectedRow); + XPathNode node = this.nodeSetTablePanel.getTableModel().getValueAt(selectedRow); + if(node != null && node.hasLocation()){ + gotoInEditor(node.getLineNumber(), node.getColumnNumber()); + } } @@ -707,7 +726,7 @@ BufferUpdate bufUpd = (BufferUpdate)message; DocumentCache.handleMessage(bufUpd); } - + public void stop() { DocumentCache.destroyCache(); } @@ -731,12 +750,12 @@ Document document; Object sourceObject; private static Map globalDocumentCache; - + static { createCacheMap(); } - public static Document getFromCache(JEditBuffer sourceBuffer) throws SAXException,ParserConfigurationException,IOException { + public static Document getFromCache(XPathAdapter xpath, JEditBuffer sourceBuffer) throws Exception { DocumentCache cacheObj = (DocumentCache) globalDocumentCache.get(sourceBuffer); if(cacheObj == null){ cacheObj = new BufferDocumentCache(sourceBuffer); @@ -744,10 +763,10 @@ globalDocumentCache.put(sourceBuffer,cacheObj); } } - return cacheObj.getDocument(); + return cacheObj.getDocument(xpath); } - - public static Document getFromCache(String sourceFileName) throws SAXException,ParserConfigurationException,IOException { + + public static Document getFromCache(XPathAdapter xpath, String sourceFileName) throws Exception { File sourceFile = new File(sourceFileName); DocumentCache cacheObj = (DocumentCache) globalDocumentCache.get(sourceFile); if(cacheObj == null){ @@ -756,13 +775,13 @@ globalDocumentCache.put(sourceFile,cacheObj); } } - return cacheObj.getDocument(); + return cacheObj.getDocument(xpath); } - + public static void destroyCache() { createCacheMap(); } - + public static void handleMessage(BufferUpdate bufUpd) { DocumentCache cacheObj = (DocumentCache) globalDocumentCache.get(bufUpd.getBuffer()); if (cacheObj == null) @@ -773,7 +792,7 @@ private static void createCacheMap() { globalDocumentCache = Collections.synchronizedMap(new HashMap()); } - + DocumentCache(Object srcObject) { this.sourceObject = srcObject; } @@ -786,11 +805,7 @@ document = null; } - synchronized void doParse(InputSource src) throws ParserConfigurationException, IOException, SAXException { - document = XPathTool.parse(src); - } - - public Document getDocument() throws SAXException,ParserConfigurationException,IOException { + public Document getDocument(XPathAdapter xpath) throws Exception { return document; } @@ -806,16 +821,16 @@ } @Override - public Document getDocument() throws SAXException,ParserConfigurationException,IOException{ + public Document getDocument(XPathAdapter adapter) throws Exception { File sourceFile = (File)sourceObject; - if (super.getDocument() == null + if (super.getDocument(adapter) == null || fileUpdateTime != sourceFile.lastModified()) { - InputSource inputSource = new InputSource(sourceFile.getName()); - doParse(inputSource); + URI u = sourceFile.toURI(); fileUpdateTime = sourceFile.lastModified(); + document = adapter.buildDocument(u); } - return super.getDocument(); + return super.getDocument(adapter); } } @@ -845,14 +860,12 @@ }); } - public Document getDocument() throws SAXException,ParserConfigurationException,IOException { - if (super.getDocument() == null) { - JEditBuffer sourceBuffer = (JEditBuffer)sourceObject; - String sourceURL = PathUtilities.pathToURL(((Buffer)sourceBuffer).getPath()); - InputSource inputSource = xml.Resolver.instance().resolveEntity("",sourceURL); - doParse(inputSource); + public Document getDocument(XPathAdapter adapter) throws Exception { + if (super.getDocument(adapter) == null) { + Buffer sourceBuffer = (Buffer)sourceObject; + document = adapter.buildDocument(sourceBuffer); } - return super.getDocument(); + return super.getDocument(adapter); } } Modified: plugins/XSLT/trunk/xslt/XalanXPathAdapter.java =================================================================== --- plugins/XSLT/trunk/xslt/XalanXPathAdapter.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/XalanXPathAdapter.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -1,7 +1,7 @@ /* * XalanXPathAdapter.java - implements XPathAdapter using Xalan * - * Copyright (c) 2010 Eric Le Lay + * Copyright (c) 2010, 2013 Eric Le Lay * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,22 +19,13 @@ */ package xslt; -import javax.xml.XMLConstants; -import javax.xml.namespace.NamespaceContext; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathFactory; import javax.xml.transform.TransformerException; + import org.w3c.dom.Document; -import org.w3c.dom.NodeList; import org.w3c.dom.Node; import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.LinkedList; -import java.util.Iterator; -import java.util.Collections; import org.apache.xpath.NodeSetDTM; import org.apache.xpath.XPathAPI; @@ -48,11 +39,10 @@ * Historically, it was included in XPathTool and the XPathAdapter * has been abstracted from its usage. */ -public class XalanXPathAdapter implements XPathAdapter { - +public class XalanXPathAdapter extends DOMXPathAdapter { + public Result evaluateExpression(Document doc, Map<String,String> prefixes, String expression) throws TransformerException { - PrefixResolverImpl res = new PrefixResolverImpl(prefixes); XObject xObject = XPathAPI.eval(doc, expression, res); Modified: plugins/XSLT/trunk/xslt/XalanXPathNode.java =================================================================== --- plugins/XSLT/trunk/xslt/XalanXPathNode.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/XalanXPathNode.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -161,8 +161,10 @@ public String getDomValue() { + + String domValue = this.dtm.getNodeValue(this.nodeHandle); - + domValue += (" -- Location: "+dtm.getSourceLocatorFor(this.nodeHandle).getLineNumber()); if (hasDomValue()) { domValue = XSLTUtilities.removeIn(domValue, (char) 10); //remove '\r' to temporarily fix a bug in the display of results in Windows } @@ -170,4 +172,19 @@ return domValue; } + public int getLineNumber() throws UnsupportedOperationException { + throw new UnsupportedOperationException("Location information not supported for Xalan"); + } + + public int getColumnNumber() throws UnsupportedOperationException { + throw new UnsupportedOperationException("Location information not supported for Xalan"); + } + + + /** + * @return always false + */ + public boolean hasLocation() { + return false; + } } Modified: plugins/XSLT/trunk/xslt/XsltSettings.java =================================================================== --- plugins/XSLT/trunk/xslt/XsltSettings.java 2013-11-05 21:17:15 UTC (rev 23315) +++ plugins/XSLT/trunk/xslt/XsltSettings.java 2013-11-06 07:09:37 UTC (rev 23316) @@ -1,234 +1,252 @@ -/* - * XsltSettings.java - Represents a settings file. - * - * Copyright (C) 2003 Robert McKinnon - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -package xslt; - -import org.gjt.sp.jedit.GUIUtilities; -import org.gjt.sp.jedit.MiscUtilities; -import org.gjt.sp.jedit.jEdit; -import org.gjt.sp.jedit.EditPlugin; -import org.gjt.sp.util.Log; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import javax.swing.JFileChooser; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerException; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; - -import java.util.Map; - - -/** - * Represents a settings file containing the configuration for an XSLT pipeline. - * Is able to be written to a working Ant build.xml file. - * - * @author Robert McKinnon - rob...@us... - */ -public class XsltSettings { - - private XSLTProcessor processor; - - - public XsltSettings(XSLTProcessor processor) { - this.processor = processor; - } - - - public void loadFromFile() throws ParserConfigurationException, IOException, SAXException, TransformerException { - String[] selections = GUIUtilities.showVFSFileDialog(processor.getView(), getSettingsDirectory(), JFileChooser.OPEN_DIALOG, false); - - if(selections != null) { - String settingsFile = selections[0]; - Log.log(Log.DEBUG, this, "settings file: " + settingsFile); - - if(settingsFile.indexOf("://") == -1) { - settingsFile = "file:///" + settingsFile; - } - - InputSource source = new InputSource(settingsFile); - Document document = XPathTool.parse(source); - - String sourceFile = XPathTool.evalString(document, "/project/target[xslt][1]/xslt/@in"); - String resultFile = XPathTool.evalString(document, "/project/target/xslt[starts-with(@out, '$')=false()]/@out"); - Log.log(Log.DEBUG, this, "source: " + sourceFile); - Log.log(Log.DEBUG, this, "result: " + resultFile); - - int stylesheetCount = XPathTool.evalCount(document, "/project/target/xslt"); - int parameterCount = XPathTool.evalCount(document, "/project/target[xslt][1]/xslt/param"); - String[] stylesheets = new String[stylesheetCount]; - String[] parameterNames = new String[parameterCount]; - String[] parameterValues = new String[parameterCount]; - - for(int i = 0; i < stylesheetCount; i++) { - stylesheets[i] = XPathTool.evalString(document, "/project/target[xslt][" + (i + 1) + "]/xslt/@style"); - Log.log(Log.DEBUG, this, "stylsheet " + i + ": " + stylesheets[i]); - } - - for(int i = 0; i < parameterCount; i++) { - String parameterXPath = "/project/target[xslt][1]/xslt/param[" + (i + 1) + "]"; - parameterNames[i] = XPathTool.evalString(document, parameterXPath + "/@name"); - parameterValues[i] = XPathTool.evalString(document, parameterXPath + "/@expression"); - Log.log(Log.DEBUG, this, "parameter: " + parameterNames[i] + "=" + parameterValues[i]); - } - - processor.getInputSelectionPanel().setSourceFile(sourceFile); - - // special case if "New Untitled Buffer" was checked - if(resu... [truncated message content] |