Project

Profile

Help

Revision 8aaa6119

Added by Norman Tovey-Walsh 9 months ago

Remove HE files that aren't part of Saxon 10

View differences:

src/main/java/net/sf/saxon/event/ReceiverOptions.java
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2018 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

  
8
package net.sf.saxon.event;
9

  
10

  
11
/**
12
 * ReceiverOptions defines a set of constants, which can be used in
13
 * calls to methods on the Receiver interface. The values are
14
 * bit-significant.
15
 *
16
 * @author Michael H. Kay
17
 */
18

  
19

  
20
public class ReceiverOptions {
21

  
22
    /**
23
     * Flag to disable output escaping
24
     */
25

  
26
    public static final int DISABLE_ESCAPING = 1;
27

  
28
    /**
29
     * Flag to disable use of character maps
30
     */
31

  
32
    public static final int DISABLE_CHARACTER_MAPS = 2;
33

  
34
    /**
35
     * Flag indicating that the value contains no special characters
36
     * that need to be escaped
37
     */
38

  
39
    public static final int NO_SPECIAL_CHARS = 4;
40

  
41
    /**
42
     * Flag indicating that an attribute value or text node was added by the schema processor
43
     * because a default value was specified
44
     */
45

  
46
    public static final int DEFAULTED_ATTRIBUTE = 8;
47

  
48
    /**
49
     * Flag used with character content that has been validated against a nillable element
50
     * declaration. Needed because of a peculiar rule for validating xs:key values
51
     */
52

  
53
    public static final int NILLED_ELEMENT = 0x10;
54

  
55
    /**
56
     * Flag indicating that duplicate values should be rejected
57
     */
58

  
59
    public static final int REJECT_DUPLICATES = 0x20;
60

  
61
    /**
62
     * Flag indicating that the namespace (of an element or attribute name)
63
     * has already been declared; it does not need to be generated by the namespace
64
     * fixup process.
65
     */
66

  
67
    public static final int NAMESPACE_OK = 0x40;
68

  
69
    /**
70
     * Flag passed on startElement indicating that the element does not pass
71
     * namespaces on to its children.
72
     */
73

  
74
    public static final int DISINHERIT_NAMESPACES = 0x80;
75

  
76
    /**
77
     * Flag used when an attribute value or text node contains null characters
78
     * before and after strings generated by character mapping; these strings
79
     * are to be output without escaping
80
     */
81

  
82
    public static final int USE_NULL_MARKERS = 0x100;
83

  
84
    /**
85
     * Flag used with character content that has been validated against a nillable element
86
     * declaration. Needed because of a peculiar rule for validating xs:key values
87
     */
88

  
89
    public static final int NILLABLE_ELEMENT = 0x200;
90

  
91
    /**
92
     * Flag used with the characters() event to indicate that the event represents an entire
93
     * text node, that is, the text node has not been fragmented over several characters() events
94
     */
95

  
96
    public static final int WHOLE_TEXT_NODE = 0x400;
97

  
98
    /**
99
     * Flag indicating an element or attribute that has the is-id property
100
     */
101

  
102
    public static final int IS_ID = 0x800;
103

  
104
    /**
105
     * Flag indicating an element or attribute that has the is-idref property (indicating that it is an IDREF
106
     * or IDREFS attribute)
107
     */
108

  
109
    public static final int IS_IDREF = 0x1000;
110

  
111
    /**
112
     * Flag indicating that the ID/IDREF properties have been set if applicable: if this bit is set,
113
     * then the absence of the IS_ID bit means the node is not an ID, and similarly for IS_IDREF
114
     */
115

  
116
    public static final int ID_IDREF_CHECKED = 0x2000;
117

  
118
    /**
119
     * Flag set on startDocument() in relation to an xsl:message call with terminate="yes"
120
     */
121

  
122
    public static final int TERMINATE = 0x4000;
123

  
124
    /**
125
     * Flag set on startDocument() to indicate that the constructed document must be updateable
126
     */
127

  
128
    public static final int MUTABLE_TREE = 0x8000;
129

  
130
    /**
131
     * Flag set on startElement() to indicate that the element does not inherit namespaces
132
     * from its parent
133
     */
134

  
135
    public static final int REFUSE_NAMESPACES = 0x10000;
136

  
137
    /**
138
     * Flag set on startElement() if the element is known to have children
139
     */
140

  
141
    public static final int HAS_CHILDREN = 0x20000;
142

  
143
    /**
144
     * Flag set on append() to indicate that namespaces declared (or undeclared) on this element
145
     * should be copied, but not namespaces inherited from a parent element
146
     */
147
    public static final int LOCAL_NAMESPACES = 0x40000;
148

  
149
    /**
150
     * Flag set on append() to indicate that all in-scope namespaces should be copied
151
     */
152
    public static final int ALL_NAMESPACES = 0x80000;
153

  
154
    /**
155
     * Flag set on attribute() to indicate that there is no need to check for duplicate attributes
156
     */
157
    public static final int NOT_A_DUPLICATE = 0x100000;
158

  
159

  
160
}
161

  
src/main/java/net/sf/saxon/event/SequenceOutputter.java
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2018 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

  
8
package net.sf.saxon.event;
9

  
10
import net.sf.saxon.Controller;
11
import net.sf.saxon.expr.XPathContext;
12
import net.sf.saxon.om.Item;
13
import net.sf.saxon.om.Sequence;
14
import net.sf.saxon.om.SequenceIterator;
15
import net.sf.saxon.tree.iter.EmptyIterator;
16
import net.sf.saxon.tree.iter.ListIterator;
17
import net.sf.saxon.value.EmptySequence;
18
import net.sf.saxon.value.SequenceExtent;
19

  
20
import java.util.ArrayList;
21
import java.util.List;
22

  
23

  
24
/**
25
 * This outputter is used when writing a sequence of atomic values and nodes, that
26
 * is, when xsl:variable is used with content and an "as" attribute. The outputter
27
 * builds the sequence and provides access to it. (It isn't really an outputter at all,
28
 * it doesn't pass the events to anyone, it merely constructs the sequence in memory
29
 * and provides access to it). Note that the event sequence can include calls such as
30
 * startElement and endElement that require trees to be built. If nodes such as attributes
31
 * and text nodes are received while an element is being constructed, the nodes are added
32
 * to the tree. Otherwise, "orphan" nodes (nodes with no parent) are created and added
33
 * directly to the sequence.
34
 * <p>This class is not used to build temporary trees. For that, the ComplexContentOutputter
35
 * is used.</p>
36
 *
37
 * @author Michael H. Kay
38
 */
