1 package eu.fbk.knowledgestore.data;
2
3 import java.util.Collection;
4 import java.util.Collections;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.NoSuchElementException;
8
9 import javax.annotation.Nullable;
10
11 import com.google.common.collect.AbstractIterator;
12 import com.google.common.collect.Iterators;
13 import com.google.common.collect.UnmodifiableIterator;
14
15 import org.jaxen.DefaultNavigator;
16 import org.jaxen.UnsupportedAxisException;
17 import org.jaxen.saxpath.SAXPathException;
18 import org.openrdf.model.Statement;
19 import org.openrdf.model.URI;
20 import org.openrdf.model.Value;
21
22 final class XPathNavigator extends DefaultNavigator {
23
24 public static final XPathNavigator INSTANCE = new XPathNavigator();
25
26 private static final long serialVersionUID = -1402394846594186887L;
27
28 private XPathNavigator() {
29 }
30
31 public Object wrap(final Object node) {
32 return new Element(null, null, node);
33 }
34
35 public Object unwrap(final Object object) {
36 return object instanceof Element ? ((Element) object).getContent() : object;
37 }
38
39 @Override
40 public Iterator<?> getChildAxisIterator(final Object contextNode)
41 throws UnsupportedAxisException {
42
43 if (contextNode instanceof Element) {
44 final Element element = (Element) contextNode;
45 if (element.getContent() instanceof Record) {
46 return new ChildIterator(element);
47 } else {
48 final Object value = element.getContent();
49 return Iterators.singletonIterator(value instanceof Number ||
50 value instanceof Boolean ? value : value.toString());
51 }
52 } else {
53 return Collections.emptyIterator();
54 }
55 }
56
57 @Override
58 public Iterator<?> getParentAxisIterator(final Object contextNode)
59 throws UnsupportedAxisException {
60 return contextNode instanceof Element ? new ParentIterator((Element) contextNode)
61 : Collections.emptyIterator();
62 }
63
64 @Override
65 public Object getParentNode(final Object child) throws UnsupportedAxisException {
66 return child instanceof Element ? ((Element) child).getParent() : null;
67 }
68
69 @Override
70 public Object getDocumentNode(final Object contextNode) {
71 if (!(contextNode instanceof Element)) {
72 return null;
73 }
74 Element element = (Element) contextNode;
75 while (element.getParent() != null) {
76 element = element.getParent();
77 assert element != null;
78 }
79 return element;
80 }
81
82 @Override
83 public String translateNamespacePrefixToUri(final String prefix, final Object element) {
84 throw new Error("This method is not expected to be called by Jaxen (!)");
85 }
86
87 @Override
88 public String getElementNamespaceUri(final Object element) {
89 if (element instanceof Element) {
90 final URI tag = ((Element) element).getTag();
91 return tag == null ? "" : tag.getNamespace();
92 }
93 return null;
94 }
95
96 @Override
97 public String getElementName(final Object element) {
98 if (element instanceof Element) {
99 final URI tag = ((Element) element).getTag();
100 return tag == null ? "" : tag.getLocalName();
101 }
102 return null;
103 }
104
105 @Override
106 public String getElementQName(final Object element) {
107 throw new Error("This method is not expected to be called by Jaxen (!)");
108 }
109
110 @Override
111 public String getAttributeNamespaceUri(final Object attr) {
112 throw new Error("This method is not expected to be called by Jaxen (!)");
113 }
114
115 @Override
116 public String getAttributeName(final Object attr) {
117 throw new Error("This method is not expected to be called by Jaxen (!)");
118 }
119
120 @Override
121 public String getAttributeQName(final Object attr) {
122 throw new Error("This method is not expected to be called by Jaxen (!)");
123 }
124
125 @Override
126 public boolean isDocument(final Object object) {
127 return object instanceof Element && ((Element) object).getParent() == null;
128 }
129
130 @Override
131 public boolean isElement(final Object object) {
132 return object instanceof Element && ((Element) object).getParent() != null;
133 }
134
135 @Override
136 public boolean isAttribute(final Object object) {
137 return false;
138 }
139
140 @Override
141 public boolean isNamespace(final Object object) {
142 return false;
143 }
144
145 @Override
146 public boolean isComment(final Object object) {
147 return false;
148 }
149
150 @Override
151 public boolean isText(final Object object) {
152 return !(object instanceof Element) && !(object instanceof Collection);
153 }
154
155 @Override
156 public boolean isProcessingInstruction(final Object object) {
157 return false;
158 }
159
160 @Override
161 public String getCommentStringValue(final Object comment) {
162 throw new Error("This method is not expected to be called by Jaxen (!)");
163 }
164
165 @Override
166 public String getElementStringValue(final Object element) {
167 if (element instanceof Element) {
168 final Object object = ((Element) element).getContent();
169 if (object instanceof Record) {
170 return "";
171 } else if (object instanceof Value) {
172 return ((Value) object).stringValue();
173 } else if (object instanceof Statement) {
174 return object.toString();
175 }
176 }
177 return null;
178 }
179
180 @Override
181 public String getAttributeStringValue(final Object attr) {
182 throw new Error("This method is not expected to be called by Jaxen (!)");
183 }
184
185 @Override
186 public String getNamespaceStringValue(final Object ns) {
187 throw new Error("This method is not expected to be called by Jaxen (!)");
188 }
189
190 @Override
191 public String getTextStringValue(final Object text) {
192 if (text instanceof Element || text instanceof Collection) {
193 return null;
194 }
195 if (text instanceof Value) {
196 return ((Value) text).stringValue();
197 }
198 return text.toString();
199 }
200
201 @Override
202 public String getNamespacePrefix(final Object ns) {
203 throw new Error("This method is not expected to be called by Jaxen (!)");
204 }
205
206 @Override
207 public org.jaxen.XPath parseXPath(final String xpath) throws SAXPathException {
208 throw new Error("This method is not expected to be called by Jaxen (!)");
209 }
210
211 private static final class ParentIterator extends UnmodifiableIterator<Object> {
212
213 private final Element node;
214
215 ParentIterator(final Element node) {
216 assert node != null;
217 this.node = node;
218 }
219
220 @Override
221 public boolean hasNext() {
222 return this.node.getParent() != null;
223 }
224
225 @Override
226 public Element next() {
227 final Element parent = this.node.getParent();
228 if (parent == null) {
229 throw new NoSuchElementException();
230 }
231 return parent;
232 }
233
234 }
235
236 private static final class ChildIterator extends AbstractIterator<Object> {
237
238 private final Element parent;
239
240 private final List<URI> properties;
241
242 private URI propertyURI;
243
244 private int propertyIndex;
245
246 private List<? extends Object> values;
247
248 private int valueIndex;
249
250 public ChildIterator(final Element parent) {
251
252 assert parent != null;
253 assert parent.getContent() instanceof Record;
254
255 this.parent = parent;
256 this.properties = ((Record) parent.getContent()).getProperties();
257 this.propertyURI = null;
258 this.propertyIndex = 0;
259 this.values = Collections.emptyList();
260 this.valueIndex = 0;
261 }
262
263 @Override
264 protected Object computeNext() {
265 while (true) {
266 while (this.valueIndex < this.values.size()) {
267 final Object value = this.values.get(this.valueIndex++);
268
269
270 return new Element(this.parent, this.propertyURI, value);
271
272 }
273 if (this.propertyIndex == this.properties.size()) {
274 return endOfData();
275 }
276 this.propertyURI = this.properties.get(this.propertyIndex++);
277 this.values = ((Record) this.parent.getContent()).get(this.propertyURI);
278 this.valueIndex = 0;
279 }
280 }
281
282 }
283
284 private static final class Element {
285
286 @Nullable
287 private final Element parent;
288
289 @Nullable
290 private final URI tag;
291
292 private final Object content;
293
294 public Element(@Nullable final Element parent, @Nullable final URI tag,
295 final Object content) {
296 this.parent = parent;
297 this.tag = tag;
298 this.content = content;
299 }
300
301 @Nullable
302 public Element getParent() {
303 return this.parent;
304 }
305
306 @Nullable
307 public URI getTag() {
308 return this.tag;
309 }
310
311 public Object getContent() {
312 return this.content;
313 }
314
315 }
316
317 }