Ignore:
Timestamp:
2016-07-21T17:55:50+02:00 (8 years ago)
Author:
simon04
Message:

JOSM/wikipedia: simplify XML parsing using custom XPath class and Java 8

Location:
applications/editors/josm/plugins/wikipedia/src/org/wikipedia
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/wikipedia/src/org/wikipedia/WikipediaApp.java

    r32694 r32695  
    2727import javax.xml.parsers.DocumentBuilderFactory;
    2828import javax.xml.parsers.ParserConfigurationException;
    29 import javax.xml.xpath.XPath;
    30 import javax.xml.xpath.XPathConstants;
    31 import javax.xml.xpath.XPathExpression;
    3229import javax.xml.xpath.XPathExpressionException;
    33 import javax.xml.xpath.XPathFactory;
    3430
    3531import org.openstreetmap.josm.Main;
     
    4339import org.w3c.dom.Document;
    4440import org.w3c.dom.Node;
    45 import org.w3c.dom.NodeList;
    4641
    4742public final class WikipediaApp {
     
    4944    public static Pattern WIKIDATA_PATTERN = Pattern.compile("Q\\d+");
    5045    private static final DocumentBuilder DOCUMENT_BUILDER = newDocumentBuilder();
    51     private static final XPath X_PATH = XPathFactory.newInstance().newXPath();
     46    private static final XPath X_PATH = XPath.getInstance();
    5247
    5348    private WikipediaApp() {
     
    8075                    + "&gsbbox=" + max.lat() + "|" + min.lon() + "|" + min.lat() + "|" + max.lon();
    8176            // parse XML document
    82             final XPathExpression xpathPlacemark = X_PATH.compile("//gs");
    83             final XPathExpression xpathName = X_PATH.compile("@title");
    84             final XPathExpression xpathLat = X_PATH.compile("@lat");
    85             final XPathExpression xpathLon = X_PATH.compile("@lon");
    8677            try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
    8778                final Document doc = DOCUMENT_BUILDER.parse(in);
    88                 final NodeList nodes = (NodeList) xpathPlacemark.evaluate(doc, XPathConstants.NODESET);
    89                 final List<WikipediaEntry> entries = new ArrayList<>(nodes.getLength());
    90                 for (int i = 0; i < nodes.getLength(); i++) {
    91                     final Node node = nodes.item(i);
    92                     final String name = xpathName.evaluate(node);
    93                     final LatLon latLon = new LatLon((
    94                             (double) xpathLat.evaluate(node, XPathConstants.NUMBER)),
    95                             (double) xpathLon.evaluate(node, XPathConstants.NUMBER));
    96                     if ("wikidata".equals(wikipediaLang)) {
    97                         entries.add(new WikidataEntry(name, null, latLon, null));
    98                     } else {
    99                         entries.add(new WikipediaEntry(wikipediaLang, name, name, latLon
    100                         ));
    101                     }
    102                 }
     79                final List<WikipediaEntry> entries = X_PATH.evaluateNodes("//gs", doc).stream()
     80                        .map(node -> {
     81                            final String name = X_PATH.evaluateString("@title", node);
     82                            final LatLon latLon = new LatLon(
     83                                    X_PATH.evaluateDouble("@lat", node),
     84                                    X_PATH.evaluateDouble("@lon", node));
     85                            if ("wikidata".equals(wikipediaLang)) {
     86                                return new WikidataEntry(name, null, latLon, null);
     87                            } else {
     88                                return new WikipediaEntry(wikipediaLang, name, name, latLon);
     89                            }
     90                        }).collect(Collectors.toList());
    10391                if ("wikidata".equals(wikipediaLang)) {
    104                     final List<WikidataEntry> withLabel = getLabelForWikidata(entries, Locale.getDefault());
    105                     return new ArrayList<>(withLabel);
     92                    return getLabelForWikidata(entries, Locale.getDefault()).stream().collect(Collectors.toList());
    10693                } else {
    10794                    return entries;
     
    122109                    "&limit=50" +
    123110                    "&format=xml";
    124             final List<WikidataEntry> r = new ArrayList<>();
    125111            try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
    126112                final Document xml = DOCUMENT_BUILDER.parse(in);
    127                 final NodeList nodes = (NodeList) X_PATH.compile("//entity").evaluate(xml, XPathConstants.NODESET);
    128                 final XPathExpression xpathId = X_PATH.compile("@id");
    129                 for (int i = 0; i < nodes.getLength(); i++) {
    130                     final Node node = nodes.item(i);
    131                     final String id = (String) xpathId.evaluate(node, XPathConstants.STRING);
    132                     r.add(new WikidataEntry(id, null, null, null));
    133                 }
    134             }
    135             return getLabelForWikidata(r, localeForLabels);
     113                final List<WikidataEntry> r = X_PATH.evaluateNodes("//entity", xml).stream()
     114                        .map(node -> new WikidataEntry(X_PATH.evaluateString("@id", node), null, null, null))
     115                        .collect(Collectors.toList());
     116                return getLabelForWikidata(r, localeForLabels);
     117            }
    136118        } catch (Exception ex) {
    137119            throw new RuntimeException(ex);
     
    165147
    166148    static void updateWIWOSMStatus(String wikipediaLang, Collection<WikipediaEntry> entries) {
    167         Collection<String> articleNames = new ArrayList<>();
    168         for (WikipediaEntry i : entries) {
    169             articleNames.add(i.wikipediaArticle);
    170         }
    171149        Map<String, Boolean> status = new HashMap<>();
    172         if (!articleNames.isEmpty()) {
    173             final String url = "https://tools.wmflabs.org/wiwosm/osmjson/getGeoJSON.php?action=check"
    174                     + "&lang=" + wikipediaLang;
    175 
     150        if (!entries.isEmpty()) {
     151            final String url = "https://tools.wmflabs.org/wiwosm/osmjson/getGeoJSON.php?action=check&lang=" + wikipediaLang;
    176152            try {
    177                 final String requestBody = "articles=" + Utils.encodeUrl(articleNames.stream().collect(Collectors.joining(",")));
     153                final String articles = entries.stream().map(i -> i.wikipediaArticle).collect(Collectors.joining(","));
     154                final String requestBody = "articles=" + Utils.encodeUrl(articles);
    178155                try (final BufferedReader reader = HttpClient.create(new URL(url), "POST").setReasonForRequest("Wikipedia")
    179156                                .setHeader("Content-Type", "application/x-www-form-urlencoded")
     
    231208            try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
    232209                final Document xml = DOCUMENT_BUILDER.parse(in);
    233                 final NodeList nodes = (NodeList) X_PATH.compile("//entity").evaluate(xml, XPathConstants.NODESET);
    234                 for (int i = 0; i < nodes.getLength(); i++) {
    235                     final Node node = nodes.item(i);
    236                     final String wikidata = (String) X_PATH.compile("./@id").evaluate(node, XPathConstants.STRING);
    237                     final String wikipedia = (String) X_PATH.compile("./sitelinks/sitelink/@title").evaluate(node, XPathConstants.STRING);
     210                X_PATH.evaluateNodes("//entity", xml).forEach(node -> {
     211                    final String wikidata = X_PATH.evaluateString("./@id", node);
     212                    final String wikipedia = X_PATH.evaluateString("./sitelinks/sitelink/@title", node);
    238213                    r.put(wikipedia, wikidata);
    239                 }
     214                });
    240215            }
    241216            return r;
     
    257232            try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
    258233                final Document doc = DOCUMENT_BUILDER.parse(in);
    259                 final NodeList nodes = (NodeList) X_PATH.compile("//ps/@title").evaluate(doc, XPathConstants.NODESET);
    260                 final List<String> categories = new ArrayList<>(nodes.getLength());
    261                 for (int i = 0; i < nodes.getLength(); i++) {
    262                     final Node node = nodes.item(i);
    263                     final String value = node.getNodeValue();
    264                     categories.add(value.contains(":") ? value.split(":", 2)[1] : value);
    265                 }
    266                 return categories;
     234                return X_PATH.evaluateNodes("//ps/@title", doc).stream()
     235                        .map(Node::getNodeValue)
     236                        .map(value -> value.contains(":") ? value.split(":", 2)[1] : value)
     237                        .collect(Collectors.toList());
    267238            }
    268239        } catch (Exception ex) {
     
    273244    static String getLabelForWikidata(String wikidataId, Locale locale, String ... preferredLanguage) {
    274245        try {
    275             return getLabelForWikidata(Collections.singletonList(new WikidataEntry(wikidataId, null, null, null)), locale, preferredLanguage).get(0).label;
     246            final List<WikidataEntry> entry = Collections.singletonList(new WikidataEntry(wikidataId, null, null, null));
     247            return getLabelForWikidata(entry, locale, preferredLanguage).get(0).label;
    276248        } catch (IndexOutOfBoundsException ignore) {
    277249            return null;
     
    303275                final Document xml = DOCUMENT_BUILDER.parse(in);
    304276                for (final WikipediaEntry entry : entries) {
    305                     final Node entity = (Node) X_PATH.compile("//entity[@id='" + entry.wikipediaArticle + "']").evaluate(xml, XPathConstants.NODE);
     277                    final Node entity = X_PATH.evaluateNode("//entity[@id='" + entry.wikipediaArticle + "']", xml);
    306278                    r.add(new WikidataEntry(
    307279                            entry.wikipediaArticle,
     
    318290    }
    319291
    320     private static String getFirstField(Iterable<String> languages, String field, Node entity) throws XPathExpressionException {
    321         for (String language : languages) {
    322             final String label = (String) X_PATH.compile(language != null
    323                     ? ".//" + field + "[@language='" + language + "']/@value"
    324                     : ".//" + field + "/@value"
    325             ).evaluate(entity, XPathConstants.STRING);
    326             if (label != null && !label.isEmpty()) {
    327                 return label;
    328             }
    329         }
    330         return null;
     292    private static String getFirstField(Collection<String> languages, String field, Node entity) throws XPathExpressionException {
     293        return languages.stream()
     294                .map(language -> X_PATH.evaluateString(language != null
     295                        ? ".//" + field + "[@language='" + language + "']/@value"
     296                        : ".//" + field + "/@value", entity))
     297                .filter(label -> label != null && !label.isEmpty())
     298                .findFirst()
     299                .orElse(null);
    331300    }
    332301
     
    342311            try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
    343312                final Document xml = DOCUMENT_BUILDER.parse(in);
    344                 final NodeList nodes = (NodeList) X_PATH.compile("//ll").evaluate(xml, XPathConstants.NODESET);
    345                 for (int i = 0; i < nodes.getLength(); i++) {
    346                     final String lang = nodes.item(i).getAttributes().getNamedItem("lang").getTextContent();
    347                     final String name = nodes.item(i).getTextContent();
    348                     r.add(new WikipediaLangArticle(lang, name));
    349                 }
    350             }
    351             return r;
     313                return X_PATH.evaluateNodes("//ll", xml).stream()
     314                        .map(node -> {
     315                            final String lang = X_PATH.evaluateString("@lang", node);
     316                            final String name = node.getTextContent();
     317                            return new WikipediaLangArticle(lang, name);
     318                        }).collect(Collectors.toList());
     319            }
    352320        } catch (Exception ex) {
    353321            throw new RuntimeException(ex);
     
    364332            try (final InputStream in = HttpClient.create(new URL(url)).setReasonForRequest("Wikipedia").connect().getContent()) {
    365333                final Document xml = DOCUMENT_BUILDER.parse(in);
    366                 final Node node = (Node) X_PATH.compile("//coordinates/co").evaluate(xml, XPathConstants.NODE);
     334                final Node node = X_PATH.evaluateNode("//coordinates/co", xml);
    367335                if (node == null) {
    368336                    return null;
    369337                } else {
    370                     final double lat = Double.parseDouble(node.getAttributes().getNamedItem("lat").getTextContent());
    371                     final double lon = Double.parseDouble(node.getAttributes().getNamedItem("lon").getTextContent());
    372                     return new LatLon(lat, lon);
     338                    return new LatLon(X_PATH.evaluateDouble("@lat", node), X_PATH.evaluateDouble("@lon", node));
    373339                }
    374340            }
Note: See TracChangeset for help on using the changeset viewer.