39

  
40
public final class SequenceOutputter extends SequenceWriter {
41

  
42
    private List<Item<?>> list;
43

  
44

  
45
    /**
46
     * Create a new SequenceOutputter
47
     *
48
     * @param pipe the pipeline configuration
49
     */
50

  
51
    public SequenceOutputter(PipelineConfiguration pipe) {
52
        this(pipe, 50);
53
    }
54

  
55
    public SequenceOutputter(PipelineConfiguration pipe, int estimatedSize) {
56
        super(pipe);
57
        this.list = new ArrayList<>(estimatedSize);
58
    }
59

  
60
    /**
61
     * Allocate a SequenceOutputter. Used from generated bytecode.
62
     *
63
     * @param context  dynamic XPath context
64
     * @param hostLang host language (XSLT/XQuery)
65
     * @return the allocated SequenceOutputter
66
     * @see com.saxonica.ee.bytecode.util.CompilerService
67
     */
68

  
69
    /*@Nullable*/
70
    public static SequenceOutputter allocateSequenceOutputter(XPathContext context, int hostLang) {
71
        Controller controller = context.getController();
72
        SequenceOutputter seq = controller.allocateSequenceOutputter(20);
73
        seq.getPipelineConfiguration().setHostLanguage(hostLang);
74
        return seq;
75
    }
76

  
77
    /**
78
     * Clear the contents of the SequenceOutputter and make it available for reuse
79
     */
80

  
81
    public void reset() {
82
        list = new ArrayList<>(Math.min(list.size() + 10, 50));
83
    }
84

  
85
    /**
86
     * Method to be supplied by subclasses: output one item in the sequence.
87
     */
88

  
89
    public void write(Item item) {
90
        list.add(item);
91
    }
92

  
93
    /**
94
     * Get the sequence that has been built
95
     *
96
     * @return the value (sequence of items) that have been written to this SequenceOutputter
97
     */
98

  
99
    public Sequence<?> getSequence() {
100
        switch (list.size()) {
101
            case 0:
102
                return EmptySequence.getInstance();
103
            case 1:
104
                //noinspection unchecked
105
                return list.get(0);
106
            default:
107
                return new SequenceExtent<>(list);
108
        }
109
    }
110

  
111
    /**
112
     * Get an iterator over the sequence of items that has been constructed
113
     *
114
     * @return an iterator over the items that have been written to this SequenceOutputter
115
     */
116

  
117
    public SequenceIterator<Item<?>> iterate() {
118
        if (list.isEmpty()) {
119
            return EmptyIterator.emptyIterator();
120
        } else {
121
            return new ListIterator<>(list);
122
        }
123
    }
124

  
125
    /**
126
     * Get the list containing the sequence of items
127
     *
128
     * @return the list of items that have been written to this SequenceOutputter
129
     */
130

  
131
    public List<Item<?>> getList() {
132
        return list;
133
    }
134

  
135
    /**
136
     * Get the first item in the sequence that has been built
137
     *
138
     * @return the first item in the list of items that have been written to this SequenceOutputter;
139
     *         or null if the list is empty.
140
     */
141

  
142
    public Item getFirstItem() {
143
        if (list.isEmpty()) {
144
            return null;
145
        } else {
146
            return list.get(0);
147
        }
148
    }
149

  
150
    /**
151
     * Get the last item in the sequence that has been built, and remove it
152
     *
153
     * @return the last item written
154
     */
155

  
156
    public Item popLastItem() {
157
        if (list.isEmpty()) {
158
            return null;
159
        } else {
160
            return list.remove(list.size() - 1);
161
        }
162
    }
163

  
164

  
165
}
166

  
src/main/java/net/sf/saxon/event/StartTagBuffer.java
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2018 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

  
8
package net.sf.saxon.event;
9

  
10
import net.sf.saxon.expr.parser.ExplicitLocation;
11
import net.sf.saxon.expr.parser.Location;
12
import net.sf.saxon.lib.NamespaceConstant;
13
import net.sf.saxon.om.*;
14
import net.sf.saxon.trans.XPathException;
15
import net.sf.saxon.tree.util.AttributeCollectionImpl;
16
import net.sf.saxon.type.SchemaType;
17
import net.sf.saxon.type.SimpleType;
18
import net.sf.saxon.type.Type;
19

  
20
import java.util.ArrayList;
21
import java.util.Arrays;
22
import java.util.Iterator;
23
import java.util.List;
24

  
25
/**
26
 * StartTagBuffer is a ProxyReceiver that buffers attributes and namespace events within a start tag.
27
 * It maintains details of the namespace context, and a full set of attribute information, on behalf
28
 * of other filters that need access to namespace information or need to process attributes in arbitrary
29
 * order.
30
 * <p>StartTagBuffer also implements namespace fixup (the process of creating namespace nodes|bindings on behalf
31
 * of constructed element and attribute nodes). Although this would be done anyway, further down the pipeline,
32
 * it has to be done early in the case of a validating pipeline, because the namespace bindings must be created
33
 * before any namespace-sensitive attribute content is validated.</p>
34
 * <p>The StartTagBuffer also allows error conditions to be buffered. This is because the XSIAttributeHandler
35
 * validates attributes such as xsi:type and xsi:nil before attempting to match its parent element against
36
 * a particle of its containing type. It is possible that the parent element will match a wildcard particle
37
 * with processContents="skip", in which case an invalid xsi:type or xsi:nil attribute is not an error.</p>
38
 */
