1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package com.jcabi.xml;
31
32 import java.io.File;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.StringReader;
36 import java.net.URI;
37 import java.net.URL;
38 import java.nio.charset.StandardCharsets;
39 import java.nio.file.Path;
40 import java.util.List;
41 import java.util.stream.Collectors;
42 import javax.xml.namespace.NamespaceContext;
43 import javax.xml.transform.stream.StreamSource;
44 import net.sf.saxon.s9api.DocumentBuilder;
45 import net.sf.saxon.s9api.Processor;
46 import net.sf.saxon.s9api.SaxonApiException;
47 import net.sf.saxon.s9api.XPathCompiler;
48 import net.sf.saxon.s9api.XPathSelector;
49 import net.sf.saxon.s9api.XdmItem;
50 import net.sf.saxon.s9api.XdmNode;
51 import org.w3c.dom.Node;
52
53
54
55
56
57
58
59
60 public final class SaxonDocument implements XML {
61
62
63
64
65 private static final Processor SAXON = new Processor(false);
66
67
68
69
70 private static final DocumentBuilder DOC_BUILDER = SaxonDocument.SAXON.newDocumentBuilder();
71
72
73
74
75 private static final XPathCompiler XPATH_COMPILER = SaxonDocument.SAXON.newXPathCompiler();
76
77
78
79
80 private static final String UNSUPPORTED =
81 "The %s method is not supported yet. You can use XMLDocument instead or if you need to use Saxon specific features, you can open an issue at https://github.com/jcabi/jcabi-xml";
82
83
84
85
86 private final XdmNode xdm;
87
88
89
90
91
92
93 public SaxonDocument(final String text) {
94 this(SaxonDocument.node(text));
95 }
96
97
98
99
100
101
102 public SaxonDocument(final byte[] data) {
103 this(SaxonDocument.node(new String(data, StandardCharsets.UTF_8)));
104 }
105
106
107
108
109
110
111 public SaxonDocument(final Path path) {
112 this(path.toFile());
113 }
114
115
116
117
118
119
120 public SaxonDocument(final File file) {
121 this(SaxonDocument.node(new StreamSource(file)));
122 }
123
124
125
126
127
128
129
130 public SaxonDocument(final URL url) throws IOException {
131 this(SaxonDocument.node(new TextResource(url).toString()));
132 }
133
134
135
136
137
138
139
140 public SaxonDocument(final URI uri) throws IOException {
141 this(SaxonDocument.node(new TextResource(uri).toString()));
142 }
143
144
145
146
147
148
149 public SaxonDocument(final InputStream stream) {
150 this(SaxonDocument.node(new StreamSource(stream)));
151 }
152
153
154
155
156
157
158 public SaxonDocument(final XdmNode xml) {
159 this.xdm = xml;
160 }
161
162 @Override
163 public List<String> xpath(final String query) {
164 try {
165 final XPathSelector selector = SaxonDocument.XPATH_COMPILER.compile(query).load();
166 selector.setContextItem(this.xdm);
167 return selector.evaluate()
168 .stream()
169 .map(XdmItem::getStringValue)
170 .collect(Collectors.toList());
171 } catch (final SaxonApiException exception) {
172 throw new IllegalArgumentException(
173 String.format("Can't evaluate the '%s' XPath query with Saxon API", query),
174 exception
175 );
176 }
177 }
178
179 @Override
180 public List<XML> nodes(final String query) {
181 throw new UnsupportedOperationException(
182 String.format(SaxonDocument.UNSUPPORTED, "nodes")
183 );
184 }
185
186 @Override
187 public XML registerNs(final String prefix, final Object uri) {
188 throw new UnsupportedOperationException(
189 String.format(SaxonDocument.UNSUPPORTED, "registerNs")
190 );
191 }
192
193 @Override
194 public XML merge(final NamespaceContext context) {
195 throw new UnsupportedOperationException(
196 String.format(SaxonDocument.UNSUPPORTED, "merge")
197 );
198 }
199
200 @Override
201 public Node node() {
202 throw new UnsupportedOperationException(
203 String.format(SaxonDocument.UNSUPPORTED, "node")
204 );
205 }
206
207
208
209
210
211
212 private static XdmNode node(final String text) {
213 return SaxonDocument.node(new StreamSource(new StringReader(text)));
214 }
215
216
217
218
219
220
221 private static XdmNode node(final StreamSource source) {
222 try {
223 return SaxonDocument.DOC_BUILDER.build(source);
224 } catch (final SaxonApiException exception) {
225 throw new IllegalArgumentException(
226 String.format("SaxonDocument can't parse XML from source '%s'", source),
227 exception
228 );
229 }
230 }
231 }