public void startElement()

in xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaPathFinder.java [480:750]


    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {

        final QName elemQName = new QName(uri, localName);

        try {
            if (currentPath == null) {
                /*
                 * We just started a new document. Likewise we need to move into
                 * a position to process the root element.
                 */
                currentPath = rootPathNode;

            } else if (currentPath.getStateMachineNode().getNodeType()
                .equals(XmlSchemaStateMachineNode.Type.ANY)
                       && (anyStack != null) && !anyStack.isEmpty()) {
                /*
                 * If we are currently following a wildcard element node, we
                 * don't know anything about the element or its children. So it
                 * does not make sense to follow the children or grandchildren
                 * of this element.
                 */
                elementStack.add(elemQName);
                anyStack.add(elemQName);
                return;
            }

            // 1. Find possible paths.
            List<PathSegment<U, V>> possiblePaths = find(currentPath, elemQName);

            PathSegment<U, V> nextPath = null;

            if ((possiblePaths != null) && !possiblePaths.isEmpty()) {
                /*
                 * 2. If multiple paths were returned, add a DecisionPoint. Sort
                 * the paths where paths ending in elements are favored over
                 * element wild cards, and shorter paths are favored over longer
                 * paths.
                 */
                if (possiblePaths.size() > 1) {
                    final DecisionPoint<U, V> decisionPoint =
                        new DecisionPoint<U, V>(currentPath, possiblePaths, traversedElements.size(),
                                                elementStack, anyStack);

                    if (decisionPoints == null) {
                        decisionPoints = new ArrayList<DecisionPoint<U, V>>(4);
                    }
                    decisionPoints.add(decisionPoint);

                    nextPath = decisionPoint.tryNextPath();
                } else {
                    nextPath = possiblePaths.get(0);
                }

                if (nextPath == null) {
                    throw new IllegalStateException("When searching for " + elemQName
                                                    + ", received a set of path choices of size "
                                                    + possiblePaths.size() + ", but the next path is null.");
                }

                followPath(nextPath);

            } else {
                // OR: If no paths are returned:
                while ((decisionPoints != null) && !decisionPoints.isEmpty()) {
                    /*
                     * 2a. Backtrack to the most recent decision point. Remove
                     * the top path (the one we just tried), and select the next
                     * one.
                     */
                    final DecisionPoint<U, V> priorPoint = decisionPoints.get(decisionPoints.size() - 1);

                    nextPath = priorPoint.tryNextPath();

                    if (nextPath == null) {
                        /*
                         * We have tried all paths at this decision point.
                         * Remove it and try the next prior decision point.
                         */
                        decisionPoints.remove(decisionPoints.size() - 1);
                        continue;
                    }

                    pathMgr.unfollowPath(priorPoint.getDecisionPoint());

                    elementStack = priorPoint.getElementStack();
                    anyStack = priorPoint.getAnyStack();

                    /*
                     * Walk through the traversedElements list again from that
                     * index and see if we traverse through all of the elements
                     * in the list, including this one. If not, repeat step 2a,
                     * removing decision points from the stack as we refute
                     * them.
                     */
                    followPath(nextPath);

                    final QName traversedQName = traversedElements.get(priorPoint.traversedElementIndex).elemName;

                    elementStack.add(traversedQName);

                    if (currentPath.getStateMachineNode().getNodeType()
                        .equals(XmlSchemaStateMachineNode.Type.ANY)) {
                        if (anyStack == null) {
                            anyStack = new ArrayList<QName>();
                        }
                        anyStack.add(traversedQName);
                    }

                    int index = priorPoint.traversedElementIndex + 1;
                    for (; index < traversedElements.size(); ++index) {
                        nextPath = null;

                        final TraversedElement te = traversedElements.get(index);

                        if (te.traversal.equals(TraversedElement.Traversal.START)) {
                            possiblePaths = find(currentPath, te.elemName);

                            if ((possiblePaths == null) || possiblePaths.isEmpty()) {
                                break;

                            } else if (possiblePaths.size() > 1) {
                                final DecisionPoint<U, V> decisionPoint =
                                    new DecisionPoint<U, V>(currentPath, possiblePaths, index, elementStack, anyStack);

                                decisionPoints.add(decisionPoint);
                                nextPath = decisionPoint.tryNextPath();

                            } else {
                                nextPath = possiblePaths.get(0);
                            }

                            if (nextPath == null) {
                                throw new IllegalStateException("Somehow after finding a new path to follow,"
                                                                + " that path is null.");
                            }

                            // If we find (a) path(s) that match(es), success!
                            // Follow it.
                            followPath(nextPath);

                            if (currentPath.getStateMachineNode().getNodeType()
                                .equals(XmlSchemaStateMachineNode.Type.ANY)) {
                                if (anyStack == null) {
                                    anyStack = new ArrayList<QName>();
                                }
                                anyStack.add(te.elemName);
                            }

                            elementStack.add(te.elemName);

                        } else if (te.traversal.equals(TraversedElement.Traversal.END)) {
                            final boolean isAny = (currentPath.getStateMachineNode().getNodeType()
                                .equals(XmlSchemaStateMachineNode.Type.ANY)
                                                   && (anyStack != null) && !anyStack.isEmpty());

                            if (!isAny) {
                                walkUpToElement(te.elemName);
                            }

                            walkUpTree(te.elemName);

                            final QName endingElemName = elementStack.remove(elementStack.size() - 1);

                            if (!te.elemName.equals(endingElemName)) {
                                throw new IllegalStateException("Attempted to end element " + te.elemName
                                                                + " but found " + endingElemName
                                                                + " on the stack instead!");
                            }

                            if (isAny) {
                                anyStack.remove(anyStack.size() - 1);
                            }

                        } else if (te.traversal.equals(TraversedElement.Traversal.CONTENT)) {

                            final XmlSchemaPathNode<U, V> contentPath =
                                pathMgr
                                  .addParentSiblingOrContentNodeToPath(currentPath,
                                                                       XmlSchemaPathNode.Direction.CONTENT);

                            currentPath.setNextNode(-1, contentPath);
                            currentPath = contentPath;

                        } else {
                            throw new IllegalStateException("Unrecognized element traversal direction for "
                                                            + te.elemName + " of " + te.traversal + '.');
                        }
                    }

                    if (index < traversedElements.size()) {
                        /*
                         * This attempt is also incorrect. However, we may have
                         * introduced new decision points along the way, and we
                         * want to follow them first. So let's go back around
                         * for another try.
                         */
                        continue;
                    }

                    /*
                     * We made it to the end of the element list! Now try the
                     * current one again.
                     */
                    possiblePaths = find(currentPath, elemQName);

                    if (possiblePaths == null) {
                        // Still incorrect!
                        continue;

                    } else if (possiblePaths.size() > 1) {
                        final DecisionPoint<U, V> decisionPoint =
                            new DecisionPoint<U, V>(currentPath, possiblePaths, traversedElements.size(),
                                                    elementStack, anyStack);

                        decisionPoints.add(decisionPoint);
                        nextPath = decisionPoint.tryNextPath();
                    } else {
                        nextPath = possiblePaths.get(0);
                    }

                    if (nextPath != null) {
                        followPath(nextPath);
                        break;
                    }
                }
            }

            if (nextPath == null) {
                /*
                 * If we go through all prior decision points and are unable to
                 * find one or more paths through the XML Schema that match the
                 * document, throw an error. There is nothing more we can do
                 * here.
                 */
                throw new IllegalStateException(
                                                "Walked through XML Schema and could not find a traversal that "
                                                    + "represented this XML Document.");
            }

            /*
             * Current path now points to the element we just started. Validate
             * its attributes.
             */
            validateAttributes(atts);

            traversedElements.add(new TraversedElement(elemQName, TraversedElement.Traversal.START));
            elementStack.add(elemQName);

            /*
             * If this is element is of type xsd:any, we do not track it or its
             * children. So, we keep a stack of the element and its children,
             * allowing us to know when we leave and can start tracking elements
             * again.
             */
            if (currentPath.getStateMachineNode().getNodeType().equals(XmlSchemaStateMachineNode.Type.ANY)) {
                if (anyStack == null) {
                    anyStack = new ArrayList<QName>();
                }
                anyStack.add(elemQName);
            }

        } catch (Exception e) {
            /*
             * A SAX Exception cannot be thrown because it is caught, and its
             * internal exception is thrown instead. Likewise, any useful info
             * about the error reported in the wrapper SAXException is lost.
             */
            throw new RuntimeException("Error occurred while starting element " + elemQName
                                       + "; traversed path is " + getElementsTraversedAsString(), e);
        }
    }