39

  
40
public class StartTagBuffer extends ProxyReceiver implements NamespaceResolver {
41

  
42
    public StartTagBuffer(Receiver next) {
43
        super(next);
44
    }
45

  
46
    // Details of the pending element event
47

  
48
    protected NodeName elementNameCode;
49
    protected SchemaType elementTypeCode;
50
    protected Location elementLocationId;
51
    protected int elementProperties;
52

  
53
    // Details of pending attribute events
54

  
55
    protected AttributeCollectionImpl bufferedAttributes;
56
    private boolean acceptAttributes;
57
    private boolean inDocument;
58
    private boolean inStartTag;
59

  
60
    // We keep track of namespaces. The namespaces
61
    // array holds a list of all namespaces currently declared (organised as pairs of entries,
62
    // prefix followed by URI). The stack contains an entry for each element currently open; the
63
    // value on the stack is an Integer giving the number of namespaces added to the main
64
    // namespace stack by that element.
65

  
66
    protected NamespaceBinding[] namespaces = new NamespaceBinding[50];          // all namespaces currently declared
67
    protected int namespacesSize = 0;                  // all namespaces currently declared
68
    private int[] countStack = new int[50];
69
    private int depth = 0;
70
    private int attCount = 0;
71

  
72
    // The preceding filter in the pipeline can notify this class, immediately before calling startContent(),
73
    // that the current element node has children
74

  
75
    private boolean hasChildren = false;
76

  
77
    /**
78
     * Set the pipeline configuration
79
     *
80
     * @param pipe the pipeline configuration
81
     */
82

  
83
    public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipe) {
84
        super.setPipelineConfiguration(pipe);
85
        bufferedAttributes = new AttributeCollectionImpl(pipe.getConfiguration());
86
    }
87

  
88
    /**
89
     * Start of a document node.
90
     */
91

  
92
    public void startDocument(int properties) throws XPathException {
93
        // a document node in the content sequence of an element is ignored. However, we need
94
        // to stop attributes being created within the document node.
95
        if (depth == 0) {
96
            depth++;
97
            super.startDocument(properties);
98
        }
99
        acceptAttributes = false;
100
        inDocument = true;      // we ought to clear this on endDocument, but it only affects diagnostics
101
        inStartTag = false;
102
    }
103

  
104

  
105
    /**
106
     * Notify the end of a document node
107
     */
108

  
109
    public void endDocument() throws XPathException {
110
        if (depth == 1) {
111
            depth--;
112
            super.endDocument();
113
        }
114
    }
115

  
116
    /**
117
     * startElement
118
     */
119

  
120
    public void startElement(NodeName nameCode, SchemaType typeCode, Location location, int properties) throws XPathException {
121

  
122
        maybeStartContent();
123
        
124
        elementNameCode = nameCode;
125
        elementTypeCode = typeCode;
126
        elementLocationId = location.saveLocation();
127
        elementProperties = properties;
128

  
129
        bufferedAttributes.clear();
130
        hasChildren = false;
131

  
132
        // Record the current height of the namespace list so it can be reset at endElement time
133

  
134
        countStack[depth] = 0;
135
        if (++depth >= countStack.length) {
136
            countStack = Arrays.copyOf(countStack, depth * 2);
137
        }
138

  
139
        // Ensure that the element namespace is output, unless this is done
140
        // automatically by the caller (which is true, for example, for a literal
141
        // result element).
142

  
143
        acceptAttributes = true;
144
        inDocument = false;
145
        if ((properties & ReceiverOptions.NAMESPACE_OK) == 0) {
146
            namespace(nameCode.getNamespaceBinding(), 0);
147
        }
148
        attCount = 0;
149
        inStartTag = true;
150
    }
151

  
152
    public void namespace(NamespaceBindingSet namespaceBindings, int properties) throws XPathException {
153

  
154
        for (NamespaceBinding ns : namespaceBindings) {
155
            if (!acceptAttributes) {
156
                throw NoOpenStartTagException.makeNoOpenStartTagException(
157
                        Type.NAMESPACE, ns.getPrefix(),
158
                        getPipelineConfiguration().getHostLanguage(),
159
                        inDocument, ExplicitLocation.UNKNOWN_LOCATION);
160
            }
161

  
162
            // avoid duplicates
163
            boolean duplicate = false;
164
            for (int n = 0; n < countStack[depth - 1]; n++) {
165
                if (namespaces[namespacesSize - 1 - n].equals(ns)) {
166
                    duplicate = true;
167
                    break;
168
                }
169
            }
170
            if (!duplicate) {
171
                addToStack(ns);
172
                countStack[depth - 1]++;
173
            }
174
        }
175
    }
176

  
177
    /**
178
     * Notify an attribute. Attributes are notified after the startElement event, and before any
179
     * children. Namespaces and attributes may be intermingled.
180
     *
181
     * @param attName    The name of the attribute
182
     * @param typeCode   The type of the attribute
183
     * @param locationId the location of the node in the source, or of the instruction that created it
184
     * @param properties Bit significant value. The following bits are defined:
185
     *                   <dl>
186
     *                   <dd>DISABLE_ESCAPING</dd>    <dt>Disable escaping for this attribute</dt>
187
     *                   <dd>NO_SPECIAL_CHARACTERS</dd>      <dt>Attribute value contains no special characters</dt>
188
     *                   </dl>
189
     * @throws IllegalStateException: attempt to output an attribute when there is no open element
190
     *                                start tag
191
     */
192

  
193
    public void attribute(NodeName attName, SimpleType typeCode, CharSequence value, Location locationId, int properties)
