package eu.fbk.knowledgestore.data; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import javax.annotation.Nullable; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Iterators; import com.google.common.collect.UnmodifiableIterator; import org.jaxen.DefaultNavigator; import org.jaxen.UnsupportedAxisException; import org.jaxen.saxpath.SAXPathException; import org.openrdf.model.Statement; import org.openrdf.model.URI; import org.openrdf.model.Value; final class XPathNavigator extends DefaultNavigator { public static final XPathNavigator INSTANCE = new XPathNavigator(); private static final long serialVersionUID = -1402394846594186887L; private XPathNavigator() { } public Object wrap(final Object node) { return new Element(null, null, node); } public Object unwrap(final Object object) { return object instanceof Element ? ((Element) object).getContent() : object; } @Override public Iterator<?> getChildAxisIterator(final Object contextNode) throws UnsupportedAxisException { if (contextNode instanceof Element) { final Element element = (Element) contextNode; if (element.getContent() instanceof Record) { return new ChildIterator(element); } else { final Object value = element.getContent(); return Iterators.singletonIterator(value instanceof Number || // value instanceof Boolean ? value : value.toString()); } } else { return Collections.emptyIterator(); } } @Override public Iterator<?> getParentAxisIterator(final Object contextNode) throws UnsupportedAxisException { return contextNode instanceof Element ? new ParentIterator((Element) contextNode) : Collections.emptyIterator(); } @Override public Object getParentNode(final Object child) throws UnsupportedAxisException { return child instanceof Element ? ((Element) child).getParent() : null; } @Override public Object getDocumentNode(final Object contextNode) { if (!(contextNode instanceof Element)) { return null; } Element element = (Element) contextNode; while (element.getParent() != null) { element = element.getParent(); assert element != null; } return element; } @Override public String translateNamespacePrefixToUri(final String prefix, final Object element) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public String getElementNamespaceUri(final Object element) { if (element instanceof Element) { final URI tag = ((Element) element).getTag(); return tag == null ? "" : tag.getNamespace(); } return null; } @Override public String getElementName(final Object element) { if (element instanceof Element) { final URI tag = ((Element) element).getTag(); return tag == null ? "" : tag.getLocalName(); } return null; } @Override public String getElementQName(final Object element) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public String getAttributeNamespaceUri(final Object attr) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public String getAttributeName(final Object attr) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public String getAttributeQName(final Object attr) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public boolean isDocument(final Object object) { return object instanceof Element && ((Element) object).getParent() == null; } @Override public boolean isElement(final Object object) { return object instanceof Element && ((Element) object).getParent() != null; } @Override public boolean isAttribute(final Object object) { return false; } @Override public boolean isNamespace(final Object object) { return false; } @Override public boolean isComment(final Object object) { return false; } @Override public boolean isText(final Object object) { return !(object instanceof Element) && !(object instanceof Collection); } @Override public boolean isProcessingInstruction(final Object object) { return false; } @Override public String getCommentStringValue(final Object comment) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public String getElementStringValue(final Object element) { if (element instanceof Element) { final Object object = ((Element) element).getContent(); if (object instanceof Record) { return ""; } else if (object instanceof Value) { return ((Value) object).stringValue(); } else if (object instanceof Statement) { return object.toString(); } } return null; } @Override public String getAttributeStringValue(final Object attr) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public String getNamespaceStringValue(final Object ns) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public String getTextStringValue(final Object text) { if (text instanceof Element || text instanceof Collection) { return null; } if (text instanceof Value) { return ((Value) text).stringValue(); } return text.toString(); } @Override public String getNamespacePrefix(final Object ns) { throw new Error("This method is not expected to be called by Jaxen (!)"); } @Override public org.jaxen.XPath parseXPath(final String xpath) throws SAXPathException { throw new Error("This method is not expected to be called by Jaxen (!)"); } private static final class ParentIterator extends UnmodifiableIterator<Object> { private final Element node; ParentIterator(final Element node) { assert node != null; this.node = node; } @Override public boolean hasNext() { return this.node.getParent() != null; } @Override public Element next() { final Element parent = this.node.getParent(); if (parent == null) { throw new NoSuchElementException(); } return parent; } } private static final class ChildIterator extends AbstractIterator<Object> { private final Element parent; private final List<URI> properties; private URI propertyURI; private int propertyIndex; private List<? extends Object> values; private int valueIndex; public ChildIterator(final Element parent) { assert parent != null; assert parent.getContent() instanceof Record; this.parent = parent; this.properties = ((Record) parent.getContent()).getProperties(); this.propertyURI = null; this.propertyIndex = 0; this.values = Collections.emptyList(); this.valueIndex = 0; } @Override protected Object computeNext() { while (true) { while (this.valueIndex < this.values.size()) { final Object value = this.values.get(this.valueIndex++); // if (!BooleanLiteralImpl.FALSE.equals(value)) { // This is necessary for proper comparison of boolean values return new Element(this.parent, this.propertyURI, value); // } } if (this.propertyIndex == this.properties.size()) { return endOfData(); } this.propertyURI = this.properties.get(this.propertyIndex++); this.values = ((Record) this.parent.getContent()).get(this.propertyURI); this.valueIndex = 0; } } } private static final class Element { @Nullable private final Element parent; @Nullable private final URI tag; private final Object content; public Element(@Nullable final Element parent, @Nullable final URI tag, // final Object content) { this.parent = parent; this.tag = tag; this.content = content; } @Nullable public Element getParent() { return this.parent; } @Nullable public URI getTag() { return this.tag; } public Object getContent() { return this.content; } } }