Index: /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/WikipediaApp.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/WikipediaApp.java	(revision 32694)
+++ /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/WikipediaApp.java	(revision 32695)
@@ -27,9 +27,5 @@
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
 import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
 
 import org.openstreetmap.josm.Main;
@@ -43,5 +39,4 @@
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
 public final class WikipediaApp {
@@ -49,5 +44,5 @@
     public static Pattern WIKIDATA_PATTERN = Pattern.compile("Q\\d+");
     private static final DocumentBuilder DOCUMENT_BUILDER = newDocumentBuilder();
-    private static final XPath X_PATH = XPathFactory.newInstance().newXPath();
+    private static final XPath X_PATH = XPath.getInstance();
 
     private WikipediaApp() {
@@ -80,28 +75,20 @@
                     + "&gsbbox=" + max.lat() + "|" + min.lon() + "|" + min.lat() + "|" + max.lon();
             // parse XML document
-            final XPathExpression xpathPlacemark = X_PATH.compile("//gs");
-            final XPathExpression xpathName = X_PATH.compile("@title");
-            final XPathExpression xpathLat = X_PATH.compile("@lat");
-            final XPathExpression xpathLon = X_PATH.compile("@lon");
             try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
                 final Document doc = DOCUMENT_BUILDER.parse(in);
-                final NodeList nodes = (NodeList) xpathPlacemark.evaluate(doc, XPathConstants.NODESET);
-                final List<WikipediaEntry> entries = new ArrayList<>(nodes.getLength());
-                for (int i = 0; i < nodes.getLength(); i++) {
-                    final Node node = nodes.item(i);
-                    final String name = xpathName.evaluate(node);
-                    final LatLon latLon = new LatLon((
-                            (double) xpathLat.evaluate(node, XPathConstants.NUMBER)),
-                            (double) xpathLon.evaluate(node, XPathConstants.NUMBER));
-                    if ("wikidata".equals(wikipediaLang)) {
-                        entries.add(new WikidataEntry(name, null, latLon, null));
-                    } else {
-                        entries.add(new WikipediaEntry(wikipediaLang, name, name, latLon
-                        ));
-                    }
-                }
+                final List<WikipediaEntry> entries = X_PATH.evaluateNodes("//gs", doc).stream()
+                        .map(node -> {
+                            final String name = X_PATH.evaluateString("@title", node);
+                            final LatLon latLon = new LatLon(
+                                    X_PATH.evaluateDouble("@lat", node),
+                                    X_PATH.evaluateDouble("@lon", node));
+                            if ("wikidata".equals(wikipediaLang)) {
+                                return new WikidataEntry(name, null, latLon, null);
+                            } else {
+                                return new WikipediaEntry(wikipediaLang, name, name, latLon);
+                            }
+                        }).collect(Collectors.toList());
                 if ("wikidata".equals(wikipediaLang)) {
-                    final List<WikidataEntry> withLabel = getLabelForWikidata(entries, Locale.getDefault());
-                    return new ArrayList<>(withLabel);
+                    return getLabelForWikidata(entries, Locale.getDefault()).stream().collect(Collectors.toList());
                 } else {
                     return entries;
@@ -122,16 +109,11 @@
                     "&limit=50" +
                     "&format=xml";
-            final List<WikidataEntry> r = new ArrayList<>();
             try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
                 final Document xml = DOCUMENT_BUILDER.parse(in);
-                final NodeList nodes = (NodeList) X_PATH.compile("//entity").evaluate(xml, XPathConstants.NODESET);
-                final XPathExpression xpathId = X_PATH.compile("@id");
-                for (int i = 0; i < nodes.getLength(); i++) {
-                    final Node node = nodes.item(i);
-                    final String id = (String) xpathId.evaluate(node, XPathConstants.STRING);
-                    r.add(new WikidataEntry(id, null, null, null));
-                }
-            }
-            return getLabelForWikidata(r, localeForLabels);
+                final List<WikidataEntry> r = X_PATH.evaluateNodes("//entity", xml).stream()
+                        .map(node -> new WikidataEntry(X_PATH.evaluateString("@id", node), null, null, null))
+                        .collect(Collectors.toList());
+                return getLabelForWikidata(r, localeForLabels);
+            }
         } catch (Exception ex) {
             throw new RuntimeException(ex);
@@ -165,15 +147,10 @@
 
     static void updateWIWOSMStatus(String wikipediaLang, Collection<WikipediaEntry> entries) {
-        Collection<String> articleNames = new ArrayList<>();
-        for (WikipediaEntry i : entries) {
-            articleNames.add(i.wikipediaArticle);
-        }
         Map<String, Boolean> status = new HashMap<>();
-        if (!articleNames.isEmpty()) {
-            final String url = "https://tools.wmflabs.org/wiwosm/osmjson/getGeoJSON.php?action=check"
-                    + "&lang=" + wikipediaLang;
-
+        if (!entries.isEmpty()) {
+            final String url = "https://tools.wmflabs.org/wiwosm/osmjson/getGeoJSON.php?action=check&lang=" + wikipediaLang;
             try {
-                final String requestBody = "articles=" + Utils.encodeUrl(articleNames.stream().collect(Collectors.joining(",")));
+                final String articles = entries.stream().map(i -> i.wikipediaArticle).collect(Collectors.joining(","));
+                final String requestBody = "articles=" + Utils.encodeUrl(articles);
                 try (final BufferedReader reader = HttpClient.create(new URL(url), "POST").setReasonForRequest("Wikipedia")
                                 .setHeader("Content-Type", "application/x-www-form-urlencoded")
@@ -231,11 +208,9 @@
             try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
                 final Document xml = DOCUMENT_BUILDER.parse(in);
-                final NodeList nodes = (NodeList) X_PATH.compile("//entity").evaluate(xml, XPathConstants.NODESET);
-                for (int i = 0; i < nodes.getLength(); i++) {
-                    final Node node = nodes.item(i);
-                    final String wikidata = (String) X_PATH.compile("./@id").evaluate(node, XPathConstants.STRING);
-                    final String wikipedia = (String) X_PATH.compile("./sitelinks/sitelink/@title").evaluate(node, XPathConstants.STRING);
+                X_PATH.evaluateNodes("//entity", xml).forEach(node -> {
+                    final String wikidata = X_PATH.evaluateString("./@id", node);
+                    final String wikipedia = X_PATH.evaluateString("./sitelinks/sitelink/@title", node);
                     r.put(wikipedia, wikidata);
-                }
+                });
             }
             return r;
@@ -257,12 +232,8 @@
             try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
                 final Document doc = DOCUMENT_BUILDER.parse(in);
-                final NodeList nodes = (NodeList) X_PATH.compile("//ps/@title").evaluate(doc, XPathConstants.NODESET);
-                final List<String> categories = new ArrayList<>(nodes.getLength());
-                for (int i = 0; i < nodes.getLength(); i++) {
-                    final Node node = nodes.item(i);
-                    final String value = node.getNodeValue();
-                    categories.add(value.contains(":") ? value.split(":", 2)[1] : value);
-                }
-                return categories;
+                return X_PATH.evaluateNodes("//ps/@title", doc).stream()
+                        .map(Node::getNodeValue)
+                        .map(value -> value.contains(":") ? value.split(":", 2)[1] : value)
+                        .collect(Collectors.toList());
             }
         } catch (Exception ex) {
@@ -273,5 +244,6 @@
     static String getLabelForWikidata(String wikidataId, Locale locale, String ... preferredLanguage) {
         try {
-            return getLabelForWikidata(Collections.singletonList(new WikidataEntry(wikidataId, null, null, null)), locale, preferredLanguage).get(0).label;
+            final List<WikidataEntry> entry = Collections.singletonList(new WikidataEntry(wikidataId, null, null, null));
+            return getLabelForWikidata(entry, locale, preferredLanguage).get(0).label;
         } catch (IndexOutOfBoundsException ignore) {
             return null;
@@ -303,5 +275,5 @@
                 final Document xml = DOCUMENT_BUILDER.parse(in);
                 for (final WikipediaEntry entry : entries) {
-                    final Node entity = (Node) X_PATH.compile("//entity[@id='" + entry.wikipediaArticle + "']").evaluate(xml, XPathConstants.NODE);
+                    final Node entity = X_PATH.evaluateNode("//entity[@id='" + entry.wikipediaArticle + "']", xml);
                     r.add(new WikidataEntry(
                             entry.wikipediaArticle,
@@ -318,15 +290,12 @@
     }
 
-    private static String getFirstField(Iterable<String> languages, String field, Node entity) throws XPathExpressionException {
-        for (String language : languages) {
-            final String label = (String) X_PATH.compile(language != null
-                    ? ".//" + field + "[@language='" + language + "']/@value"
-                    : ".//" + field + "/@value"
-            ).evaluate(entity, XPathConstants.STRING);
-            if (label != null && !label.isEmpty()) {
-                return label;
-            }
-        }
-        return null;
+    private static String getFirstField(Collection<String> languages, String field, Node entity) throws XPathExpressionException {
+        return languages.stream()
+                .map(language -> X_PATH.evaluateString(language != null
+                        ? ".//" + field + "[@language='" + language + "']/@value"
+                        : ".//" + field + "/@value", entity))
+                .filter(label -> label != null && !label.isEmpty())
+                .findFirst()
+                .orElse(null);
     }
 
@@ -342,12 +311,11 @@
             try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
                 final Document xml = DOCUMENT_BUILDER.parse(in);
-                final NodeList nodes = (NodeList) X_PATH.compile("//ll").evaluate(xml, XPathConstants.NODESET);
-                for (int i = 0; i < nodes.getLength(); i++) {
-                    final String lang = nodes.item(i).getAttributes().getNamedItem("lang").getTextContent();
-                    final String name = nodes.item(i).getTextContent();
-                    r.add(new WikipediaLangArticle(lang, name));
-                }
-            }
-            return r;
+                return X_PATH.evaluateNodes("//ll", xml).stream()
+                        .map(node -> {
+                            final String lang = X_PATH.evaluateString("@lang", node);
+                            final String name = node.getTextContent();
+                            return new WikipediaLangArticle(lang, name);
+                        }).collect(Collectors.toList());
+            }
         } catch (Exception ex) {
             throw new RuntimeException(ex);
@@ -364,11 +332,9 @@
             try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
                 final Document xml = DOCUMENT_BUILDER.parse(in);
-                final Node node = (Node) X_PATH.compile("//coordinates/co").evaluate(xml, XPathConstants.NODE);
+                final Node node = X_PATH.evaluateNode("//coordinates/co", xml);
                 if (node == null) {
                     return null;
                 } else {
-                    final double lat = Double.parseDouble(node.getAttributes().getNamedItem("lat").getTextContent());
-                    final double lon = Double.parseDouble(node.getAttributes().getNamedItem("lon").getTextContent());
-                    return new LatLon(lat, lon);
+                    return new LatLon(X_PATH.evaluateDouble("@lat", node), X_PATH.evaluateDouble("@lon", node));
                 }
             }
Index: /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/XPath.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/XPath.java	(revision 32695)
+++ /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/XPath.java	(revision 32695)
@@ -0,0 +1,139 @@
+// License: GPL. See LICENSE file for details./*
+package org.wikipedia;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+import java.util.AbstractList;
+import java.util.Collection;
+
+public class XPath implements javax.xml.xpath.XPath {
+    private final javax.xml.xpath.XPath xPath;
+    private static XPath INSTANCE = new XPath(XPathFactory.newInstance().newXPath());
+
+    private XPath(javax.xml.xpath.XPath xPath) {
+        this.xPath = xPath;
+    }
+
+    public static XPath getInstance() {
+        return INSTANCE;
+    }
+
+    public static class UncheckedXPathExpressionException extends RuntimeException {
+        public UncheckedXPathExpressionException(Throwable cause) {
+            super(cause);
+        }
+    }
+
+    public String evaluateString(String expression, Object item) throws UncheckedXPathExpressionException {
+        try {
+            return (String) xPath.evaluate(expression, item, XPathConstants.STRING);
+        } catch (XPathExpressionException e) {
+            throw new UncheckedXPathExpressionException(e);
+        }
+    }
+
+    public double evaluateDouble(String expression, Object item) throws UncheckedXPathExpressionException {
+        try {
+            return ((Number) xPath.evaluate(expression, item, XPathConstants.NUMBER)).doubleValue();
+        } catch (XPathExpressionException e) {
+            throw new UncheckedXPathExpressionException(e);
+        }
+    }
+
+    public Node evaluateNode(String expression, Object item) throws UncheckedXPathExpressionException {
+        try {
+            return (Node) evaluate(expression, item, XPathConstants.NODE);
+        } catch (XPathExpressionException e) {
+            throw new UncheckedXPathExpressionException(e);
+        }
+    }
+
+    public Collection<Node> evaluateNodes(String expression, Object item) throws UncheckedXPathExpressionException {
+        try {
+            final NodeList nodes = (NodeList) evaluate(expression, item, XPathConstants.NODESET);
+            return new AbstractList<Node>() {
+                @Override
+                public Node get(int index) {
+                    return nodes.item(index);
+                }
+
+                @Override
+                public int size() {
+                    return nodes.getLength();
+                }
+            };
+        } catch (XPathExpressionException e) {
+            throw new UncheckedXPathExpressionException(e);
+        }
+    }
+
+    @Override
+    public void reset() {
+        xPath.reset();
+    }
+
+    @Override
+    public void setXPathVariableResolver(XPathVariableResolver resolver) {
+        xPath.setXPathVariableResolver(resolver);
+    }
+
+    @Override
+    public XPathVariableResolver getXPathVariableResolver() {
+        return xPath.getXPathVariableResolver();
+    }
+
+    @Override
+    public void setXPathFunctionResolver(XPathFunctionResolver resolver) {
+        xPath.setXPathFunctionResolver(resolver);
+    }
+
+    @Override
+    public XPathFunctionResolver getXPathFunctionResolver() {
+        return xPath.getXPathFunctionResolver();
+    }
+
+    @Override
+    public void setNamespaceContext(NamespaceContext nsContext) {
+        xPath.setNamespaceContext(nsContext);
+    }
+
+    @Override
+    public NamespaceContext getNamespaceContext() {
+        return xPath.getNamespaceContext();
+    }
+
+    @Override
+    public XPathExpression compile(String expression) throws XPathExpressionException {
+        return xPath.compile(expression);
+    }
+
+    @Override
+    public Object evaluate(String expression, InputSource source, QName returnType) throws XPathExpressionException {
+        return xPath.evaluate(expression, source, returnType);
+    }
+
+    @Override
+    public String evaluate(String expression, InputSource source) throws XPathExpressionException {
+        return xPath.evaluate(expression, source);
+    }
+
+    @Override
+    public Object evaluate(String expression, Object item, QName returnType) throws XPathExpressionException {
+        return xPath.evaluate(expression, item, returnType);
+    }
+
+    @Override
+    public String evaluate(String expression, Object item) throws XPathExpressionException {
+        return xPath.evaluate(expression, item);
+    }
+}