194
            throws XPathException {
195

  
196
        if (!acceptAttributes) {
197
            throw NoOpenStartTagException.makeNoOpenStartTagException(
198
                    Type.ATTRIBUTE, attName.getDisplayName(),
199
                    getPipelineConfiguration().getHostLanguage(),
200
                    inDocument, ExplicitLocation.UNKNOWN_LOCATION);
201
        }
202

  
203
        // Perform namespace fixup for the attribute
204

  
205
        if (((properties & ReceiverOptions.NAMESPACE_OK) == 0) &&
206
                !attName.hasURI("")) {    // non-null prefix
207
            attName = checkProposedPrefix(attName, attCount++);
208
        }
209
        bufferedAttributes.addAttribute(attName, typeCode, value.toString(), locationId, properties);
210

  
211
        // Note: we're relying on the fact that AttributeCollection can hold two attributes of the same name
212
        // and maintain their order, because the check for duplicate attributes is not done until later in the
213
        // pipeline. We validate both the attributes (see Bugzilla #4600 which legitimizes this.)
214

  
215
    }
216

  
217
    /**
218
     * Add a namespace declaration (or undeclaration) to the stack
219
     *
220
     * @param binding the namespace binding for the declaration
221
     */
222

  
223
    private void addToStack(NamespaceBinding binding) {
224
        // expand the stack if necessary
225
        if (namespacesSize + 1 >= namespaces.length) {
226
            namespaces = Arrays.copyOf(namespaces, namespacesSize * 2);
227
        }
228
        namespaces[namespacesSize++] = binding;
229
    }
230

  
231
    public void setHasChildren(boolean hasChildren) {
232
        this.hasChildren = hasChildren;
233
    }
234

  
235
    /**
236
     * startContent: Add any namespace undeclarations needed to stop
237
     * namespaces being inherited from parent elements
238
     */
239

  
240
    public void startContent() throws XPathException {
241
        inStartTag = false;
242
        int props = elementProperties | ReceiverOptions.NAMESPACE_OK;
243
        if (hasChildren) {
244
            props |= ReceiverOptions.HAS_CHILDREN;
245
        }
246
        nextReceiver.startElement(elementNameCode, elementTypeCode, elementLocationId, props);
247
        declareNamespacesForStartElement();
248

  
249
        final int length = bufferedAttributes.getLength();
250
        for (int i = 0; i < length; i++) {
251
            nextReceiver.attribute(bufferedAttributes.getNodeName(i),
252
                    bufferedAttributes.getTypeAnnotation(i),
253
                    bufferedAttributes.getValue(i),
254
                    bufferedAttributes.getLocation(i),
255
                    bufferedAttributes.getProperties(i) | ReceiverOptions.NAMESPACE_OK);
256
        }
257
        acceptAttributes = false;
258
        nextReceiver.startContent();
259
    }
260

  
261
    private void maybeStartContent() throws XPathException {
262
        if (inStartTag) {
263
            startContent();
264
        }
265
    }
266

  
267
    protected void declareNamespacesForStartElement() throws XPathException {
268
        for (int i = namespacesSize - countStack[depth - 1]; i < namespacesSize; i++) {
269
            nextReceiver.namespace(namespaces[i], 0);
270
        }
271
    }
272

  
273
    /**
274
     * Get the namespaces declared (or undeclared) at the current level
275
     *
276
     * @return an array of namespace bindings
277
     */
278

  
279
    public NamespaceBinding[] getLocalNamespaces() {
280
        int size = countStack[depth - 1];
281
        if (size == 0) {
282
            return NamespaceBinding.EMPTY_ARRAY;
283
        } else {
284
            NamespaceBinding[] localBindings = new NamespaceBinding[countStack[depth - 1]];
285
            System.arraycopy(namespaces, namespacesSize - size, localBindings, 0, size);
286
            return localBindings;
287
        }
288
    }
289

  
290
    /**
291
     * Signal namespace events for all in-scope namespaces to the current receiver in the pipeline
292
     *
293
     * @throws XPathException if any downstream error occurs
294
     */
295

  
296
    protected void declareAllNamespaces() throws XPathException {
297
        for (int i = 0; i < namespacesSize; i++) {
298
            nextReceiver.namespace(namespaces[i], 0);
299
        }
300
    }
301

  
302
    /**
303
     * endElement: Discard the namespaces declared locally on this element.
304
     */
305

  
306
    public void endElement() throws XPathException {
307
        maybeStartContent();
308
        nextReceiver.endElement();
309
        undeclareNamespacesForElement();
310
    }
311

  
312
    protected void undeclareNamespacesForElement() {
313
        namespacesSize -= countStack[--depth];
314
    }
315

  
316
    /**
317
     * Determine if the current element has any attributes
318
     *
319
     * @return true if the element has one or more attributes
320
     */
321

  
322
    public boolean hasAttributes() {
323
        return bufferedAttributes.getLength() > 0;
324
    }
325

  
326
    /**
327
     * Get the value of the current attribute with a given nameCode
328
     *
329
     * @param nameCode the name of the required attribute
330
     * @return the attribute value, or null if the attribute is not present
331
     */
332

  
333
    public String getAttribute(int nameCode) {
334
        return bufferedAttributes.getValueByFingerprint(nameCode & 0xfffff);
335
    }
336

  
337
    /**
338
     * Get the value of the current attribute with a given name
339
     *
340
     * @param uri   the uri of the name of the required attribute
341
     * @param local the local part of the name of the required attribute
342
     * @return the attribute value, or null if the attribute is not present
343
     */
344

  
345
    public String getAttribute(String uri, String local) {
346
        return bufferedAttributes.getValue(uri, local);
347
    }
348

  
349
    /**
350
     * Get all the attributes on the current element start tag
351
     *
352
     * @return an AttributeCollection containing all the attributes
353
     */
354

  
355
    public AttributeCollection getAllAttributes() {
356
        return bufferedAttributes;
357
    }
358

  
359
    /**
360
     * Ask whether the attribute collection contains any attributes
361
     * in a specified namespace
362
     *
363
     * @param uri the specified namespace
364
     * @return true if there are one or more attributes in this namespace
365
     */
366

  
367
    public boolean hasAttributeInNamespace(String uri) {
368
        return bufferedAttributes.hasAttributeInNamespace(uri);
369
    }
