Пример #1
0
  /**
   * Add allowed URL protocols for an element's URL attribute. This restricts the possible values of
   * the attribute to URLs with the defined protocol.
   *
   * <p>E.g.: <code>addProtocols("a", "href", "ftp", "http", "https")</code>
   *
   * @param tag Tag the URL protocol is for
   * @param key Attribute key
   * @param protocols List of valid protocols
   * @return this, for chaining
   */
  public Whitelist addProtocols(String tag, String key, String... protocols) {
    Validate.notEmpty(tag);
    Validate.notEmpty(key);
    Validate.notNull(protocols);

    TagName tagName = TagName.valueOf(tag);
    AttributeKey attrKey = AttributeKey.valueOf(key);
    Map<AttributeKey, Set<Protocol>> attrMap;
    Set<Protocol> protSet;

    if (this.protocols.containsKey(tagName)) {
      attrMap = this.protocols.get(tagName);
    } else {
      attrMap = new HashMap<AttributeKey, Set<Protocol>>();
      this.protocols.put(tagName, attrMap);
    }
    if (attrMap.containsKey(attrKey)) {
      protSet = attrMap.get(attrKey);
    } else {
      protSet = new HashSet<Protocol>();
      attrMap.put(attrKey, protSet);
    }
    for (String protocol : protocols) {
      Validate.notEmpty(protocol);
      Protocol prot = Protocol.valueOf(protocol);
      protSet.add(prot);
    }
    return this;
  }
Пример #2
0
  /**
   * Get an absolute URL from a URL attribute that may be relative (i.e. an <code>&lt;a href></code>
   * or <code>&lt;img src></code>).
   *
   * <p>E.g.: <code>String absUrl = linkEl.absUrl("href");</code>
   *
   * <p>If the attribute value is already absolute (i.e. it starts with a protocol, like <code>
   * http://</code> or <code>https://</code> etc), and it successfully parses as a URL, the
   * attribute is returned directly. Otherwise, it is treated as a URL relative to the element's
   * {@link #baseUri}, and made absolute using that.
   *
   * <p>As an alternate, you can use the {@link #attr} method with the <code>abs:</code> prefix,
   * e.g.: <code>String absUrl = linkEl.attr("abs:href");</code>
   *
   * @param attributeKey The attribute key
   * @return An absolute URL if one could be made, or an empty string (not null) if the attribute
   *     was missing or could not be made successfully into a URL.
   * @see #attr
   * @see java.net.URL#URL(java.net.URL, String)
   */
  public String absUrl(String attributeKey) {
    Validate.notEmpty(attributeKey);

    String relUrl = attr(attributeKey);
    if (!hasAttr(attributeKey)) {
      return ""; // nothing to make absolute with
    } else {
      URL base;
      try {
        try {
          base = new URL(baseUri);
        } catch (MalformedURLException e) {
          // the base is unsuitable, but the attribute may be abs on its own, so try that
          URL abs = new URL(relUrl);
          return abs.toExternalForm();
        }
        // workaround: java resolves '//path/file + ?foo' to '//path/?foo', not '//path/file?foo' as
        // desired
        if (relUrl.startsWith("?")) relUrl = base.getPath() + relUrl;
        URL abs = new URL(base, relUrl);
        return abs.toExternalForm();
      } catch (MalformedURLException e) {
        return "";
      }
    }
  }
Пример #3
0
  /**
   * Find an element by ID, including or under this element.
   *
   * <p>Note that this finds the first matching ID, starting with this element. If you search down
   * from a different starting point, it is possible to find a different element by ID. For unique
   * element by ID within a Document, use {@link Document#getElementById(String)}
   *
   * @param id The ID to search for.
   * @return The first matching element by ID, starting with this element, or null if none found.
   */
  public Element getElementById(String id) {
    Validate.notEmpty(id);

    Elements elements = Collector.collect(new Evaluator.Id(id), this);
    if (elements.size() > 0) return elements.get(0);
    else return null;
  }
