1
|
/**
|
2
|
* ====================================================================
|
3
|
* About
|
4
|
* ====================================================================
|
5
|
* Sarissa cross browser XML library - IE XPath Emulation
|
6
|
* @version 0.9.7.6
|
7
|
* @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
|
8
|
*
|
9
|
* This script emulates Internet Explorer's selectNodes and selectSingleNode
|
10
|
* for Mozilla. Associating namespace prefixes with URIs for your XPath queries
|
11
|
* is easy with IE's setProperty.
|
12
|
* USers may also map a namespace prefix to a default (unprefixed) namespace in the
|
13
|
* source document with Sarissa.setXpathNamespaces
|
14
|
*
|
15
|
*
|
16
|
* ====================================================================
|
17
|
* Licence
|
18
|
* ====================================================================
|
19
|
* Sarissa is free software distributed under the GNU GPL version 2 (see <a href="gpl.txt">gpl.txt</a>) or higher,
|
20
|
* GNU LGPL version 2.1 (see <a href="lgpl.txt">lgpl.txt</a>) or higher and Apache Software License 2.0 or higher
|
21
|
* (see <a href="asl.txt">asl.txt</a>). This means you can choose one of the three and use that if you like. If
|
22
|
* you make modifications under the ASL, i would appreciate it if you submitted those.
|
23
|
* In case your copy of Sarissa does not include the license texts, you may find
|
24
|
* them online in various formats at <a href="http://www.gnu.org">http://www.gnu.org</a> and
|
25
|
* <a href="http://www.apache.org">http://www.apache.org</a>.
|
26
|
*
|
27
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
28
|
* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
29
|
* WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE
|
30
|
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
31
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
32
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
33
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
34
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
35
|
*/
|
36
|
if(_SARISSA_HAS_DOM_FEATURE && document.implementation.hasFeature("XPath", "3.0")){
|
37
|
/**
|
38
|
* <p>SarissaNodeList behaves as a NodeList but is only used as a result to <code>selectNodes</code>,
|
39
|
* so it also has some properties IEs proprietery object features.</p>
|
40
|
* @private
|
41
|
* @constructor
|
42
|
* @argument i the (initial) list size
|
43
|
*/
|
44
|
function SarissaNodeList(i){
|
45
|
this.length = i;
|
46
|
};
|
47
|
/** <p>Set an Array as the prototype object</p> */
|
48
|
SarissaNodeList.prototype = new Array(0);
|
49
|
/** <p>Inherit the Array constructor </p> */
|
50
|
SarissaNodeList.prototype.constructor = Array;
|
51
|
/**
|
52
|
* <p>Returns the node at the specified index or null if the given index
|
53
|
* is greater than the list size or less than zero </p>
|
54
|
* <p><b>Note</b> that in ECMAScript you can also use the square-bracket
|
55
|
* array notation instead of calling <code>item</code>
|
56
|
* @argument i the index of the member to return
|
57
|
* @returns the member corresponding to the given index
|
58
|
*/
|
59
|
SarissaNodeList.prototype.item = function(i) {
|
60
|
return (i < 0 || i >= this.length)?null:this[i];
|
61
|
};
|
62
|
/**
|
63
|
* <p>Emulate IE's expr property
|
64
|
* (Here the SarissaNodeList object is given as the result of selectNodes).</p>
|
65
|
* @returns the XPath expression passed to selectNodes that resulted in
|
66
|
* this SarissaNodeList
|
67
|
*/
|
68
|
SarissaNodeList.prototype.expr = "";
|
69
|
/** dummy, used to accept IE's stuff without throwing errors */
|
70
|
if(window.XMLDocument && (!XMLDocument.prototype.setProperty)){
|
71
|
XMLDocument.prototype.setProperty = function(x,y){};
|
72
|
};
|
73
|
/**
|
74
|
* <p>Programmatically control namespace URI/prefix mappings for XPath
|
75
|
* queries.</p>
|
76
|
* <p>This method comes especially handy when used to apply XPath queries
|
77
|
* on XML documents with a default namespace, as there is no other way
|
78
|
* of mapping that to a prefix.</p>
|
79
|
* <p>Using no namespace prefix in DOM Level 3 XPath queries, implies you
|
80
|
* are looking for elements in the null namespace. If you need to look
|
81
|
* for nodes in the default namespace, you need to map a prefix to it
|
82
|
* first like:</p>
|
83
|
* <pre>Sarissa.setXpathNamespaces(oDoc, "xmlns:myprefix=&aposhttp://mynsURI&apos");</pre>
|
84
|
* <p><b>Note 1 </b>: Use this method only if the source document features
|
85
|
* a default namespace (without a prefix), otherwise just use IE's setProperty
|
86
|
* (moz will rezolve non-default namespaces by itself). You will need to map that
|
87
|
* namespace to a prefix for queries to work.</p>
|
88
|
* <p><b>Note 2 </b>: This method calls IE's setProperty method to set the
|
89
|
* appropriate namespace-prefix mappings, so you dont have to do that.</p>
|
90
|
* @param oDoc The target XMLDocument to set the namespace mappings for.
|
91
|
* @param sNsSet A whilespace-seperated list of namespace declarations as
|
92
|
* those would appear in an XML document. E.g.:
|
93
|
* <code>"xmlns:xhtml='http://www.w3.org/1999/xhtml'
|
94
|
* xmlns:'http://www.w3.org/1999/XSL/Transform'"</code>
|
95
|
* @throws An error if the format of the given namespace declarations is bad.
|
96
|
*/
|
97
|
Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
|
98
|
//oDoc._sarissa_setXpathNamespaces(sNsSet);
|
99
|
oDoc._sarissa_useCustomResolver = true;
|
100
|
var namespaces = sNsSet.indexOf(" ")>-1?sNsSet.split(" "):new Array(sNsSet);
|
101
|
oDoc._sarissa_xpathNamespaces = new Array(namespaces.length);
|
102
|
for(var i=0;i < namespaces.length;i++){
|
103
|
var ns = namespaces[i];
|
104
|
var colonPos = ns.indexOf(":");
|
105
|
var assignPos = ns.indexOf("=");
|
106
|
if(colonPos > 0 && assignPos > colonPos+1){
|
107
|
var prefix = ns.substring(colonPos+1, assignPos);
|
108
|
var uri = ns.substring(assignPos+2, ns.length-1);
|
109
|
oDoc._sarissa_xpathNamespaces[prefix] = uri;
|
110
|
}else{
|
111
|
throw "Bad format on namespace declaration(s) given";
|
112
|
};
|
113
|
};
|
114
|
};
|
115
|
/**
|
116
|
* @private Flag to control whether a custom namespace resolver should
|
117
|
* be used, set to true by Sarissa.setXpathNamespaces
|
118
|
*/
|
119
|
XMLDocument.prototype._sarissa_useCustomResolver = false;
|
120
|
/** @private */
|
121
|
XMLDocument.prototype._sarissa_xpathNamespaces = new Array();
|
122
|
/**
|
123
|
* <p>Extends the XMLDocument to emulate IE's selectNodes.</p>
|
124
|
* @argument sExpr the XPath expression to use
|
125
|
* @argument contextNode this is for internal use only by the same
|
126
|
* method when called on Elements
|
127
|
* @returns the result of the XPath search as a SarissaNodeList
|
128
|
* @throws An error if no namespace URI is found for the given prefix.
|
129
|
*/
|
130
|
XMLDocument.prototype.selectNodes = function(sExpr, contextNode, returnSingle){
|
131
|
var nsDoc = this;
|
132
|
var nsresolver = this._sarissa_useCustomResolver
|
133
|
? function(prefix){
|
134
|
var s = nsDoc._sarissa_xpathNamespaces[prefix];
|
135
|
if(s)return s;
|
136
|
else throw "No namespace URI found for prefix: '" + prefix+"'";
|
137
|
}
|
138
|
: this.createNSResolver(this.documentElement);
|
139
|
var result = null;
|
140
|
if(!returnSingle){
|
141
|
var oResult = this.evaluate(sExpr,
|
142
|
(contextNode?contextNode:this),
|
143
|
nsresolver,
|
144
|
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
145
|
var nodeList = new SarissaNodeList(oResult.snapshotLength);
|
146
|
nodeList.expr = sExpr;
|
147
|
for(var i=0;i<nodeList.length;i++)
|
148
|
nodeList[i] = oResult.snapshotItem(i);
|
149
|
result = nodeList;
|
150
|
}
|
151
|
else {
|
152
|
result = oResult = this.evaluate(sExpr,
|
153
|
(contextNode?contextNode:this),
|
154
|
nsresolver,
|
155
|
XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
156
|
};
|
157
|
return result;
|
158
|
};
|
159
|
/**
|
160
|
* <p>Extends the Element to emulate IE's selectNodes</p>
|
161
|
* @argument sExpr the XPath expression to use
|
162
|
* @returns the result of the XPath search as an (Sarissa)NodeList
|
163
|
* @throws An
|
164
|
* error if invoked on an HTML Element as this is only be
|
165
|
* available to XML Elements.
|
166
|
*/
|
167
|
Element.prototype.selectNodes = function(sExpr){
|
168
|
var doc = this.ownerDocument;
|
169
|
if(doc.selectNodes)
|
170
|
return doc.selectNodes(sExpr, this);
|
171
|
else
|
172
|
throw "Method selectNodes is only supported by XML Elements";
|
173
|
};
|
174
|
/**
|
175
|
* <p>Extends the XMLDocument to emulate IE's selectSingleNode.</p>
|
176
|
* @argument sExpr the XPath expression to use
|
177
|
* @argument contextNode this is for internal use only by the same
|
178
|
* method when called on Elements
|
179
|
* @returns the result of the XPath search as an (Sarissa)NodeList
|
180
|
*/
|
181
|
XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode){
|
182
|
var ctx = contextNode?contextNode:null;
|
183
|
return this.selectNodes(sExpr, ctx, true);
|
184
|
};
|
185
|
/**
|
186
|
* <p>Extends the Element to emulate IE's selectSingleNode.</p>
|
187
|
* @argument sExpr the XPath expression to use
|
188
|
* @returns the result of the XPath search as an (Sarissa)NodeList
|
189
|
* @throws An error if invoked on an HTML Element as this is only be
|
190
|
* available to XML Elements.
|
191
|
*/
|
192
|
Element.prototype.selectSingleNode = function(sExpr){
|
193
|
var doc = this.ownerDocument;
|
194
|
if(doc.selectSingleNode)
|
195
|
return doc.selectSingleNode(sExpr, this);
|
196
|
else
|
197
|
throw "Method selectNodes is only supported by XML Elements";
|
198
|
};
|
199
|
Sarissa.IS_ENABLED_SELECT_NODES = true;
|
200
|
};
|