370

  
371
    /**
372
     * Get the namespace URI corresponding to a given prefix. Return null
373
     * if the prefix is not in scope.                                                         f
374
     *
375
     * @param prefix     the namespace prefix
376
     * @param useDefault true if the default namespace is to be used when the
377
     *                   prefix is ""
378
     * @return the uri for the namespace, or null if the prefix is not in scope
379
     */
380

  
381
    /*@Nullable*/
382
    public String getURIForPrefix(String prefix, boolean useDefault) {
383
        if (prefix.isEmpty() && !useDefault) {
384
            return NamespaceConstant.NULL;
385
        } else if ("xml".equals(prefix)) {
386
            return NamespaceConstant.XML;
387
        } else {
388
            for (int i = namespacesSize - 1; i >= 0; i--) {
389
                if (namespaces[i].getPrefix().equals(prefix)) {
390
                    String uri = namespaces[i].getURI();
391
                    if (uri.isEmpty()) {
392
//                    // we've found a namespace undeclaration, so it's as if the prefix weren't there at all
393
                    } else {
394
                        return uri;
395
                    }
396
                }
397
            }
398
        }
399
        return (prefix.isEmpty() ? NamespaceConstant.NULL : null);
400
    }
401

  
402
    /**
403
     * Get an iterator over all the prefixes declared in this namespace context. This will include
404
     * the default namespace (prefix="") and the XML namespace where appropriate
405
     */
406

  
407
    public Iterator<String> iteratePrefixes() {
408
        List<String> prefixes = new ArrayList<String>(namespacesSize);
409
        for (int i = namespacesSize - 1; i >= 0; i--) {
410
            String prefix = namespaces[i].getPrefix();
411
            if (!prefixes.contains(prefix)) {
412
                prefixes.add(prefix);
413
            }
414
        }
415
        prefixes.add("xml");
416
        return prefixes.iterator();
417
    }
418

  
419
    /**
420
     * Check that the prefix for an element or attribute is acceptable, allocating a substitute
421
     * prefix if not. The prefix is acceptable unless a namespace declaration has been
422
     * written that assignes this prefix to a different namespace URI. This method
423
     * also checks that the element or attribute namespace has been declared, and declares it
424
     * if not.
425
     *
426
     * @param nameCode the proposed element or attribute name
427
     * @param seq      sequence number of attribute, used for generating distinctive prefixes
428
     * @return the actual allocated name, which may be different.
429
     * @throws net.sf.saxon.trans.XPathException
430
     *          if any error occurs writing the new namespace binding
431
     */
432

  
433
    private NodeName checkProposedPrefix(NodeName nameCode, int seq) throws XPathException {
434
        NamespaceBinding binding = nameCode.getNamespaceBinding();
435
        String prefix = binding.getPrefix();
436

  
437
        String existingURI = getURIForPrefix(prefix, true);
438
        if (existingURI == null) {
439
            // prefix has not been declared: declare it now (namespace fixup)
440
            namespace(binding, 0);
441
            return nameCode;
442
        } else {
443
            if (binding.getURI().equals(existingURI)) {
444
                // prefix is already bound to this URI
445
                return nameCode;    // all is well
446
            } else {
447
                // conflict: prefix is currently bound to a different URI
448
                prefix = getSubstitutePrefix(binding, seq);
449

  
450
                NodeName newCode = new FingerprintedQName(
451
                        prefix,
452
                        nameCode.getURI(),
453
                        nameCode.getLocalPart());
454
                namespace(newCode.getNamespaceBinding(), 0);
455
                return newCode;
456
            }
457
        }
458
    }
459

  
460
    /**
461
     * It is possible for a single output element to use the same prefix to refer to different
462
     * namespaces. In this case we have to generate an alternative prefix for uniqueness. The
463
     * one we generate is based on the sequential position of the element/attribute: this is
464
     * designed to ensure both uniqueness (with a high probability) and repeatability
465
     *
466
     * @param binding the namespace binding of the proposed element or attribute name
467
     * @param seq     sequence number of attribute, used for generating distinctive prefixes
468
     * @return the actual allocated name, which may be different.
469
     */
470

  
471
    private String getSubstitutePrefix(NamespaceBinding binding, int seq) {
472
        String prefix = binding.getPrefix();
473
        return prefix + '_' + seq;
474
    }
475

  
476
    /**
477
     * Character data
478
     *
479
     * @param chars
480
     * @param locationId the location of the node in the source, or of the instruction that created it
481
     * @param properties
482
     */
483
    @Override
484
    public void characters(CharSequence chars, Location locationId, int properties) throws XPathException {
485
        maybeStartContent();
486
        nextReceiver.characters(chars, locationId, properties);
487
    }
488

  
489
    /**
490
     * Processing Instruction
491
     *
492
     * @param target
493
     * @param data
494
     * @param locationId the location of the node in the source, or of the instruction that created it
495
     * @param properties
496
     */
497
    @Override
498
    public void processingInstruction(String target, CharSequence data, Location locationId, int properties) throws XPathException {
499
        maybeStartContent();
500
        nextReceiver.processingInstruction(target, data, locationId, properties);
501
    }
502

  
503
    /**
504
     * Output a comment
505
     *
506
     * @param chars
507
     * @param locationId the location of the node in the source, or of the instruction that created it
508
     * @param properties
509
     */
510
    @Override
511
    public void comment(CharSequence chars, Location locationId, int properties) throws XPathException {
512
        maybeStartContent();
513
        nextReceiver.comment(chars, locationId, properties);
514
    }
515
}
516

  
src/main/java/net/sf/saxon/expr/EveryItemMappingIterator.java
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2018 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

  
8
package net.sf.saxon.expr;
9

  
10
import net.sf.saxon.om.Item;
11
import net.sf.saxon.om.SequenceIterator;
12
import net.sf.saxon.trans.XPathException;
13

  
14
/**
15
 * EveryItemMappingIterator applies a mapping function to each item in a sequence.
16
 * The mapping function always returns a single item (never null)
17
 * <p>This is a specialization of the more general MappingIterator class, for use
18
 * in cases where a single input item always maps to exactly one output item</p>
19
 */
