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

org.apache.ws.commons.schema.docpath.XmlSchemaDocumentNode Maven / Gradle / Ivy

Go to download

Code to walk an XML Schema and confirm an XML Document conforms to it.

There is a newer version: 2.3.1
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.ws.commons.schema.docpath;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * The XmlSchemaDocumentNode represents a node in the XML Schema as
 * it is used by an XML document. As {@link XmlSchemaPathFinder} walks through
 * an XML document, it builds {@link XmlSchemaPathNode}s representing the path
 * walked, and XmlSchemaDocumentNodes representing where the XML
 * document's elements fall in the XML Schema's sequences, choices, and all
 * groups.
 * 

* While {@link XmlSchemaStateMachineNode}s may loop back on themselves, the * XmlSchemaDocumentNodes will not. Likewise, the document nodes * form a tree that represent the XML Schema as it is applied to the document. *

*

* If a single node has multiple occurrences, the children of each occurrence * can be retrieved by calling {@link #getChildren(int)}. {@link #getChildren()} * returns the child nodes for the final occurrence. *

*/ public final class XmlSchemaDocumentNode { private XmlSchemaStateMachineNode stateMachineNode; private XmlSchemaDocumentNode parent; private List>> children; private List> visitors; private boolean receivedContent; private U userDefinedContent; XmlSchemaDocumentNode(XmlSchemaDocumentNode parent, XmlSchemaStateMachineNode stateMachineNode) { userDefinedContent = null; set(parent, stateMachineNode); } /** * Returns the {@link XmlSchemaStateMachineNode} representing the place in * the XML Schema that this XmlSchemaDocumentNode represents. */ public XmlSchemaStateMachineNode getStateMachineNode() { return stateMachineNode; } /** * The XmlSchemaDocumentNode representing this one's immediate * parent. */ public XmlSchemaDocumentNode getParent() { return parent; } /** * Retrieves the children in the last occurrence of this node, mapped to * their relative position. */ public SortedMap> getChildren() { if (children == null) { return null; } else { return getChildren(children.size()); } } /** * Retrieves the children in the provided occurrence of this node, mapped to * their relative position. * * @param iteration The 1-based occurrence to retrieve children for. */ public SortedMap> getChildren(int iteration) { if ((children == null) || (children.size() < iteration) || (iteration < 1)) { return null; } else { return children.get(iteration - 1); } } /** * Indicates whether an element has text in it. */ boolean getReceivedContent() { return receivedContent; } /** * Sets whether the element has text in it. * * @param receivedContent */ void setReceivedContent(boolean receivedContent) { this.receivedContent = receivedContent; } /** * A visitor is a CHILD or SIBLING {@link XmlSchemaPathNode} entering this * XmlSchemaDocumentNode. This is used to keep track of how * many occurrences are active via the current path winding through the * schema. */ void addVisitor(XmlSchemaPathNode path) { if (path.getDocumentNode() != this) { throw new IllegalArgumentException("Path node must have this XmlSchemaDocumentNode " + "as its document node."); } switch (path.getDirection()) { case CHILD: case SIBLING: break; default: throw new IllegalArgumentException("Only CHILD and SIBLING paths may be visitors of an " + "XmlSchemaDocumentNode, not a " + path.getDirection() + " path."); } if (visitors == null) { visitors = new ArrayList>(4); } if (children != null) { if (children.size() == visitors.size()) { children.add(new TreeMap>()); } else { throw new IllegalStateException( "Attempted to add a new visitor when the number of occurrences (" + children.size() + ") did not match the number of existing visitors (" + visitors.size() + ")."); } } visitors.add(path); } boolean removeVisitor(XmlSchemaPathNode path) { if ((visitors == null) || visitors.isEmpty()) { return false; } if ((children != null) && (visitors.size() != children.size())) { throw new IllegalStateException("The number of visitors (" + visitors.size() + ") does not match the number of occurrences (" + children.size() + ")."); } int visitorIndex = 0; for (; visitorIndex < visitors.size(); ++visitorIndex) { if (visitors.get(visitorIndex) == path) { break; } } if (visitors.size() == visitorIndex) { return false; } visitors.remove(visitorIndex); if (children != null) { children.remove(visitorIndex); } return true; } /** * The total number of occurrences of this * XmlSchemaDocumentNode in the underlying document. */ public int getIteration() { if ((children != null) && (children.size() != visitors.size())) { throw new IllegalStateException("The number of occurrences (" + children.size() + ") is not equal to the number of visitors (" + visitors.size() + ")."); } return visitors.size(); } /** * Shortcut for calling getStateMachineNode().getMinOccurs(). * * @see XmlSchemaStateMachineNode#getMinOccurs() */ public long getMinOccurs() { return stateMachineNode.getMinOccurs(); } /** * Shortcut for calling getStateMachineNode().getMaxOccurs(). * * @see XmlSchemaStateMachineNode#getMaxOccurs() */ public long getMaxOccurs() { return stateMachineNode.getMaxOccurs(); } int getSequencePosition() { if ((children == null) || (!stateMachineNode.getNodeType().equals(XmlSchemaStateMachineNode.Type.SEQUENCE))) { return -1; } else if (children.isEmpty()) { return 0; } else if (children.get(children.size() - 1).isEmpty()) { return 0; } else { return children.get(children.size() - 1).lastKey(); } } void set(XmlSchemaDocumentNode parent, XmlSchemaStateMachineNode stateMachineNode) { this.parent = parent; this.stateMachineNode = stateMachineNode; this.receivedContent = false; this.visitors = null; if ((this.stateMachineNode.getPossibleNextStates() == null) || this.stateMachineNode.getPossibleNextStates().isEmpty()) { this.children = null; } else { this.children = new ArrayList>>(1); } } /** * Retrieves any user-defined content attached to this * XmlSchemaDocumentNode, or null if none. */ public U getUserDefinedContent() { return userDefinedContent; } /** * Attaches user-defined content to this XmlSchemaDocumentNode. */ public void setUserDefinedContent(U userDefinedContent) { this.userDefinedContent = userDefinedContent; } }