View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *  http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.any23.extractor.microdata;
    19
    20  import org.apache.any23.rdf.RDFUtils;
    21  import org.apache.commons.lang3.StringUtils;
    22  import org.eclipse.rdf4j.common.net.ParsedIRI;
    23  import org.eclipse.rdf4j.model.IRI;
    24
    25  import java.net.MalformedURLException;
    26  import java.net.URL;
    27  import java.util.ArrayList;
    28  import java.util.Arrays;
    29  import java.util.Collection;
    30  import java.util.Collections;
    31  import java.util.HashMap;
    32  import java.util.List;
    33  import java.util.Locale;
    34  import java.util.Map;
    35  import java.util.regex.Pattern;
    36
    37  /**
    38   * This class describes a <b>Microdata <i>itemscope</i></b>.
    39   *
    40   * @author Michele Mostarda (mostarda@fbk.eu)
    41   * @author Hans Brende (hansbrende@apache.org)
    42   */
    43  public class ItemScope extends Item {
    44
    45      /**
    46       * Map of properties and multi values.
    47       */
    48      private final Map<String, List<ItemProp>> properties;
    49
    50      /**
    51       * <i>itemscope</i> DOM identifier in container document.
    52       */
    53      private final String id;
    54
    55      /**
    56       * <i>itemscope</i> references.
    57       */
    58      private final String[] refs;
    59
    60      /**
    61       * <i>itemscope</i> type.
    62       */
    63      private final List<IRI> type;
    64
    65      /**
    66       * <i>itemscope</i> external identifier.
    67       */
    68      private final String itemId;
    69
    70      /**
    71       * Constructor.
    72       *
    73       * @param xpath
    74       *            location of this <i>itemscope</i> within the container document.
    75       * @param itemProps
    76       *            list of properties bound to this <i>itemscope</i>.
    77       * @param id
    78       *            DOM identifier for this <i>itemscope</i>. Can be <code>null</code>.
    79       * @param refs
    80       *            list of item prop references connected to this <i>itemscope</i>. Can be <code>null</code>.
    81       * @param type
    82       *            <i>itemscope</i> type. Can be <code>null</code>.
    83       * @param itemId
    84       *            <i>itemscope</i> id. Can be <code>null</code>.
    85       */
    86      public ItemScope(String xpath, ItemProp[] itemProps, String id, String[] refs, String type, String itemId) {
    87          this(xpath, itemProps, id, refs, stringToSingletonIRI(type), itemId);
    88      }
    89
    90      private static final Pattern looksLikeStartsWithHost = Pattern.compile("[^:/.]+(\\.[^:/.]+)+(:\\d+)?([/#?].*)?");
    91
    92      static List<IRI> stringToSingletonIRI(String type) {
    93          if (StringUtils.isNotBlank(type)) {
    94              ParsedIRI iri = ParsedIRI.create(type.trim());
    95              if (StringUtils.isBlank(iri.getScheme())) {
    96                  String host = iri.getHost();
    97                  if (StringUtils.isNotBlank(host)) {
    98                      iri = new ParsedIRI("http", iri.getUserInfo(), host, iri.getPort(), iri.getPath(), iri.getQuery(),
    99                              iri.getFragment());
    100                 } else {
    101                     String path = iri.getPath();
    102                     if (path != null && looksLikeStartsWithHost.matcher(path).matches()) {
    103                         iri = ParsedIRI.create("http://" + iri.toString());
    104                     }
    105                 }
    106             }
    107             return Collections.singletonList(RDFUtils.iri(iri.toString()));
    108         } else {
    109             return Collections.emptyList();
    110         }
    111     }
    112
    113     ItemScope(String xpath, ItemProp[] itemProps, String id, String[] refs, List<IRI> types, String itemId) {
    114         super(xpath);
    115
    116         if (itemProps == null) {
    117             throw new NullPointerException("itemProps list cannot be null.");
    118         }
    119
    120         this.type = types;
    121         this.id = id;
    122         this.refs = refs;
    123         this.itemId = itemId;
    124
    125         final Map<String, List<ItemProp>> tmpProperties = new HashMap<>();
    126         for (ItemProp itemProp : itemProps) {
    127             final String propName = itemProp.getName();
    128             List<ItemProp> propList = tmpProperties.get(propName);
    129             if (propList == null) {
    130                 propList = new ArrayList<>();
    131                 tmpProperties.put(propName, propList);
    132             }
    133             propList.add(itemProp);
    134         }
    135         final Map<String, List<ItemProp>> properties = new HashMap<>();
    136         for (Map.Entry<String, List<ItemProp>> propertiesEntry : tmpProperties.entrySet()) {
    137             properties.put(propertiesEntry.getKey(),
    138                     // Collections.unmodifiableList( propertiesEntry.getValue() )
    139                     propertiesEntry.getValue());
    140         }
    141         // this.properties = Collections.unmodifiableMap(properties);
    142         this.properties = properties;
    143     }
    144
    145     /**
    146      * @return map of declared properties, every property can have more than a value.
    147      */
    148     public Map<String, List<ItemProp>> getProperties() {
    149         return properties;
    150     }
    151
    152     /**
    153      * @return the <i>itemscope</i>
    154      */
    155     public String getId() {
    156         return id;
    157     }
    158
    159     /**
    160      * @return <i>itemscope</i> list of references to <i>itemprop</i>s.
    161      */
    162     public String[] getRefs() {
    163         return refs;
    164     }
    165
    166     /**
    167      * @return <i>itemscope</i> type.
    168      */
    169     public URL getType() {
    170         // No longer using URL.
    171         // But for backwards compatibility:
    172         try {
    173             return type.isEmpty() ? null : new URL(type.get(0).stringValue());
    174         } catch (MalformedURLException e) {
    175             try {
    176                 return new URL(ParsedIRI.create(type.get(0).stringValue()).toASCIIString());
    177             } catch (Exception e1) {
    178                 return null;
    179             }
    180         }
    181     }
    182
    183     List<IRI> getTypes() {
    184         return type;
    185     }
    186
    187     /**
    188      * @return <i>itemscope</i> public identifier.
    189      */
    190     public String getItemId() {
    191         return itemId;
    192     }
    193
    194     @Override
    195     public String toJSON() {
    196         StringBuilder sb = new StringBuilder();
    197         int i;
    198         int j;
    199         final Collection<List<ItemProp>> itemPropsList = properties.values();
    200         j = 0;
    201         for (List<ItemProp> itemProps : itemPropsList) {
    202             i = 0;
    203             for (ItemProp itemProp : itemProps) {
    204                 sb.append(itemProp);
    205                 if (i < itemProps.size() - 1) {
    206                     sb.append(", ");
    207                 }
    208                 i++;
    209             }
    210             if (j < itemPropsList.size() - 1) {
    211                 sb.append(", ");
    212             }
    213             j++;
    214         }
    215         return String.format(Locale.ROOT, "{ "
    216                 + "\"xpath\" : \"%s\", \"id\" : %s, \"refs\" : %s, \"type\" : %s, \"itemid\" : %s, \"properties\" : [ %s ]"
    217                 + " }", getXpath(), id == null ? null : "\"" + id + "\"", refs == null ? null : toJSON(refs),
    218                 type.isEmpty() ? null : "\"" + type.get(0) + "\"", itemId == null ? null : "\"" + itemId + "\"",
    219                 sb.toString());
    220     }
    221
    222     @Override
    223     public String toString() {
    224         return toJSON();
    225     }
    226
    227     @Override
    228     public int hashCode() {
    229         int i = properties == null ? 0 : properties.hashCode();
    230         i += id == null ? 0 : id.hashCode();
    231         i += refs == null ? 0 : Arrays.hashCode(refs);
    232         i += type == null ? 0 : type.hashCode();
    233         i += itemId == null ? 0 : itemId.hashCode();
    234         return i;
    235     }
    236
    237     @Override
    238     public boolean equals(Object obj) {
    239         if (obj == null) {
    240             return false;
    241         }
    242         if (obj == this) {
    243             return true;
    244         }
    245         if (obj instanceof ItemScope) {
    246             final ItemScope/../../../../org/apache/any23/extractor/microdata/ItemScope.html#ItemScope">ItemScope other = (ItemScope) obj;
    247             return super.getXpath().equals(other.getXpath())
    248                     && (properties == null ? other.properties == null : properties.equals(other.properties))
    249                     && (id == null ? other.id == null : id.equals(other.id))
    250                     && (refs == null ? other.refs == null : Arrays.equals(refs, other.refs))
    251                     && (type == null ? other.type == null : type.equals(other.type))
    252                     && (itemId == null ? other.itemId == null : itemId.equals(other.itemId));
    253         }
    254         return false;
    255     }
    256
    257     protected void acquireProperty(ItemProp itemProp) {
    258         List<ItemProp> itemProps = properties.computeIfAbsent(itemProp.getName(), k -> new ArrayList<>());
    259         if (!itemProps.contains(itemProp))
    260             itemProps.add(itemProp);
    261     }
    262
    263     protected void disownProperty(ItemProp itemProp) {
    264         List<ItemProp> propList = properties.get(itemProp.getName());
    265         if (propList != null)
    266             propList.remove(itemProp);
    267     }
    268
    269     private String toJSON(String[] in) {
    270         StringBuilder sb = new StringBuilder();
    271         sb.append('[');
    272         for (int i = 0; i < in.length; i++) {
    273             sb.append("\"");
    274             sb.append(in[i]);
    275             sb.append("\"");
    276             if (i < in.length - 1) {
    277                 sb.append(", ");
    278             }
    279         }
    280         sb.append(']');
    281         return sb.toString();
    282     }
    283
    284 }