20

  
21
public final class EveryItemMappingIterator implements SequenceIterator {
22

  
23
    private SequenceIterator base;
24
    private ItemMappingFunction action;
25

  
26
    /**
27
     * Construct an ItemMappingIterator that will apply a specified DummyItemMappingFunction to
28
     * each Item returned by the base iterator.
29
     *
30
     * @param base   the base iterator
31
     * @param action the mapping function to be applied
32
     */
33

  
34
    public EveryItemMappingIterator(SequenceIterator base, ItemMappingFunction action) {
35
        this.base = base;
36
        this.action = action;
37
    }
38

  
39
    public Item next() throws XPathException {
40
        Item nextSource = base.next();
41
        if (nextSource == null) {
42
            return null;
43
        }
44
        // Call the supplied mapping function
45
        return action.mapItem(nextSource);
46
    }
47

  
48
    public void close() {
49
        base.close();
50
    }
51

  
52
    /**
53
     * Get properties of this iterator, as a bit-significant integer.
54
     *
55
     * @return the properties of this iterator. This will be some combination of
56
     *         properties such as {@link net.sf.saxon.om.SequenceIterator#GROUNDED},
57
     *         {@link net.sf.saxon.om.SequenceIterator#LAST_POSITION_FINDER},
58
     *         and {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD}. It is always
59
     *         acceptable to return the value zero, indicating that there are no known special properties.
60
     *         It is acceptable for the properties of the iterator to change depending on its state.
61
     */
62

  
63
    public int getProperties() {
64
        return 0;
65
    }
66
}
67

  
src/main/java/net/sf/saxon/expr/instruct/InstructionDetails.java
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2018 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

  
8
package net.sf.saxon.expr.instruct;
9

  
10
import net.sf.saxon.expr.Expression;
11
import net.sf.saxon.expr.parser.ExplicitLocation;
12
import net.sf.saxon.expr.parser.Location;
13
import net.sf.saxon.om.StructuredQName;
14
import net.sf.saxon.trace.InstructionInfo;
15
import net.sf.saxon.trace.LocationKind;
16

  
17
import java.util.HashMap;
18
import java.util.Iterator;
19

  
20
/**
21
 * Details about an instruction, used when reporting errors and when tracing
22
 */
23

  
24
public final class InstructionDetails implements InstructionInfo {
25

  
26
    private int constructType = LocationKind.UNCLASSIFIED;
27
    /*@Nullable*/ private String systemId = null;
28
    private int lineNumber = -1;
29
    private int columnNumber = -1;
30
    /*@Nullable*/ private StructuredQName objectName;
31
    private HashMap<String, Object> properties = new HashMap<String, Object>(5);
32

  
33
    public InstructionDetails() {
34
    }
35

  
36
    public InstructionDetails(Expression expr) {
37
        setConstructType(expr.getConstructType());
38
        setLineNumber(expr.getLocation().getLineNumber());
39
        setSystemId(expr.getLocation().getSystemId());
40
        setColumnNumber(expr.getLocation().getColumnNumber());
41
        setProperty("name", expr.getExpressionName());
42
    }
43

  
44
    /**
45
     * Set the type of construct
46
     *
47
     * @param type the type of contruct
48
     */
49

  
50
    public void setConstructType(int type) {
51
        constructType = type;
52
    }
53

  
54
    /**
55
     * Get the construct type
56
     */
57
    public int getConstructType() {
58
        return constructType;
59
    }
60

  
61
    /**
62
     * Set the URI of the module containing the instruction
63
     *
64
     * @param systemId the module's URI, or null indicating unknown
65
     */
66

  
67
    public void setSystemId(/*@Nullable*/ String systemId) {
68
        this.systemId = systemId;
69
    }
70

  
71
    /**
72
     * Get the URI of the module containing the instruction
73
     *
74
     * @return the module's URI, or null indicating unknown
75
     */
76

  
77
    /*@Nullable*/
78
    public String getSystemId() {
79
        return systemId;
80
    }
81

  
82
    /**
83
     * Set the line number of the instruction within the module
84
     *
85
     * @param lineNumber the line number
86
     */
87

  
88
    public void setLineNumber(int lineNumber) {
89
        this.lineNumber = lineNumber;
90
    }
91

  
92
    /**
93
     * Get the line number of the instruction within its module
94
     *
95
     * @return the line number
96
     */
97

  
98
    public int getLineNumber() {
99
        return lineNumber;
100
    }
101

  
102
    /**
103
     * Get an immutable copy of this Location object. By default Location objects may be mutable, so they
104
     * should not be saved for later use. The result of this operation holds the same location information,
105
     * but in an immutable form.
106
     */
107
    public Location saveLocation() {
108
        return new ExplicitLocation(this);
109
    }
110

  
111
    /**
112
     * Set a name identifying the object of the expression, for example a function name, template name,
113
     * variable name, key name, element name, etc. This is used only where the name is known statically.
114
     *
115
     * @param qName the name of the object, for example a function or variable name, or null to indicate
116
     *              that it has no name
117
     */
118

  
119
    public void setObjectName(/*@Nullable*/ StructuredQName qName) {
120
        objectName = qName;
121
    }
122

  
123
    /**
124
     * Get a name identifying the object of the expression, for example a function name, template name,
125
     * variable name, key name, element name, etc. This is used only where the name is known statically.
126
     *
127
     * @return the name of the object, or null to indicate that it has no name
128
     */
129

  
130
    /*@Nullable*/
131
    public StructuredQName getObjectName() {
132
        if (objectName != null) {
133
            return objectName;
134
        } else {
135
            return null;
136
        }
137
    }
138

  
139
    /**
140
     * Set a named property of the instruction
141
     *
142
     * @param name  the name of the property
143
     * @param value the value of the property
144
     */
145

  
146
    public void setProperty(String name, Object value) {
147
        properties.put(name, value);
148
    }
149

  
150
    /**
151
     * Get a named property of the instruction
152
     *
153
     * @param name name of the property
154
     * @return the value of the named property
155
     */
156

  
157
    public Object getProperty(String name) {
158
        return properties.get(name);
159
    }
160

  
161
    /**
162
     * Get an iterator over all the properties available. The values returned by the iterator
163
     * will be of type String, and each string can be supplied as input to the getProperty()
164
     * method to retrieve the value of the property.
165
     *
166
     * @return an iterator over the names of the properties
167
     */
168

  
169
    public Iterator<String> getProperties() {
170
        return properties.keySet().iterator();
171
    }
172

  
173
    /**
174
     * Get the public ID of the module containing the instruction. This method
175
     * is provided to satisfy the SourceLocator interface. However, the public ID is
176
     * not maintained by Saxon, and the method always returns null
177
     *
178
     * @return null
179
     */
180

  
181
    public String getPublicId() {
182
        return null;
183
    }
184

  
185
    /**
186
     * Set the column number
187
     *
188
     * @param column the column number of the instruction in the source module
189
     */
190

  
191
    public void setColumnNumber(int column) {
192
        columnNumber = column;
193
    }
194

  
195
    /**
196
     * Get the column number identifying the position of the instruction.
197
     *
198
     * @return -1 if column number is not known
199
     */
200

  
201
    public int getColumnNumber() {
202
        return columnNumber;
203
    }
204

  
205
}
206

  
src/main/java/net/sf/saxon/expr/instruct/SavedNamespaceContext.java
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2018 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

  
8
package net.sf.saxon.expr.instruct;
9

  
10
import net.sf.saxon.lib.NamespaceConstant;
11
import net.sf.saxon.om.NamespaceBinding;
12
import net.sf.saxon.om.NamespaceResolver;
13

  
14
import java.util.*;
15
import java.util.function.Predicate;
16

  
17
/**
18
 * An object representing a list of Namespaces. Used when the namespace
19
 * controller in the stylesheet needs to be kept for use at run-time. The list of namespaces
20
 * is maintained in the form of numeric prefix/uri codes, which are only meaningful
21
 * in the context of a name pool
22
 */
