Changeset 9068 in josm


Ignore:
Timestamp:
2015-11-29T19:41:22+01:00 (9 years ago)
Author:
wiktorn
Message:

Replace DOM parser for WMTS GetCapabilities document with StAX parser. Improves
performance dramatically, especially on large documents.

Closes: #12140

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/imagery/WMTSTileSource.java

    r8855 r9068  
    2828import javax.swing.ListSelectionModel;
    2929import javax.swing.table.AbstractTableModel;
    30 import javax.xml.XMLConstants;
    3130import javax.xml.namespace.QName;
    32 import javax.xml.parsers.DocumentBuilder;
    33 import javax.xml.parsers.DocumentBuilderFactory;
    34 import javax.xml.parsers.ParserConfigurationException;
    35 import javax.xml.xpath.XPath;
    36 import javax.xml.xpath.XPathConstants;
    37 import javax.xml.xpath.XPathExpression;
    38 import javax.xml.xpath.XPathExpressionException;
    39 import javax.xml.xpath.XPathFactory;
     31import javax.xml.stream.XMLInputFactory;
     32import javax.xml.stream.XMLStreamException;
     33import javax.xml.stream.XMLStreamReader;
    4034
    4135import org.openstreetmap.gui.jmapviewer.Coordinate;
     
    5549import org.openstreetmap.josm.tools.GBC;
    5650import org.openstreetmap.josm.tools.Utils;
    57 import org.w3c.dom.Document;
    58 import org.w3c.dom.Node;
    59 import org.w3c.dom.NodeList;
    6051
    6152/**
     
    7566    };
    7667
     68    private static final String OWS_NS_URL = "http://www.opengis.net/ows/1.1";
     69    private static final String WMTS_NS_URL = "http://www.opengis.net/wmts/1.0";
     70    private static final String XLINK_NS_URL = "http://www.w3.org/1999/xlink";
     71
    7772    private static class TileMatrix {
    7873        private String identifier;
     
    9590        private String crs;
    9691        private String identifier;
     92
     93        TileMatrixSet(TileMatrixSet tileMatrixSet) {
     94            if (tileMatrixSet != null) {
     95                tileMatrix = new TreeSet<>(tileMatrixSet.tileMatrix);
     96                crs = tileMatrixSet.crs;
     97                identifier = tileMatrixSet.identifier;
     98            }
     99        }
     100
     101        TileMatrixSet() {
     102        }
     103
    97104    }
    98105
    99106    private static class Layer {
     107        Layer(Layer l) {
     108            if (l != null) {
     109                format = l.format;
     110                name = l.name;
     111                baseUrl = l.baseUrl;
     112                style = l.style;
     113                tileMatrixSet = new TileMatrixSet(l.tileMatrixSet);
     114            }
     115        }
     116
     117        Layer() {
     118        }
     119
    100120        private String format;
    101121        private String name;
     
    103123        private String baseUrl;
    104124        private String style;
     125        public Collection<String> tileMatrixSetLinks = new ArrayList<>();
    105126    }
    106127
     
    247268
    248269    private Collection<Layer> getCapabilities() throws IOException {
    249         DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    250         builderFactory.setValidating(false);
    251         builderFactory.setNamespaceAware(false);
    252         try {
    253             builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    254         } catch (ParserConfigurationException e) {
    255             //this should not happen
    256             throw new IllegalArgumentException(e);
    257         }
    258         DocumentBuilder builder = null;
     270        XMLInputFactory factory = XMLInputFactory.newFactory();
    259271        InputStream in = new CachedFile(baseUrl).
    260272                setHttpHeaders(headers).
     
    263275                getInputStream();
    264276        try {
    265             builder = builderFactory.newDocumentBuilder();
    266277            byte[] data = Utils.readBytesFromStream(in);
    267278            if (data == null || data.length == 0) {
    268279                throw new IllegalArgumentException("Could not read data from: " + baseUrl);
    269280            }
    270             Document document = builder.parse(new ByteArrayInputStream(data));
    271             Node getTileOperation = getByXpath(document,
    272                     "/Capabilities/OperationsMetadata/Operation[@name=\"GetTile\"]/DCP/HTTP/Get").item(0);
    273             this.baseUrl = getStringByXpath(getTileOperation, "@href");
    274             this.transferMode = TransferMode.fromString(getStringByXpath(getTileOperation,
    275                     "Constraint[@name=\"GetEncoding\"]/AllowedValues/Value"));
    276             NodeList layersNodeList = getByXpath(document, "/Capabilities/Contents/Layer");
    277             Map<String, TileMatrixSet> matrixSetById = parseMatrices(getByXpath(document, "/Capabilities/Contents/TileMatrixSet"));
    278             return parseLayer(layersNodeList, matrixSetById);
     281            XMLStreamReader reader = factory.createXMLStreamReader(
     282                    new ByteArrayInputStream(data)
     283                    );
     284
     285            Collection<Layer> ret = null;
     286            for (int event = reader.getEventType(); reader.hasNext(); event = reader.next()) {
     287                if (event == XMLStreamReader.START_ELEMENT) {
     288                    if (new QName(OWS_NS_URL, "OperationsMetadata").equals(reader.getName())) {
     289                        parseOperationMetadata(reader);
     290                    }
     291
     292                    if (new QName(WMTS_NS_URL, "Contents").equals(reader.getName())) {
     293                        ret = parseContents(reader);
     294                    }
     295                }
     296            }
     297            return ret;
    279298        } catch (Exception e) {
    280299            throw new IllegalArgumentException(e);
     
    282301    }
    283302
    284     private static String normalizeCapabilitiesUrl(String url) throws MalformedURLException {
     303    /**
     304     * Parse Contents tag. Renturns when reader reaches Contents closing tag
     305     *
     306     * @param reader StAX reader instance
     307     * @return collection of layers within contents with properly linked TileMatrixSets
     308     * @throws XMLStreamException See {@link XMLStreamReader}
     309     */
     310    private static final Collection<Layer> parseContents(XMLStreamReader reader) throws XMLStreamException {
     311        Map<String, TileMatrixSet> matrixSetById = new ConcurrentHashMap<>();
     312        Collection<Layer> layers = new ArrayList<>();
     313        for (int event = reader.getEventType();
     314                reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && new QName(WMTS_NS_URL, "Contents").equals(reader.getName()));
     315                event = reader.next()) {
     316            if (event == XMLStreamReader.START_ELEMENT) {
     317                if (new QName(WMTS_NS_URL, "Layer").equals(reader.getName())) {
     318                    layers.add(parseLayer(reader));
     319                }
     320                if (new QName(WMTS_NS_URL, "TileMatrixSet").equals(reader.getName())) {
     321                    TileMatrixSet entry = parseTileMatrixSet(reader);
     322                    matrixSetById.put(entry.identifier, entry);
     323                }
     324            }
     325        }
     326        Collection<Layer> ret = new ArrayList<>();
     327        // link layers to matrix sets
     328        for (Layer l: layers) {
     329            for (String tileMatrixId: l.tileMatrixSetLinks) {
     330                Layer newLayer = new Layer(l); // create a new layer object for each tile matrix set supported
     331                newLayer.tileMatrixSet = matrixSetById.get(tileMatrixId);
     332                ret.add(newLayer);
     333            }
     334        }
     335        return ret;
     336    }
     337
     338    /**
     339     * Parse Layer tag. Returns when reader will reach Layer closing tag
     340     *
     341     * @param reader StAX reader instance
     342     * @return Layer object, with tileMatrixSetLinks and no tileMatrixSet attribute set.
     343     * @throws XMLStreamException See {@link XMLStreamReader}
     344     */
     345    private static final Layer parseLayer(XMLStreamReader reader) throws XMLStreamException {
     346        Layer layer = new Layer();
     347
     348        for (int event = reader.getEventType();
     349                reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && new QName(WMTS_NS_URL, "Layer").equals(reader.getName()));
     350                event = reader.next()) {
     351            if (event == XMLStreamReader.START_ELEMENT) {
     352                if (new QName(WMTS_NS_URL, "Format").equals(reader.getName())) {
     353                    layer.format = reader.getElementText();
     354                }
     355                if (new QName(OWS_NS_URL, "Identifier").equals(reader.getName())) {
     356                    layer.name = reader.getElementText();
     357                }
     358                if (new QName(WMTS_NS_URL, "ResourceURL").equals(reader.getName()) &&
     359                        "tile".equals(reader.getAttributeValue("", "resourceType"))) {
     360                    layer.baseUrl = reader.getAttributeValue("", "template");
     361                }
     362                if (new QName(WMTS_NS_URL, "Style").equals(reader.getName()) &&
     363                        "true".equals(reader.getAttributeValue("", "isDefault")) &&
     364                        moveReaderToTag(reader, new QName[] {new QName(OWS_NS_URL, "Identifier")})) {
     365                    layer.style = reader.getElementText();
     366                }
     367                if (new QName(WMTS_NS_URL, "TileMatrixSetLink").equals(reader.getName())) {
     368                    layer.tileMatrixSetLinks.add(praseTileMatrixSetLink(reader));
     369                }
     370            }
     371        }
     372        if (layer.style == null) {
     373            layer.style = "";
     374        }
     375        return layer;
     376    }
     377
     378    /**
     379     * Gets TileMatrixSetLink value. Returns when reader is on TileMatrixSetLink closing tag
     380     *
     381     * @param reader StAX reader instance
     382     * @return TileMatrixSetLink identifier
     383     * @throws XMLStreamException See {@link XMLStreamReader}
     384     */
     385    private static final String praseTileMatrixSetLink(XMLStreamReader reader) throws XMLStreamException {
     386        String ret = null;
     387        for (int event = reader.getEventType();
     388                reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT &&
     389                        new QName(WMTS_NS_URL, "TileMatrixSetLink").equals(reader.getName()));
     390                event = reader.next()) {
     391            if (event == XMLStreamReader.START_ELEMENT && new QName(WMTS_NS_URL, "TileMatrixSet").equals(reader.getName())) {
     392                ret = reader.getElementText();
     393            }
     394        }
     395        return ret;
     396    }
     397
     398    /**
     399     * Parses TileMatrixSet section. Returns when reader is on TileMatrixSet closing tag
     400     * @param reader StAX reader instance
     401     * @return TileMatrixSet object
     402     * @throws XMLStreamException See {@link XMLStreamReader}
     403     */
     404    private static final TileMatrixSet parseTileMatrixSet(XMLStreamReader reader) throws XMLStreamException {
     405        TileMatrixSet matrixSet = new TileMatrixSet();
     406        for (int event = reader.getEventType();
     407                reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && new QName(WMTS_NS_URL, "TileMatrixSet").equals(reader.getName()));
     408                event = reader.next()) {
     409                    if (event == XMLStreamReader.START_ELEMENT) {
     410                        if (new QName(OWS_NS_URL, "Identifier").equals(reader.getName())) {
     411                            matrixSet.identifier = reader.getElementText();
     412                        }
     413                        if (new QName(OWS_NS_URL, "SupportedCRS").equals(reader.getName())) {
     414                            matrixSet.crs = crsToCode(reader.getElementText());
     415                        }
     416                        if (new QName(WMTS_NS_URL, "TileMatrix").equals(reader.getName())) {
     417                            matrixSet.tileMatrix.add(parseTileMatrix(reader, matrixSet.crs));
     418                        }
     419                    }
     420        }
     421        return matrixSet;
     422    }
     423
     424    /**
     425     * Parses TileMatrix section. Returns when reader is on TileMatrix closing tag.
     426     * @param reader StAX reader instance
     427     * @param matrixCrs projection used by this matrix
     428     * @return TileMatrix object
     429     * @throws XMLStreamException See {@link XMLStreamReader}
     430     */
     431    private static final TileMatrix parseTileMatrix(XMLStreamReader reader, String matrixCrs) throws XMLStreamException {
     432        Projection matrixProj = Projections.getProjectionByCode(matrixCrs);
     433        TileMatrix ret = new TileMatrix();
     434
     435        if (matrixProj == null) {
     436            // use current projection if none found. Maybe user is using custom string
     437            matrixProj = Main.getProjection();
     438        }
     439        for (int event = reader.getEventType();
     440                reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && new QName(WMTS_NS_URL, "TileMatrix").equals(reader.getName()));
     441                event = reader.next()) {
     442            if (event == XMLStreamReader.START_ELEMENT) {
     443                if (new QName(OWS_NS_URL, "Identifier").equals(reader.getName())) {
     444                    ret.identifier = reader.getElementText();
     445                }
     446                if (new QName(WMTS_NS_URL, "ScaleDenominator").equals(reader.getName())) {
     447                    ret.scaleDenominator = Double.parseDouble(reader.getElementText());
     448                }
     449                if (new QName(WMTS_NS_URL, "TopLeftCorner").equals(reader.getName())) {
     450                    String[] topLeftCorner = reader.getElementText().split(" ");
     451                    if (matrixProj.switchXY()) {
     452                        ret.topLeftCorner = new EastNorth(Double.parseDouble(topLeftCorner[1]), Double.parseDouble(topLeftCorner[0]));
     453                    } else {
     454                        ret.topLeftCorner = new EastNorth(Double.parseDouble(topLeftCorner[0]), Double.parseDouble(topLeftCorner[1]));
     455                    }
     456                }
     457                if (new QName(WMTS_NS_URL, "TileHeight").equals(reader.getName())) {
     458                    ret.tileHeight = Integer.parseInt(reader.getElementText());
     459                }
     460                if (new QName(WMTS_NS_URL, "TileWidth").equals(reader.getName())) {
     461                    ret.tileWidth = Integer.parseInt(reader.getElementText());
     462                }
     463                if (new QName(WMTS_NS_URL, "MatrixHeight").equals(reader.getName())) {
     464                    ret.matrixHeight = Integer.parseInt(reader.getElementText());
     465                }
     466                if (new QName(WMTS_NS_URL, "MatrixWidth").equals(reader.getName())) {
     467                    ret.matrixWidth = Integer.parseInt(reader.getElementText());
     468                }
     469            }
     470        }
     471        if (ret.tileHeight != ret.tileWidth) {
     472            throw new AssertionError(tr("Only square tiles are supported. {0}x{1} returned by server for TileMatrix identifier {2}",
     473                    ret.tileHeight, ret.tileWidth, ret.identifier));
     474        }
     475        return ret;
     476    }
     477
     478    /**
     479     * Parses OperationMetadata section. Returns when reader is on OperationsMetadata closing tag.
     480     * Sets this.baseUrl and this.transferMode
     481     *
     482     * @param reader StAX reader instance
     483     * @throws XMLStreamException See {@link XMLStreamReader}
     484     */
     485    private void parseOperationMetadata(XMLStreamReader reader) throws XMLStreamException {
     486        for (int event = reader.getEventType();
     487                reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT &&
     488                        new QName(OWS_NS_URL, "OperationsMetadata").equals(reader.getName()));
     489                event = reader.next()) {
     490            if (event == XMLStreamReader.START_ELEMENT) {
     491                if (new QName(OWS_NS_URL, "Operation").equals(reader.getName()) && "GetTile".equals(reader.getAttributeValue("", "name")) &&
     492                        moveReaderToTag(reader, new QName[]{
     493                                new QName(OWS_NS_URL, "DCP"),
     494                                new QName(OWS_NS_URL, "HTTP"),
     495                                new QName(OWS_NS_URL, "Get"),
     496
     497                        })) {
     498                    this.baseUrl = reader.getAttributeValue(XLINK_NS_URL, "href");
     499                    this.transferMode = getTransferMode(reader);
     500                }
     501            }
     502        }
     503    }
     504
     505    /**
     506     * Parses Operation[@name='GetTile']/DCP/HTTP/Get section. Returns when reader is on Get closing tag.
     507     * @param reader StAX reader instance
     508     * @return TransferMode coded in this section
     509     * @throws XMLStreamException See {@link XMLStreamReader}
     510     */
     511    private static final TransferMode getTransferMode(XMLStreamReader reader) throws XMLStreamException {
     512        QName GET_QNAME = new QName(OWS_NS_URL, "Get");
     513
     514        Utils.ensure(GET_QNAME.equals(reader.getName()), "WMTS Parser state invalid. Expected element %s, got %s",
     515                GET_QNAME, reader.getName());
     516        for (int event = reader.getEventType();
     517                reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && GET_QNAME.equals(reader.getName()));
     518                event = reader.next()) {
     519            if (event == XMLStreamReader.START_ELEMENT && new QName(OWS_NS_URL, "Constraint").equals(reader.getName())) {
     520                if ("GetEncoding".equals(reader.getAttributeValue("", "name"))) {
     521                    moveReaderToTag(reader, new QName[]{
     522                            new QName(OWS_NS_URL, "AllowedValues"),
     523                            new QName(OWS_NS_URL, "Value")
     524                    });
     525                    return TransferMode.fromString(reader.getElementText());
     526                }
     527            }
     528        }
     529        return null;
     530    }
     531
     532    /**
     533     * Moves reader to first occurrence of the structure equivalent of Xpath tags[0]/tags[1]../tags[n]. If fails to find
     534     * moves the reader to the closing tag of current tag
     535     *
     536     * @param reader StAX reader instance
     537     * @param tags array of tags
     538     * @return true if tag was found, false otherwise
     539     * @throws XMLStreamException See {@link XMLStreamReader}
     540     */
     541    private static final boolean moveReaderToTag(XMLStreamReader reader, QName[] tags) throws XMLStreamException {
     542        QName stopTag = reader.getName();
     543        int currentLevel = 0;
     544        QName searchTag = tags[currentLevel];
     545        QName parentTag = null;
     546        QName skipTag = null;
     547
     548        for (int event = 0; //skip current element, so we will not skip it as a whole
     549                reader.hasNext() && !(event == XMLStreamReader.END_ELEMENT && stopTag.equals(reader.getName()));
     550                event = reader.next()) {
     551            if (event == XMLStreamReader.END_ELEMENT && skipTag != null && skipTag.equals(reader.getName())) {
     552                skipTag = null;
     553            }
     554            if (skipTag == null) {
     555                if (event == XMLStreamReader.START_ELEMENT) {
     556                    if (searchTag.equals(reader.getName())) {
     557                        currentLevel += 1;
     558                        if (currentLevel >= tags.length) {
     559                            return true; // found!
     560                        }
     561                        parentTag = searchTag;
     562                        searchTag = tags[currentLevel];
     563                    } else {
     564                        skipTag = reader.getName();
     565                    }
     566                }
     567
     568                if (event == XMLStreamReader.END_ELEMENT) {
     569                    if (parentTag != null && parentTag.equals(reader.getName())) {
     570                        currentLevel -= 1;
     571                        searchTag = parentTag;
     572                        if (currentLevel >= 0) {
     573                            parentTag = tags[currentLevel];
     574                        } else {
     575                            parentTag = null;
     576                        }
     577                    }
     578                }
     579            }
     580        }
     581        return false;
     582    }
     583
     584    private static final String normalizeCapabilitiesUrl(String url) throws MalformedURLException {
    285585        URL inUrl = new URL(url);
    286586        URL ret = new URL(inUrl.getProtocol(), inUrl.getHost(), inUrl.getPort(), inUrl.getFile());
     
    288588    }
    289589
    290     private Collection<Layer> parseLayer(NodeList nodeList, Map<String, TileMatrixSet> matrixSetById) throws XPathExpressionException {
    291         Collection<Layer> ret = new ArrayList<>();
    292         for (int layerId = 0; layerId < nodeList.getLength(); layerId++) {
    293             Node layerNode = nodeList.item(layerId);
    294             NodeList tileMatrixSetLinks = getByXpath(layerNode, "TileMatrixSetLink");
    295 
    296             // we add an layer for all matrix sets to allow user to choose, with which tileset he wants to work
    297             for (int tileMatrixId = 0; tileMatrixId < tileMatrixSetLinks.getLength(); tileMatrixId++) {
    298                 Layer layer = new Layer();
    299                 layer.format = getStringByXpath(layerNode, "Format");
    300                 layer.name = getStringByXpath(layerNode, "Identifier");
    301                 layer.baseUrl = getStringByXpath(layerNode, "ResourceURL[@resourceType='tile']/@template");
    302                 layer.style = getStringByXpath(layerNode, "Style[@isDefault='true']/Identifier");
    303                 if (layer.style == null) {
    304                     layer.style = "";
    305                 }
    306                 Node tileMatrixLink = tileMatrixSetLinks.item(tileMatrixId);
    307                 TileMatrixSet tms = matrixSetById.get(getStringByXpath(tileMatrixLink, "TileMatrixSet"));
    308                 layer.tileMatrixSet = tms;
    309                 ret.add(layer);
    310             }
    311         }
    312         return ret;
    313 
    314     }
    315 
    316     private Map<String, TileMatrixSet> parseMatrices(NodeList nodeList) throws XPathExpressionException {
    317         Map<String, TileMatrixSet> ret = new ConcurrentHashMap<>();
    318         for (int matrixSetId = 0; matrixSetId < nodeList.getLength(); matrixSetId++) {
    319             Node matrixSetNode = nodeList.item(matrixSetId);
    320             TileMatrixSet matrixSet = new TileMatrixSet();
    321             matrixSet.identifier = getStringByXpath(matrixSetNode, "Identifier");
    322             matrixSet.crs = crsToCode(getStringByXpath(matrixSetNode, "SupportedCRS"));
    323             NodeList tileMatrixList = getByXpath(matrixSetNode, "TileMatrix");
    324             Projection matrixProj = Projections.getProjectionByCode(matrixSet.crs);
    325             if (matrixProj == null) {
    326                 // use current projection if none found. Maybe user is using custom string
    327                 matrixProj = Main.getProjection();
    328             }
    329             for (int matrixId = 0; matrixId < tileMatrixList.getLength(); matrixId++) {
    330                 Node tileMatrixNode = tileMatrixList.item(matrixId);
    331                 TileMatrix tileMatrix = new TileMatrix();
    332                 tileMatrix.identifier = getStringByXpath(tileMatrixNode, "Identifier");
    333                 tileMatrix.scaleDenominator = Double.parseDouble(getStringByXpath(tileMatrixNode, "ScaleDenominator"));
    334                 String[] topLeftCorner = getStringByXpath(tileMatrixNode, "TopLeftCorner").split(" ");
    335 
    336                 if (matrixProj.switchXY()) {
    337                     tileMatrix.topLeftCorner = new EastNorth(Double.parseDouble(topLeftCorner[1]), Double.parseDouble(topLeftCorner[0]));
    338                 } else {
    339                     tileMatrix.topLeftCorner = new EastNorth(Double.parseDouble(topLeftCorner[0]), Double.parseDouble(topLeftCorner[1]));
    340                 }
    341                 tileMatrix.tileHeight = Integer.parseInt(getStringByXpath(tileMatrixNode, "TileHeight"));
    342                 tileMatrix.tileWidth = Integer.parseInt(getStringByXpath(tileMatrixNode, "TileHeight"));
    343                 tileMatrix.matrixWidth = getOptionalIntegerByXpath(tileMatrixNode, "MatrixWidth");
    344                 tileMatrix.matrixHeight = getOptionalIntegerByXpath(tileMatrixNode, "MatrixHeight");
    345                 if (tileMatrix.tileHeight != tileMatrix.tileWidth) {
    346                     throw new AssertionError(tr("Only square tiles are supported. {0}x{1} returned by server for TileMatrix identifier {2}",
    347                             tileMatrix.tileHeight, tileMatrix.tileWidth, tileMatrix.identifier));
    348                 }
    349 
    350                 matrixSet.tileMatrix.add(tileMatrix);
    351             }
    352             ret.put(matrixSet.identifier, matrixSet);
    353         }
    354         return ret;
    355     }
    356 
    357     private static String crsToCode(String crsIdentifier) {
     590    private static final String crsToCode(String crsIdentifier) {
    358591        if (crsIdentifier.startsWith("urn:ogc:def:crs:")) {
    359592            return crsIdentifier.replaceFirst("urn:ogc:def:crs:([^:]*):.*:(.*)$", "$1:$2");
    360593        }
    361594        return crsIdentifier;
    362     }
    363 
    364     private static int getOptionalIntegerByXpath(Node document, String xpathQuery) throws XPathExpressionException {
    365         String ret = getStringByXpath(document, xpathQuery);
    366         if (ret == null || "".equals(ret)) {
    367             return -1;
    368         }
    369         return Integer.parseInt(ret);
    370     }
    371 
    372     private static String getStringByXpath(Node document, String xpathQuery) throws XPathExpressionException {
    373         return (String) getByXpath(document, xpathQuery, XPathConstants.STRING);
    374     }
    375 
    376     private static NodeList getByXpath(Node document, String xpathQuery) throws XPathExpressionException {
    377         return (NodeList) getByXpath(document, xpathQuery, XPathConstants.NODESET);
    378     }
    379 
    380     private static Object getByXpath(Node document, String xpathQuery, QName returnType) throws XPathExpressionException {
    381         XPath xpath = XPathFactory.newInstance().newXPath();
    382         XPathExpression expr = xpath.compile(xpathQuery);
    383         return expr.evaluate(document, returnType);
    384595    }
    385596
Note: See TracChangeset for help on using the changeset viewer.