View Javadoc
1   /*
2    * Copyright (c) 2012-2022, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.xml;
31  
32  import java.util.List;
33  import javax.xml.namespace.NamespaceContext;
34  import org.w3c.dom.Node;
35  
36  /**
37   * XML document.
38   *
39   * <p>Set of convenient XML manipulations:
40   *
41   * <pre> XML xml = new XMLDocument(content);
42   * for (XML employee : xml.nodes("//Employee")) {
43   *   String name = employee.xpath("name/text()").get(0);
44   *   // ...
45   * }</pre>
46   *
47   * <p>You can always get DOM node out of this abstraction using {@link #node()}
48   * method.
49   *
50   * <p>{@code toString()} must produce a full XML.
51   *
52   * <p>Implementation of this interface must be immutable and thread-safe.
53   *
54   * @see XMLDocument
55   * @since 0.1
56   * @checkstyle AbbreviationAsWordInNameCheck (5 lines)
57   */
58  public interface XML {
59  
60      /**
61       * Find and return text elements or attributes matched by XPath address.
62       *
63       * <p>The XPath query should point to text elements or attributes in the
64       * XML document. If any nodes of different types (elements, comments, etc.)
65       * are found in result node list -
66       * a {@link RuntimeException} will be thrown.
67       *
68       * <p>Alternatively, the XPath query can be a function or expression that
69       * returns a single value instead of pointing to a set of nodes. In this
70       * case, the result will be a List containing a single String, the content
71       * of which is the result of the evaluation. If the expression result is not
72       * a String, it will be converted to a String representation and returned as
73       * such. For example, a document containing three &lt;a&gt; elements,
74       * the input query "count(//a)", will return a singleton List with a single
75       * string value "3".
76       *
77       * <p>This is a convenient method, which is used (according to our
78       * experience) in 95% of all cases. Usually you don't need to get anything
79       * else but a text value of some node or an attribute. And in most cases
80       * you are interested to get just the first value
81       * (use {@code xpath(..).get(0)}). But when/if you need to get more than
82       * just a plain text - use {@link #nodes(String)}.
83       *
84       * <p>The {@link List} returned will throw {@link IndexOutOfBoundsException}
85       * if you try to access a node which wasn't found by this XPath query.
86       *
87       * <p>An {@link IllegalArgumentException} is thrown if the parameter
88       * passed is not a valid XPath expression.
89       *
90       * @param query The XPath query
91       * @return The list of string values (texts) or single function result
92       */
93      List<String> xpath(String query);
94  
95      /**
96       * Retrieve DOM nodes from the XML response.
97       *
98       * <p>The {@link List} returned will throw {@link IndexOutOfBoundsException}
99       * if you try to access a node which wasn't found by this XPath query.
100      *
101      * <p>An {@link IllegalArgumentException} is thrown if the parameter
102      * passed is not a valid XPath expression.
103      *
104      * @param query The XPath query
105      * @return Collection of DOM nodes
106      */
107     List<XML> nodes(String query);
108 
109     /**
110      * Register additional namespace prefix for XPath.
111      *
112      * <p>For example:
113      *
114      * <pre>
115      * String name = new XMLDocument("...")
116      *   .registerNs("ns1", "http://example.com")
117      *   .registerNs("foo", "http://example.com/foo")
118      *   .xpath("/ns1:root/foo:name/text()")
119      *   .get(0);
120      * </pre>
121      *
122      * <p>A number of standard namespaces are registered by default in
123      * instances of XML. Their
124      * full list is in {@link XMLDocument#XMLDocument(String)}.
125      *
126      * <p>If a namespace prefix is already registered an
127      * {@link IllegalArgumentException} will be thrown.
128      *
129      * @param prefix The XPath prefix to register
130      * @param uri Namespace URI
131      * @return A new XML document, with this additional namespace registered
132      */
133     XML registerNs(String prefix, Object uri);
134 
135     /**
136      * Append this namespace context to the existing one.
137      *
138      * <p>The existing context (inside this object) and the new one provided
139      * will be merged together. The existing context will be have higher
140      * priority.
141      *
142      * @param context The context to append
143      * @return A new XML document, with a merged context on board
144      */
145     XML merge(NamespaceContext context);
146 
147     /**
148      * Retrieve DOM node, represented by this wrapper.
149      * @return DOM node
150      */
151     Node node();
152 
153 }