23

  
24
public final class SavedNamespaceContext implements NamespaceResolver {
25

  
26
    private Map<String, String> bindings = new HashMap<>();
27

  
28
    /**
29
     * Create a NamespaceContext object
30
     *
31
     * @param nsBindings an array of namespace bindings. Each namespace code is an integer
32
     *                   in which the first 16 bits represent the prefix (zero if it's the default namespace)
33
     *                   and the next 16 bits represent the uri. These are codes held in the NamePool. The
34
     *                   list will be searched from the "high" end.
35
     */
36

  
37
    public SavedNamespaceContext(/*@NotNull*/ Iterable<NamespaceBinding> nsBindings) {
38
        this(nsBindings.iterator());
39
    }
40

  
41
    /**
42
     * Create a NamespaceContext object
43
     *
44
     * @param nsBindings an array of namespace bindings. Each namespace code is an integer
45
     *                   in which the first 16 bits represent the prefix (zero if it's the default namespace)
46
     *                   and the next 16 bits represent the uri. These are codes held in the NamePool. The
47
     *                   list will be searched from the "high" end.
48
     */
49

  
50
    public SavedNamespaceContext(Iterator<NamespaceBinding> nsBindings) {
51
        while (nsBindings.hasNext()) {
52
            NamespaceBinding next = nsBindings.next();
53
            bindings.put(next.getPrefix(), next.getURI());
54
        }
55
    }
56

  
57
    /**
58
     * Create a NamespaceContext object, excluding some namespaces
59
     *
60
     * @param nsBindings an array of namespace bindings. Each namespace code is an integer
61
     *                   in which the first 16 bits represent the prefix (zero if it's the default namespace)
62
     *                   and the next 16 bits represent the uri. These are codes held in the NamePool. The
63
     *                   list will be searched from the "high" end.
64
     */
65

  
66
    public SavedNamespaceContext(Iterator<NamespaceBinding> nsBindings, Predicate<NamespaceBinding> excluded) {
67
        while (nsBindings.hasNext()) {
68
            NamespaceBinding next = nsBindings.next();
69
            if (!excluded.test(next)) {
70
                bindings.put(next.getPrefix(), next.getURI());
71
            }
72
        }
73
    }
74

  
75
    /**
76
     * Create a SavedNamespaceContext that captures all the information in a given NamespaceResolver
77
     *
78
     * @param resolver the NamespaceResolver
79
     */
80

  
81
    public SavedNamespaceContext(/*@NotNull*/ NamespaceResolver resolver) {
82
        Iterator iter = resolver.iteratePrefixes();
83
        while (iter.hasNext()) {
84
            String prefix = (String) iter.next();
85
            String uri = resolver.getURIForPrefix(prefix, true);
86
            bindings.put(prefix, uri);
87
        }
88
    }
89

  
90
    /**
91
     * Get the namespace URI corresponding to a given prefix. Return null
92
     * if the prefix is not in scope.
93
     *
94
     * @param prefix     the namespace prefix
95
     * @param useDefault true if the default namespace is to be used when the
96
     *                   prefix is ""
97
     * @return the uri for the namespace, or null if the prefix is not in scope
98
     */
99

  
100
    /*@Nullable*/
101
    public String getURIForPrefix(/*@NotNull*/ String prefix, boolean useDefault) {
102

  
103
        if (prefix.isEmpty() && !useDefault) {
104
            return NamespaceConstant.NULL;
105
        }
106

  
107
        if (prefix.equals("xml")) {
108
            return NamespaceConstant.XML;
109
        }
110

  
111
        String uri = bindings.get(prefix);
112
        if (uri == null) {
113
            return prefix.isEmpty() ? NamespaceConstant.NULL : null;
114
        } else {
115
            return uri;
116
        }
117
    }
118

  
119
    /**
120
     * Get an iterator over all the prefixes declared in this namespace context. This will include
121
     * the default namespace (prefix="") and the XML namespace where appropriate
122
     */
123

  
124
    public Iterator<String> iteratePrefixes() {
125
        List<String> prefixes = new ArrayList<>(bindings.size() + 1);
126
        prefixes.addAll(bindings.keySet());
127
        prefixes.add("xml");
128
        return prefixes.iterator();
129
    }
130

  
131
    /**
132
     * Compare this saved namespace context to another (so that they can be shared)
133
     * @param obj the other namespace context
134
     */
135

  
136
    @Override
137
    public boolean equals(Object obj) {
138
        return obj instanceof SavedNamespaceContext && bindings.equals(((SavedNamespaceContext) obj).bindings);
139
    }
140

  
141
    @Override
142
    public int hashCode() {
143
        return bindings.hashCode();
144
    }
145
}
146

  
src/main/java/net/sf/saxon/expr/parser/ExplicitLocation.java
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2018 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

  
8
package net.sf.saxon.expr.parser;
9

  
10
import org.xml.sax.Locator;
11

  
12
import javax.xml.transform.SourceLocator;
13

  
14
/**
15
 * Class to hold details of the location of an expression, of an error in a source file, etc.
16
 * The object is immutable.
17
 */
