001: package com.sun.xml.xsom;
002:
003: import com.sun.xml.xsom.impl.scd.Iterators;
004: import com.sun.xml.xsom.impl.scd.ParseException;
005: import com.sun.xml.xsom.impl.scd.SCDImpl;
006: import com.sun.xml.xsom.impl.scd.SCDParser;
007: import com.sun.xml.xsom.impl.scd.Step;
008: import com.sun.xml.xsom.impl.scd.TokenMgrError;
009: import com.sun.xml.xsom.util.DeferedCollection;
010:
011: import javax.xml.namespace.NamespaceContext;
012: import java.util.Collection;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: /**
017: * Schema Component Designator (SCD).
018: *
019: * <p>
020: * SCD for schema is what XPath is for XML. SCD allows you to select a schema component(s)
021: * from a schema component(s).
022: *
023: * <p>
024: * See <a href="http://www.w3.org/TR/2005/WD-xmlschema-ref-20050329/">XML Schema: Component Designators</a>.
025: * This implementation is based on 03/29/2005 working draft.
026: *
027: * @author Kohsuke Kawaguchi
028: */
029: public abstract class SCD {
030:
031: /**
032: * Parses the string representation of SCD.
033: *
034: * <p>
035: * This method involves parsing the path expression and preparing the in-memory
036: * structure, so this is useful when you plan to use the same SCD against
037: * different context node multiple times.
038: *
039: * <p>
040: * If you want to evaluate SCD just once, use {@link XSComponent#select} methods.
041: *
042: * @param path
043: * the string representation of SCD, such as "/foo/bar".
044: * @param nsContext
045: * Its {@link NamespaceContext#getNamespaceURI(String)} is used
046: * to resolve prefixes in the SCD to the namespace URI.
047: */
048: public static SCD create(String path, NamespaceContext nsContext)
049: throws java.text.ParseException {
050: try {
051: SCDParser p = new SCDParser(path, nsContext);
052: List<?> list = p.RelativeSchemaComponentPath();
053: return new SCDImpl(path, list
054: .toArray(new Step[list.size()]));
055: } catch (TokenMgrError e) {
056: throw setCause(new java.text.ParseException(e.getMessage(),
057: -1), e);
058: } catch (ParseException e) {
059: throw setCause(new java.text.ParseException(e.getMessage(),
060: e.currentToken.beginColumn), e);
061: }
062: }
063:
064: private static java.text.ParseException setCause(
065: java.text.ParseException e, Throwable x) {
066: e.initCause(x);
067: return e;
068: }
069:
070: /**
071: * Evaluates the SCD against the given context node and
072: * returns the matched nodes.
073: *
074: * @return
075: * could be empty but never be null.
076: */
077: public final Collection<XSComponent> select(XSComponent contextNode) {
078: return new DeferedCollection<XSComponent>(select(Iterators
079: .singleton(contextNode)));
080: }
081:
082: /**
083: * Evaluates the SCD against the whole schema and
084: * returns the matched nodes.
085: *
086: * <p>
087: * This method is here because {@link XSSchemaSet}
088: * doesn't implement {@link XSComponent}.
089: *
090: * @return
091: * could be empty but never be null.
092: */
093: public final Collection<XSComponent> select(XSSchemaSet contextNode) {
094: return select(contextNode.getSchemas());
095: }
096:
097: /**
098: * Evaluates the SCD against the given context node and
099: * returns the matched node.
100: *
101: * @return
102: * null if the SCD didn't match anything. If the SCD matched more than one node,
103: * the first one will be returned.
104: */
105: public final XSComponent selectSingle(XSComponent contextNode) {
106: Iterator<XSComponent> r = select(Iterators
107: .singleton(contextNode));
108: if (r.hasNext())
109: return r.next();
110: return null;
111: }
112:
113: /**
114: * Evaluates the SCD against the whole schema set and
115: * returns the matched node.
116: *
117: * @return
118: * null if the SCD didn't match anything. If the SCD matched more than one node,
119: * the first one will be returned.
120: */
121: public final XSComponent selectSingle(XSSchemaSet contextNode) {
122: Iterator<XSComponent> r = select(contextNode.iterateSchema());
123: if (r.hasNext())
124: return r.next();
125: return null;
126: }
127:
128: /**
129: * Evaluates the SCD against the given set of context nodes and
130: * returns the matched nodes.
131: *
132: * @param contextNodes
133: * {@link XSComponent}s that represent the context node against
134: * which {@link SCD} is evaluated.
135: *
136: * @return
137: * could be empty but never be null.
138: */
139: public abstract Iterator<XSComponent> select(
140: Iterator<? extends XSComponent> contextNodes);
141:
142: /**
143: * Evaluates the SCD against the given set of context nodes and
144: * returns the matched nodes.
145: *
146: * @param contextNodes
147: * {@link XSComponent}s that represent the context node against
148: * which {@link SCD} is evaluated.
149: *
150: * @return
151: * could be empty but never be null.
152: */
153: public final Collection<XSComponent> select(
154: Collection<? extends XSComponent> contextNodes) {
155: return new DeferedCollection<XSComponent>(select(contextNodes
156: .iterator()));
157: }
158:
159: /**
160: * Returns the textual SCD representation as given to {@link SCD#create(String, NamespaceContext)}.
161: */
162: public abstract String toString();
163: }
|