Пример #4
0
 public String get(String key) {
   Validate.notEmpty(key);
   if (this.attributes == null) {
     return UnsupportedUrlFragment.DISPLAY_NAME;
   }
   Attribute attr = (Attribute) this.attributes.get(key.toLowerCase());
   return attr != null ? attr.getValue() : UnsupportedUrlFragment.DISPLAY_NAME;
 }
Пример #5
0
  /**
   * Add a list of allowed elements to a whitelist. (If a tag is not allowed, it will be removed
   * from the HTML.)
   *
   * @param tags tag names to allow
   * @return this (for chaining)
   */
  public Whitelist addTags(String... tags) {
    Validate.notNull(tags);

    for (String tagName : tags) {
      Validate.notEmpty(tagName);
      tagNames.add(TagName.valueOf(tagName));
    }
    return this;
  }
Пример #6
0
  /**
   * Add an enforced attribute to a tag. An enforced attribute will always be added to the element.
   * If the element already has the attribute set, it will be overridden.
   *
   * <p>E.g.: <code>addEnforcedAttribute("a", "rel", "nofollow")</code> will make all <code>a</code>
   * tags output as <code>&lt;a href="..." rel="nofollow"></code>
   *
   * @param tag The tag the enforced attribute is for. The tag will be added to the allowed tag list
   *     if necessary.
   * @param key The attribute key
   * @param value The enforced attribute value
   * @return this (for chaining)
   */
  public Whitelist addEnforcedAttribute(String tag, String key, String value) {
    Validate.notEmpty(tag);
    Validate.notEmpty(key);
    Validate.notEmpty(value);

    TagName tagName = TagName.valueOf(tag);
    if (!tagNames.contains(tagName)) tagNames.add(tagName);
    AttributeKey attrKey = AttributeKey.valueOf(key);
    AttributeValue attrVal = AttributeValue.valueOf(value);

    if (enforcedAttributes.containsKey(tagName)) {
      enforcedAttributes.get(tagName).put(attrKey, attrVal);
    } else {
      Map<AttributeKey, AttributeValue> attrMap = new HashMap<AttributeKey, AttributeValue>();
      attrMap.put(attrKey, attrVal);
      enforcedAttributes.put(tagName, attrMap);
    }
    return this;
  }
Пример #7
0
  /**
   * Add a list of allowed attributes to a tag. (If an attribute is not allowed on an element, it
   * will be removed.)
   *
   * <p>E.g.: <code>addAttributes("a", "href", "class")</code> allows <code>href</code> and <code>
   * class</code> attributes on <code>a</code> tags.
   *
   * <p>To make an attribute valid for <b>all tags</b>, use the pseudo tag <code>:all</code>, e.g.
   * <code>addAttributes(":all", "class")</code>.
   *
   * @param tag The tag the attributes are for. The tag will be added to the allowed tag list if
   *     necessary.
   * @param keys List of valid attributes for the tag
   * @return this (for chaining)
   */
  public Whitelist addAttributes(String tag, String... keys) {
    Validate.notEmpty(tag);
    Validate.notNull(keys);
    Validate.isTrue(keys.length > 0, "No attributes supplied.");

    TagName tagName = TagName.valueOf(tag);
    if (!tagNames.contains(tagName)) tagNames.add(tagName);
    Set<AttributeKey> attributeSet = new HashSet<AttributeKey>();
    for (String key : keys) {
      Validate.notEmpty(key);
      attributeSet.add(AttributeKey.valueOf(key));
    }
    if (attributes.containsKey(tagName)) {
      Set<AttributeKey> currentSet = attributes.get(tagName);
      currentSet.addAll(attributeSet);
    } else {
      attributes.put(tagName, attributeSet);
    }
    return this;
  }
Пример #8
0
 public static Chat createChat(Skype client, String identity) throws SkypeException {
   Validate.notNull(client, "Client must not be null");
   Validate.isTrue(
       client instanceof SkypeImpl,
       String.format("Now is not the time to use that, %s", client.getUsername()));
   Validate.notEmpty(identity, "Identity must not be null/empty");
   if (identity.startsWith("19:")) {
     if (identity.endsWith("@thread.skype")) {
       return new ChatGroup((SkypeImpl) client, identity);
     } else {
       client.getLogger().info(String.format("Skipping P2P chat with identity %s", identity));
       return null;
     }
   } else if (identity.startsWith("8:")) {
     return new ChatIndividual((SkypeImpl) client, identity);
   } else {
     throw new IllegalArgumentException(
         String.format("Unknown group type with identity %s", identity));
   }
 }
Пример #9
0
  /**
   * Wrap the supplied HTML around this node.
   *
   * @param html HTML to wrap around this element, e.g. {@code <div class="head"></div>}. Can be
   *     arbitrarily deep.
   * @return this node, for chaining.
   */
  public Node wrap(String html) {
    Validate.notEmpty(html);

    Element context = parent() instanceof Element ? (Element) parent() : null;
    List<Node> wrapChildren = Parser.parseFragment(html, context, baseUri());
    Node wrapNode = wrapChildren.get(0);
    if (wrapNode == null || !(wrapNode instanceof Element)) // nothing to wrap with; noop
    return null;

    Element wrap = (Element) wrapNode;
    Element deepest = getDeepChild(wrap);
    parentNode.replaceChild(this, wrap);
    deepest.addChildren(this);

    // remainder (unbalanced wrap, like <div></div><p></p> -- The <p> is remainder
    if (wrapChildren.size() > 0) {
      for (int i = 0; i < wrapChildren.size(); i++) {
        Node remainder = wrapChildren.get(i);
        remainder.parentNode.removeChild(remainder);
        wrap.appendChild(remainder);
      }
    }
    return this;
  }
Пример #10
0
 public void remove(String key) {
   Validate.notEmpty(key);
   if (this.attributes != null) {
     this.attributes.remove(key.toLowerCase());
   }
 }
Пример #11
0
 /**
  * Change the tag of this element. For example, convert a {@code <span>} to a {@code <div>} with
  * {@code el.tagName("div");}.
  *
  * @param tagName new tag name for this element
  * @return this element, for chaining
  */
 public Element tagName(String tagName) {
   Validate.notEmpty(tagName, "Tag name must not be empty.");
   tag = Tag.valueOf(tagName);
   return this;
 }
Пример #12
0
  /**
   * Find elements that have an attribute name starting with the supplied prefix. Use {@code data-}
   * to find elements that have HTML5 datasets.
   *
   * @param keyPrefix name prefix of the attribute e.g. {@code data-}
   * @return elements that have attribute names that start with with the prefix, empty if none.
   */
  public Elements getElementsByAttributeStarting(String keyPrefix) {
    Validate.notEmpty(keyPrefix);
    keyPrefix = keyPrefix.trim().toLowerCase();

    return Collector.collect(new Evaluator.AttributeStarting(keyPrefix), this);
  }
Пример #13
0
  /**
   * Find elements that have a named attribute set. Case insensitive.
   *
   * @param key name of the attribute, e.g. {@code href}
   * @return elements that have this attribute, empty if none
   */
  public Elements getElementsByAttribute(String key) {
    Validate.notEmpty(key);
    key = key.trim().toLowerCase();

    return Collector.collect(new Evaluator.Attribute(key), this);
  }
Пример #14
0
  /**
   * Find elements that have this class, including or under this element. Case insensitive.
   *
   * <p>Elements can have multiple classes (e.g. {@code <div class="header round first">}. This
   * method checks each class, so you can find the above with {@code
   * el.getElementsByClass("header");}.
   *
   * @param className the name of the class to search for.
   * @return elements with the supplied class name, empty if none
   * @see #hasClass(String)
   * @see #classNames()
   */
  public Elements getElementsByClass(String className) {
    Validate.notEmpty(className);

    return Collector.collect(new Evaluator.Class(className), this);
  }
Пример #15
0
  /**
   * Finds elements, including and recursively under this element, with the specified tag name.
   *
   * @param tagName The tag name to search for (case insensitively).
   * @return a matching unmodifiable list of elements. Will be empty if this element and none of its
   *     children match.
   */
  public Elements getElementsByTag(String tagName) {
    Validate.notEmpty(tagName);
    tagName = tagName.toLowerCase().trim();

    return Collector.collect(new Evaluator.Tag(tagName), this);
  }