18

  
19
public class ExplicitLocation implements Location {
20

  
21
    private String systemId;
22
    private int lineNumber;
23
    private int columnNumber = -1;
24

  
25
    public static ExplicitLocation UNKNOWN_LOCATION = new ExplicitLocation(null, -1, -1);
26

  
27
    /**
28
     * Create an ExpressionLocation, taking the data from a supplied JAXP SourceLocator
29
     *
30
     * @param loc the JAXP SourceLocator
31
     */
32

  
33
    public ExplicitLocation(SourceLocator loc) {
34
        systemId = loc.getSystemId();
35
        lineNumber = loc.getLineNumber();
36
        columnNumber = loc.getColumnNumber();
37
    }
38

  
39
    /**
40
     * Create an ExpressionLocation, taking the data from a supplied SAX Locator
41
     *
42
     * @param loc the SAX Locator
43
     */
44

  
45
    public static ExplicitLocation makeFromSax(Locator loc) {
46
        return new ExplicitLocation(loc.getSystemId(), loc.getLineNumber(), loc.getColumnNumber());
47
    }
48

  
49
    /**
50
     * Create an ExpressionLocation corresponding to a given module, line number, and column number
51
     *
52
     * @param systemId     the module URI
53
     * @param lineNumber   the line number (starting at 1; -1 means unknown)
54
     * @param columnNumber the column number (starting at 1; -1 means unknown)
55
     */
56

  
57
    public ExplicitLocation(String systemId, int lineNumber, int columnNumber) {
58
        this.systemId = systemId;
59
        this.lineNumber = lineNumber;
60
        this.columnNumber = columnNumber;
61
    }
62

  
63
    /**
64
     * Get the system ID (the module URI)
65
     *
66
     * @return the system ID
67
     */
68

  
69
    public String getSystemId() {
70
        return systemId;
71
    }
72

  
73
    /**
74
     * Get the Public ID
75
     *
76
     * @return always null in this implementation
77
     */
78

  
79
    /*@Nullable*/
80
    public String getPublicId() {
81
        return null;
82
    }
83

  
84
    /**
85
     * Get the line number
86
     *
87
     * @return the line number
88
     */
89

  
90
    public int getLineNumber() {
91
        return lineNumber;
92
    }
93

  
94
    /**
95
     * Get the column number
96
     *
97
     * @return the column number
98
     */
99

  
100
    public int getColumnNumber() {
101
        return columnNumber;
102
    }
103

  
104
    /**
105
     * Get an immutable copy of this Location object. By default Location objects may be mutable, so they
106
     * should not be saved for later use. The result of this operation holds the same location information,
107
     * but in an immutable form.
108
     */
109
    public Location saveLocation() {
110
        return this;
111
    }
112

  
113
    /**
114
     * Ask whether this is an "unknown location"
115
     */
116

  
117
    public static boolean isUnknown(Location location) {
118
        return location == null || (location.getSystemId() == null || location.getSystemId().isEmpty())
119
                && location.getLineNumber() == -1;
120
    }
121

  
122

  
123
}
src/main/java/net/sf/saxon/expr/parser/Location.java
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright (c) 2018 Saxonica Limited.
3
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
6
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7

  
8
package net.sf.saxon.expr.parser;
9

  
10
import org.xml.sax.Locator;
11

  
12
import javax.xml.transform.SourceLocator;
13

  
14
/**
15
 * Saxon interface to represent a location, typically the location of an expression within a query
16
 * or stylesheet. The interface combines the two JAXP interfaces SourceLocator and Locator.
17
 */
18

  
19
public interface Location extends SourceLocator, Locator {
20

  
21
    /**
22
     * Get the system ID. This should be the system identifier of an XML external entity; if a stylesheet module
23
     * comprises multiple external entities, the distinction should be retained. This means, for example, that
24
     * an instruction in a stylesheet can have a different system identifier from its parent instruction. However,
25
     * SAX parsers only provide location information at the element level, so when part of an XPath expression
26
     * is in a different external entity from other parts of the same expression, this distinction is lost.
27
     *
28
     * <p>The system identifier of a node is in general not the same as its base URI. The base URI is affected
29
     * by xml:base attributes; the system identifier is not.</p>
30
     *
31
     * @return the system ID, or null if the information is not available.
32
     */
33

  
34
    String getSystemId();
35

  
36
    /**
37
     * Get the Public ID
38
     *
39
     * @return usually null
40
     */
41

  
42
    String getPublicId();
43

  
44
    /**
45
     * Get the line number. This line number is relative to the external entity identified by the system identifier.
46
     * Line numbers start at 1. The value may be an approximation; SAX parsers only provide line number information
47
     * at the level of element nodes.
48
     *
49
     * @return the line number, or -1 if the information is not available.
50
     */
51

  
52
    int getLineNumber();
53

  
54
    /**
55
     * Get the column number. This column number is relative to the line identified by the line number.
56
     * Column numbers start at 1.
57
     *
58
     * @return the column number, or -1 if the information is not available.
59
     */
60

  
61
    int getColumnNumber();
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff