001: package net.sf.saxon.event;
002:
003: import net.sf.saxon.om.NamePool;
004: import net.sf.saxon.sort.IntHashSet;
005: import net.sf.saxon.style.StandardNames;
006: import net.sf.saxon.trans.XPathException;
007: import net.sf.saxon.type.AtomicType;
008: import net.sf.saxon.type.SchemaType;
009: import net.sf.saxon.type.Type;
010:
011: /**
012: * IDFilter is a ProxyReceiver that extracts the subtree of a document rooted at the
013: * element with a given ID value. Namespace declarations outside this subtree are
014: * treated as if they were present on the identified element.
015: */
016:
017: public class IDFilter extends StartTagBuffer {
018:
019: private String requiredId;
020: private int activeDepth = 0;
021: private boolean matched = false;
022: private IntHashSet nonIDs;
023:
024: public IDFilter(String id) {
025: // System.err.println("IDFilter, looking for " + id);
026: this .requiredId = id;
027: }
028:
029: /**
030: * startElement
031: */
032:
033: public void startElement(int nameCode, int typeCode,
034: int locationId, int properties) throws XPathException {
035: matched = false;
036: if (activeDepth > 0) {
037: activeDepth++;
038: }
039: super .startElement(nameCode, typeCode, locationId, properties); // this remembers the details
040: }
041:
042: /**
043: * Notify an attribute. Attributes are notified after the startElement event, and before any
044: * children. Namespaces and attributes may be intermingled.
045: *
046: * @param nameCode The name of the attribute, as held in the name pool
047: * @param typeCode The type of the attribute, as held in the name pool
048: * @param properties Bit significant value. The following bits are defined:
049: * <dd>DISABLE_ESCAPING</dd> <dt>Disable escaping for this attribute</dt>
050: * <dd>NO_SPECIAL_CHARACTERS</dd> <dt>Attribute value contains no special characters</dt>
051: * @throws IllegalStateException: attempt to output an attribute when there is no open element
052: * start tag
053: */
054:
055: public void attribute(int nameCode, int typeCode,
056: CharSequence value, int locationId, int properties)
057: throws XPathException {
058: super .attribute(nameCode, typeCode, value, locationId,
059: properties);
060: if ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID
061: || isIDCode(typeCode)) {
062: if (value.toString().equals(requiredId)) {
063: matched = true;
064: }
065: }
066: }
067:
068: /**
069: * startContent: Test if a matching ID attribute was found; if so, start outputting.
070: */
071:
072: public void startContent() throws XPathException {
073: if (activeDepth > 0) {
074: super .startContent();
075: } else if (matched) {
076: activeDepth = 1;
077: super .startContent();
078: }
079: }
080:
081: protected void declareNamespacesForStartElement()
082: throws XPathException {
083: if (activeDepth == 1) {
084: declareAllNamespaces();
085: } else {
086: super .declareNamespacesForStartElement();
087: }
088: }
089:
090: /**
091: * endElement:
092: */
093:
094: public void endElement() throws XPathException {
095: if (activeDepth > 0) {
096: super .endElement();
097: activeDepth--;
098: } else {
099: undeclareNamespacesForElement();
100: }
101: }
102:
103: /**
104: * Character data
105: */
106:
107: public void characters(CharSequence chars, int locationId,
108: int properties) throws XPathException {
109: if (activeDepth > 0) {
110: super .characters(chars, locationId, properties);
111: }
112: }
113:
114: /**
115: * Processing Instruction
116: */
117:
118: public void processingInstruction(String target, CharSequence data,
119: int locationId, int properties) throws XPathException {
120: if (activeDepth > 0) {
121: super .processingInstruction(target, data, locationId,
122: properties);
123: }
124: }
125:
126: /**
127: * Output a comment
128: */
129:
130: public void comment(CharSequence chars, int locationId,
131: int properties) throws XPathException {
132: if (activeDepth > 0) {
133: super .comment(chars, locationId, properties);
134: }
135: }
136:
137: /**
138: * Test whether a type annotation code represents the type xs:ID or one of its subtypes
139: */
140:
141: private boolean isIDCode(int typeCode) {
142: if ((typeCode & NamePool.FP_MASK) == StandardNames.XS_ID) {
143: return true;
144: } else if (typeCode < 1024) {
145: // No other built-in type is an ID
146: return false;
147: } else {
148: if (nonIDs == null) {
149: nonIDs = new IntHashSet(20);
150: }
151: if (nonIDs.contains(typeCode)) {
152: return false;
153: }
154: SchemaType type = getConfiguration()
155: .getSchemaType(typeCode);
156: if (type instanceof AtomicType) {
157: if (getNamePool().getTypeHierarchy().isSubType(
158: (AtomicType) type, Type.ID_TYPE)) {
159: return true;
160: } else {
161: nonIDs.add(typeCode);
162: return false;
163: }
164: } else {
165: return false;
166: }
167: }
168: }
169:
170: }
171: //
172: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
173: // you may not use this file except in compliance with the License. You may obtain a copy of the
174: // License at http://www.mozilla.org/MPL/
175: //
176: // Software distributed under the License is distributed on an "AS IS" basis,
177: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
178: // See the License for the specific language governing rights and limitations under the License.
179: //
180: // The Original Code is: all this file.
181: //
182: // The Initial Developer of the Original Code is Michael H. Kay.
183: //
184: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
185: //
186: // Contributor(s): none.
187: //
|