All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xmlcalabash.util.AxisNodes Maven / Gradle / Ivy

The newest version!
/*
 * RelevantNodes.java
 *
 * Copyright 2008 Mark Logic Corporation.
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package com.xmlcalabash.util;

import com.xmlcalabash.core.XProcConstants;
import com.xmlcalabash.core.XProcException;
import com.xmlcalabash.core.XProcRuntime;
import net.sf.saxon.s9api.*;
import net.sf.saxon.trans.XPathException;

import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by IntelliJ IDEA.
 * User: ndw
 * Date: Apr 23, 2008
 * Time: 12:39:28 PM
 *
 * All this really does is make XdmSequenceIterator Iterable.
 *
 * To change this template use File | Settings | File Templates.
 */
public class AxisNodes implements Iterable {
    public static final int NO_PIS = 0x01;
    public static final int NO_COMMENTS = 0x02;
    public static final int NO_WHITESPACE = 0x04;
    public static final int NO_DOC = 0x08;
    public static final int USE_WHEN = 0x10;

    public static final int ALL = 0;
    public static final int SIGNIFICANT = NO_PIS | NO_COMMENTS | NO_WHITESPACE;
    public static final int PIPELINE = SIGNIFICANT | NO_DOC | USE_WHEN;
    private static final int VALID_BITS = PIPELINE;

    protected Logger logger = LoggerFactory.getLogger(AxisNodes.class);
    private static QName use_when = new QName("", "use-when");
    private static QName p_use_when = new QName(XProcConstants.NS_XPROC, "use-when");
    private AxisNodesIter iter = null;
    private XProcRuntime runtime = null;
    private int filter = ALL;

    public AxisNodes(XdmNode start, Axis axis) {
        iter = new AxisNodesIter(start, axis);
    }

    public AxisNodes(XdmNode start, Axis axis, int filter) {
        if ((filter | VALID_BITS) != VALID_BITS) {
            throw new XProcException("Invalid filter passed to AxisNodes");
        }
        if ((filter & USE_WHEN) == USE_WHEN) {
            throw new XProcException("Pointless use of USE_WHEN filter in AxisNodes");
        }
        this.filter = filter;
        iter = new AxisNodesIter(start, axis);
    }

    public AxisNodes(XProcRuntime runtime, XdmNode start, Axis axis, int filter) {
        if ((filter | VALID_BITS) != VALID_BITS) {
            throw new XProcException("Invalid filter passed to AxisNodes");
        }
        this.runtime = runtime;
        this.filter = filter;
        iter = new AxisNodesIter(start, axis);
    }

    public Iterator iterator() {
        return iter;
    }

    private class AxisNodesIter implements Iterator {
        private XdmSequenceIterator iter = null;
        private XdmNode next = null;
        private boolean finished = false;
        private boolean hasNext = false;

        public AxisNodesIter(XdmNode start, Axis axis) {
            iter = start.axisIterator(axis);
        }

        public boolean hasNext() {
            hasNext = true;

            // This code is funky because XdmSequenceIterator.hasNext() consumes an item
            if (next == null) {
                boolean hasNext = iter.hasNext();
                finished = finished || !hasNext;
                if (finished) {
                    return false;
                }

                // If we got here, there must be a next
                next = (XdmNode) iter.next();
                while (next != null && !ok(next)) {
                    if (iter.hasNext()) {
                        next = (XdmNode) iter.next();
                    } else {
                        next = null;
                    }
                }

                return ok(next);
            } else {
                return true;
            }
        }

        public XdmNode next() {
            if (!hasNext) {
                hasNext();
                hasNext = false;
            }
            XdmNode r = next;
            next = null;
            return r;
        }

        public void remove() {
            throw new UnsupportedOperationException("Not supported!");
        }

        private boolean ok(XdmNode node) {
            if (node == null) {
                return false;
            }

            if (((filter & NO_DOC) == NO_DOC)
                && (node.getNodeKind() == XdmNodeKind.ELEMENT)
                && (XProcConstants.p_documentation.equals(node.getNodeName())
                    || XProcConstants.p_pipeinfo.equals(node.getNodeName()))) {
                return false;
            }

            if (((filter & NO_COMMENTS) == NO_COMMENTS)
                    && node.getNodeKind() == XdmNodeKind.COMMENT) {
                return false;
            }

            if (((filter & NO_PIS) == NO_PIS)
                    && node.getNodeKind() == XdmNodeKind.PROCESSING_INSTRUCTION) {
                return false;
            }

            if (node.getNodeKind() == XdmNodeKind.TEXT) {
                if ((filter & NO_WHITESPACE) == NO_WHITESPACE) {
                    return !"".equals(node.toString().trim());
                } else {
                    return true;
                }
            }

            if (((filter & USE_WHEN) == USE_WHEN)
                    && node.getNodeKind() == XdmNodeKind.ELEMENT) {
                String expr = null;

                if (XProcConstants.NS_XPROC.equals(node.getNodeName().getNamespaceURI())) {
                    expr = node.getAttributeValue(use_when);
                }

                if (!XProcConstants.NS_XPROC.equals(node.getNodeName().getNamespaceURI())) {
                    expr = node.getAttributeValue(p_use_when);
                }

                if (expr != null) {
                    return useWhen(node, expr);
                } else {
                    return true;
                }
            }

            return true;
        }

        private boolean useWhen(XdmNode element, String xpath) {
            boolean use = false;

            // FIXME: I don't think this is a good idea, but XProcConfiguration calls relevant nodes w/o a runtime...
            if (runtime == null) {
                logger.info("The use-when attribute has no effect on pipelines in a configuration file.");
                return true;
            }

            try {
                XPathCompiler xcomp = runtime.getProcessor().newXPathCompiler();
                // FIXME: Static base URI here?

                XdmSequenceIterator nsIter = element.axisIterator(Axis.NAMESPACE);
                while (nsIter.hasNext()) {
                    XdmNode ns = (XdmNode) nsIter.next();
                    xcomp.declareNamespace(ns.getNodeName().getLocalName(),ns.getStringValue());
                }

                XPathExecutable xexec = null;

                try {
                    xexec = xcomp.compile(xpath);
                } catch (SaxonApiException sae) {
                    throw sae;
                }

                XPathSelector selector = xexec.load();

                try {
                    use = selector.effectiveBooleanValue();
                } catch (SaxonApiUncheckedException saue) {
                    Throwable sae = saue.getCause();
                    if (sae instanceof XPathException) {
                        XPathException xe = (XPathException) sae;
                        if ("http://www.w3.org/2005/xqt-errors".equals(xe.getErrorCodeNamespace()) && "XPDY0002".equals(xe.getErrorCodeLocalPart())) {
                            throw XProcException.dynamicError(26, element, "Expression refers to context when none is available: " + xpath);
                        } else {
                            throw saue;
                        }

                    } else {
                        throw saue;
                    }
                }
            } catch (SaxonApiException sae) {
                if (S9apiUtils.xpathSyntaxError(sae)) {
                    throw XProcException.dynamicError(23, element, sae.getCause().getMessage());
                } else {
                    throw new XProcException(sae);
                }
            }

            return use;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy