OSDN Git Service

Verison 0.6.198, add jsdoc commnets.
[pettanr/clientJs.git] / 0.6.x / js / 05_util / 04_XXML.js
1 /*\r
2  * XMLWrapper_find 周りの オリジナルコードに関する情報\r
3  *  Original code by pettanR team\r
4  *  - https://osdn.jp/projects/pettanr/scm/git/clientJs/blobs/master/0.6.x/js/02_dom/08_XNodeSelector.js\r
5  *  and\r
6  *  Original code by ofk ( kQuery, ksk )\r
7  *  - http://d.hatena.ne.jp/ofk/comment/20090106/1231258010\r
8  *  - http://d.hatena.ne.jp/ofk/20090111/1231668170\r
9  * \r
10  * TODO X.Class で作り、kill を強要する\r
11  */\r
12 X[ 'XML' ] = XMLWrapper;\r
13 \r
14 /**\r
15  * XML 探索用のラッパークラスです\r
16  * @alias X.XML\r
17  * @class XML 探索用のラッパークラスです\r
18  * @constructor\r
19  * @param {XMLElement}\r
20  */\r
21 function XMLWrapper( xml ){\r
22         this._rawXML = xml;\r
23 };\r
24 \r
25 /**\r
26  * ラップした xml の数 常に1または0, XMLList の場合2以上\r
27  * @alias X.XML.prototype.length\r
28  * @type {Number}\r
29  */\r
30 XMLWrapper.prototype.length      = 1;\r
31 XMLWrapper.prototype[ 'parent' ] = XMLWrapper_parent;\r
32 XMLWrapper.prototype[ 'has' ]    = XMLWrapper_has;\r
33 XMLWrapper.prototype[ 'get' ]    = XMLWrapper_get;\r
34 XMLWrapper.prototype[ 'val' ]    = XMLWrapper_val;\r
35 XMLWrapper.prototype[ 'find' ]   = XMLWrapper_find;\r
36 \r
37 /**\r
38  * 親要素を返す、ルート要素の場合 null を返す\r
39  * @alias X.XML.prototype.parent\r
40  * @return {X.XML} 親要素\r
41  */\r
42 function XMLWrapper_parent(){\r
43         if( this.length === 1 ) return this._rawXML && this._rawXML.parentNode ? new XMLWrapper( this._rawXML.parentNode ) : null;\r
44         if( this.length === 0 ) return null;\r
45         \r
46         return this[ 0 ].parentNode ? ( new XMLWrapper( this[ 0 ].parentNode ) ) : null;\r
47 };\r
48 \r
49 /**\r
50  * セレクターにヒットした要素数を返す\r
51  * @alias X.XML.prototype.has\r
52  * @param {string} queryString XML セレクター文字列\r
53  * @return {number}\r
54  */\r
55 function XMLWrapper_has( queryString ){\r
56         return !!this.find( queryString ).length;\r
57 };\r
58 \r
59 /**\r
60  * <p>X.XML では常に自信を返す\r
61  * <p>X.XMLList ではラップした xml 群から index のものを返す\r
62  * @alias X.XML.prototype.get\r
63  * @param {number} index\r
64  * @return {X.XML} X.XML では自身、X.XMLList では index の X.XML\r
65  */\r
66 function XMLWrapper_get( index ){\r
67         if( this.length === 1 ) return this;\r
68         if( this.length === 0 ) return null;\r
69         // 一度発行した XMLWrapper は控えて置いて再発行する。\r
70         if( this._wraps && this._wraps[ index ] ) return this._wraps[ index ];\r
71         if( !this._wraps ) this._wraps = [];\r
72         return this[ index ] ?\r
73                 ( this._wraps[ index ] = new XMLWrapper( this[ index ] ) ) :\r
74                 null;\r
75 };\r
76 \r
77 /**\r
78  * セレクターにヒットした要素の内容を指定されたデータ型で返す。複数要素にヒットした場合、0番目の要素の内容を使用する。\r
79  * @alias X.XML.prototype.val\r
80  * @param {string} queryString XML セレクター文字列\r
81  * @param {string} type 'number','int','boolean','string'\r
82  * @return {boolean|number|string} 内容を型変換した値\r
83  */\r
84 function XMLWrapper_val( queryString, type ){\r
85         var //attr_textContent = X_UA[ 'IE' ] < 9 || X_UA[ 'Opera' ] ? 'innerText' : X_UA[ 'IE9' ] ? 'text' : 'textContent',\r
86                 wrapper, xml, v;\r
87         \r
88         switch( queryString ){\r
89                 case 'number' :\r
90                 case 'int' :\r
91                 case 'boolean' :\r
92                 case 'string' :\r
93                 case undefined :\r
94                         type = queryString;\r
95                         queryString = 0;\r
96         };\r
97                 \r
98         wrapper = queryString ? this.find( queryString ) : this;\r
99         xml     = wrapper.length === 1 ? wrapper._rawXML : wrapper[ 0 ];\r
100 \r
101         if( !xml ){\r
102                 switch( type ){\r
103                         case 'number' :\r
104                         case 'int' :\r
105                                 return NaN;\r
106                         case 'boolean' :\r
107                                 return false;\r
108                         case 'string' :\r
109                                 return '';\r
110                         default :\r
111                                 return null;\r
112                 };\r
113         };\r
114         \r
115         v = xml.nodeType === 1 ? xml.innerText || xml.text || xml.textContent : xml.nodeValue;\r
116         //xml.toStrign()\r
117         switch( type ){\r
118                 case 'number' :\r
119                         return parseFloat( v );\r
120                 case 'int' :\r
121                         return parseFloat( v ) | 0;\r
122                 case 'boolean' :\r
123                         return !!X_String_parse( v );\r
124                 //case 'string' :\r
125                 //default :     \r
126         };\r
127         return v || '';\r
128 };\r
129 \r
130 /**\r
131  * セレクターにヒットした要素を返す。0~1個の要素がヒットした場合は X.XML を、それ以上の場合は X.XMLList を返す。\r
132  * @alias X.XML.prototype.find\r
133  * @param {string} queryString セレクター文字列\r
134  * @return {X.XML|X.XMLList} \r
135  */\r
136         function XMLWrapper_find( queryString ){\r
137 \r
138                 var scope     = this.constructor === XMLListWrapper ? this : [ this._rawXML ],\r
139                         parents   = scope, // 探索元の親要素 xmlList の場合あり\r
140                         ARY_PUSH  = Array.prototype.push,\r
141                         ret       = [], // 結果要素\r
142                         isXML     = true,\r
143                         isMulti   = 1 < scope.length,// 要素をマージする必要がある\r
144                         isStart   = true,\r
145                         _         = ' ',\r
146                         isAll, isNot, hasRoot,\r
147                         l, i, n, parsed,\r
148                         xmlList, // 一時保存用\r
149                         merge, // 要素がコメントノードで汚染されている場合使う\r
150                         combinator, selector, name, tagName,\r
151                         uid, tmp, xml, filter, key, op, val, toLower, useName,\r
152             links, className, attr, flag;\r
153 \r
154                 // 文字列以外は空で返す\r
155                 if( !X_Type_isString( queryString ) ) return XMLListWrapper_0;\r
156                 \r
157                 xmlList = [];\r
158                 \r
159                 // 以下、パースと探索\r
160                 for( ; queryString.length; ){\r
161                         //console.log( 'queryString[' + queryString + ']' );\r
162                         \r
163                         // 初期化処理\r
164                         if( !parsed ){\r
165                                 parsed = X_Node_Selector__parse( queryString );\r
166                                 \r
167                                 if( X_Type_isNumber( parsed ) ){\r
168                                         // error\r
169                                         return XMLListWrapper_0;\r
170                                 };\r
171                                 \r
172                                 queryString = queryString.substr( parsed[ 0 ] );\r
173                                 parsed      = parsed[ 1 ];\r
174                                 \r
175                                 if( parsed === 5 ){\r
176                                         isMulti = true;\r
177                                         parents = scope;\r
178                                         xmlList && xmlList.length && ARY_PUSH.apply( ret, xmlList );\r
179                                         parsed  = null;\r
180                                         xmlList = [];\r
181                                         isStart = true;\r
182                                         continue;\r
183                                 };\r
184                         };\r
185                         \r
186                         combinator  = parsed[ 0 ];\r
187                         selector    = parsed[ 1 ];\r
188                         name        = parsed[ 2 ];\r
189                         tagName     = selector === 1 ? name : '*';\r
190                         isAll       = tagName === '*';\r
191         \r
192                         if( !isStart ){\r
193                                 if( !xmlList.length ){\r
194                                         parsed = null;\r
195                                         continue;                                       \r
196                                 } else\r
197                                 if( combinator !== 0 ){\r
198                                         parents = xmlList;\r
199                                         xmlList = [];\r
200                                         //console.log( 'cobinator !== 0 ' + parents.length + ' : ' + xmlList.length );\r
201                                 };\r
202                         };\r
203                         \r
204                         i = 0;\r
205                         l = parents.length;\r
206                         n = -1; \r
207                         isMulti = isMulti || 1 < l;\r
208                         \r
209                         //console.log( 'combinator ' + combinator );\r
210         \r
211                         switch( combinator ){\r
212                                 // > TagName|*\r
213                                 case 2 :\r
214                                         for( ; i < l; ++i ){\r
215                                                 for( xml = parents[ i ].firstChild; xml; xml = xml.nextSibling ){\r
216                                                         if( xml.nodeType === 1 && ( isAll || tagName === xml.tagName ) ) xmlList[ ++n ] = xml;\r
217                                                 };                              \r
218                                         };\r
219                                         break;\r
220                                 // + TagName|*\r
221                                 case 3 :\r
222                                         for( ; i < l; ++i ){\r
223                                                 for( xml = parents[ i ].nextSibling; xml; xml = xml.nextSibling ){\r
224                                                         if( xml.nodeType === 1 ){\r
225                                                                 if( isAll || tagName === xml.tagName ) xmlList[ ++n ] = xml;\r
226                                                                 break;                                                          \r
227                                                         };\r
228                                                 };                                                              \r
229                                         };\r
230                                         break;\r
231                                 // ~ TagName|*\r
232                                 case 4 :\r
233                                         merge = [];\r
234                                         for( ; i < l; ++i ){\r
235                                                 for( xml = parents[ i ].nextSibling; xml; xml = xml.nextSibling ){\r
236                                                         if( xml.nodeType === 1 && ( isAll || tagName === xml.tagName ) ){\r
237                                                                 if( merge.indexOf( xml ) !== -1 ){\r
238                                                                         break;\r
239                                                                 } else {\r
240                                                                         merge[ merge.length ] = xml;\r
241                                                                         xmlList[ ++n ] = xml;\r
242                                                                 };\r
243                                                         };                                                                      \r
244                                                 };                                                              \r
245                                         };\r
246                                         break;\r
247 \r
248                                 // @ 属性ノード\r
249                                 case 6 :\r
250                                         selector = 0;\r
251                                         tagName  = '*';\r
252                                         for( ; i < l; ++i ){\r
253                                                 if( xml = parents[ i ].getAttributeNode( name ) ){\r
254                                                         xmlList[ ++n ] = xml;\r
255                                                 };\r
256                                         };\r
257                                         break;\r
258                                 default :\r
259                                         if( combinator === 1 || ( isStart && selector < 7 ) ){\r
260                                                 //console.log( l + ' > ' + xmlList.length + ' tag:' + tagName );\r
261                                                 for( ; i < l; ++i ){\r
262                                                         xml = parents[ i ];\r
263                                                         xml.childNodes && xml.childNodes.length && XMLWrapper_fetchElements( xmlList, xml, isAll ? null : tagName );\r
264                                                 };\r
265                                                 //console.log( l + ' >> ' + xmlList.length + ' tag:' + tagName );\r
266                                         };\r
267                         };\r
268                         \r
269                         isStart = false;\r
270                         \r
271                         //alert( 'pre-selector:' + ( xmlList && xmlList.length ) )\r
272                         \r
273                         switch( selector ){\r
274                                 // #, ID\r
275                                 case 2 :\r
276                                         filter = [ 'id', 1, name ]; break;\r
277                                 // ., class\r
278                                 case 3 :\r
279                                         filter = [ 'class', 3 /*'~='*/, name ]; break;\r
280                                 // :, 擬似クラス\r
281                                 case 4 :\r
282                                         if( !( filter = XMLWrapper_filter[ name ] ) ){\r
283                                                 return XMLListWrapper_0;\r
284                                         };\r
285                                         break;\r
286                                 // [] 属性\r
287                                 case 5 :\r
288                                         filter = [ name, parsed[ 3 ], parsed[ 4 ] ]; break;\r
289                                 // :not\r
290                                 case 6 :\r
291                                         isNot  = true;\r
292                                         parsed = parsed[ 2 ];\r
293                                         name   = parsed[ 2 ];\r
294                                         switch( parsed[ 1 ] ) {\r
295                                                 case 1 :\r
296                                                         filter = [ 'tag', 1, name ]; break;\r
297                                                 // #, ID\r
298                                                 case 2 :\r
299                                                         filter = [ 'id', 1, name ]; break;\r
300                                                 // ., class\r
301                                                 case 3 :\r
302                                                         filter = [ 'class', 3, name ]; break;\r
303                                                 // :, 擬似クラス\r
304                                                 case 4 :\r
305                                                         if( !( filter = XMLWrapper_filter[ name ] ) ){\r
306                                                                 return [];\r
307                                                         };\r
308                                                         break;\r
309                                                 // [] 属性\r
310                                                 case 5 :\r
311                                                         filter = [ name, parsed[ 3 ], parsed[ 4 ] ]; break;\r
312                                         };\r
313                                         break;\r
314                                 // scope\r
315                                 case 7 :\r
316                                         xmlList = scope; break;\r
317                                 /* root\r
318                                 case 8 :\r
319                                         hasRoot = true;\r
320                                         xmlList = [ HTML ]; break;\r
321                                 // link\r
322                                 case 9 :\r
323                                         if( links = document.links ){\r
324                                                 for( xmlList = [], i = links.length; i; ){\r
325                                                         xmlList[ --i ] = new Node( links[ i ] );\r
326                                                 };\r
327                                         } else {\r
328                                                 // area[href],a[href]\r
329                                         }; */\r
330                         };\r
331                         \r
332                         if( filter && xmlList.length ){\r
333                                 // filter.mが関数の場合\r
334                                 if( filter.m ){\r
335                                         xmlList = filter.m(\r
336                                                 {\r
337                                                         not : isNot,\r
338                                                         xml : isXML\r
339                                                 },\r
340                                                 xmlList,\r
341                                                 parsed[ 3 ], parsed[ 4 ]\r
342                                         );\r
343                                 } else\r
344                                 // filterが関数の場合\r
345                                 if( X_Type_isFunction( filter ) ){\r
346                                         tmp = [];\r
347                                         for( i = 0, n = -1; xml = xmlList[ i ]; ++i ){\r
348                                                 if( ( !!filter( xml ) ) ^ isNot ) tmp[ ++n ] = xml;     \r
349                                         };\r
350                                         xmlList = tmp;\r
351                                 } else {\r
352                                 // 属性セレクター                        \r
353                                         tmp = [];\r
354                                         key = filter[ 0 ];\r
355                                         op  = filter[ 1 ];\r
356                                         val = filter[ 2 ];\r
357 \r
358                                         // 通常\r
359                                                 if( op === 3 ) val = _ + val + _;\r
360 \r
361                                                 for( i = 0, n = -1, l = xmlList.length; i < l; ++i ){\r
362                                                         xml  = xmlList[ i ];\r
363                                                         attr = xml.getAttribute( key, 2 );\r
364                                                         flag = attr != null;// && ( !useName || attr !== '' );\r
365                                                         if( flag && op ){\r
366                                                                 //if( toLower ) attr = attr.toLowerCase();\r
367                                                                 \r
368                                                                 switch( op ){\r
369                                                                         case 1: // =\r
370                                                                                 flag = attr === val;\r
371                                                                                 break;\r
372                                                                         case 2: // !=\r
373                                                                                 flag = attr !== val;\r
374                                                                                 break;\r
375                                                                         case 3: // ~=\r
376                                                                                 flag = ( _ + attr + _ ).indexOf( val ) !== -1;\r
377                                                                                 break;\r
378                                                                         case 4: // ^=\r
379                                                                                 flag = attr.indexOf( val ) === 0;\r
380                                                                                 break;\r
381                                                                         case 5: // $=\r
382                                                                                 flag = attr.lastIndexOf( val ) + val.length === attr.length;\r
383                                                                                 break;\r
384                                                                         case 6: // *=\r
385                                                                                 flag = attr.indexOf( val ) !== -1;\r
386                                                                                 break;\r
387                                                                         case 7: // |=\r
388                                                                                 flag = attr === val || attr.substring( 0, val.length + 1 ) === val + '-';\r
389                                                                                 break;\r
390                                                                 };\r
391                                                         };\r
392                                                         if( !!flag ^ isNot ) tmp[ ++n ] = xml;\r
393                                                 //};\r
394                                         };\r
395                                         xmlList = tmp;\r
396                                 };\r
397                         };\r
398                         filter  = null;\r
399                         isNot   = false;\r
400                         parsed  = null;\r
401                         \r
402                         //console.log( '//end :' + ( xmlList && xmlList.length ) );\r
403                 };\r
404                 //console.log( 'multi:' + ( xmlList && xmlList.length ) );\r
405                 \r
406                 // tree 順に並び替え、同一要素の排除\r
407                 if( isMulti ){\r
408                         xmlList && xmlList.length && ARY_PUSH.apply( ret, xmlList );\r
409                         l = ret.length;\r
410                         if( l === 0 ) return XMLListWrapper_0;\r
411                         if( l === 1 ) return new XMLWrapper( ret[ 0 ] );\r
412                         \r
413                         xmlList = [];\r
414                         //merge   = [];\r
415                         for( i = 0, n = -1; i < l; ++i ){\r
416                                 //alert( 'multi:' + i )\r
417                                 xml = ret[ i ];\r
418                                 if( xmlList.indexOf( xml ) === -1 ){\r
419                                         //merge[ merge.length ] = xml;\r
420                                         xmlList[ ++n ] = xml;\r
421                                 };\r
422                         };\r
423                         XMLWrapper_sortElementOrder( ret = [], xmlList, this._rawXML.childNodes );\r
424                         \r
425                         // @\r
426                         for( i = 0, l = xmlList.length; i < l; ++i ){\r
427                                 if( ret.indexOf( xml = xmlList[ i ] ) === -1 ){\r
428                                         ret[ ret.length ] = xml;\r
429                                 };\r
430                         };\r
431                         \r
432                         xmlList = ret;\r
433                 };\r
434 \r
435                 return xmlList.length === 1 ? new XMLWrapper( xmlList[ 0 ] ) : new XMLListWrapper( xmlList );\r
436         };\r
437 \r
438         function XMLWrapper_sortElementOrder( newList, list, xmlList ){\r
439                 var l = xmlList.length,\r
440                         i = 0,\r
441                         j, child, _xmlList;\r
442                 for( ; i < l; ++i ){\r
443                         child = xmlList[ i ];\r
444                         //if( child.nodeType !== 1 ) continue;\r
445                         //console.log( child.tagName );\r
446                         if( ( j = list.indexOf( child ) ) !== -1 ){\r
447                                 newList[ newList.length ] = child;\r
448                                 list.splice( j, 1 );\r
449                                 if( list.length === 1 ){\r
450                                         newList[ newList.length ] = list[ 0 ];\r
451                                         list.length = 0;\r
452                                         return true;\r
453                                 };\r
454                                 if( list.length === 0 ) return true;\r
455                         };\r
456                         if( ( _xmlList = child.childNodes ) && XMLWrapper_sortElementOrder( newList, list, _xmlList ) ){\r
457                                 return true;\r
458                         };\r
459                 };\r
460         };\r
461         \r
462         function XMLWrapper_fetchElements( list, parent, tag ){\r
463                 var xmlList = parent.childNodes,\r
464                         l      = xmlList.length,\r
465                         i      = 0,\r
466                         child;\r
467                 for( ; i < l; ++i ){\r
468                         child = xmlList[ i ];\r
469                         if( child.nodeType === 1 ){\r
470                                 ( !tag || child.tagName === tag ) && ( list[ list.length ] = child );\r
471                                 //console.log( parent.tagName + ' > ' + child.tagName + ' == ' + tag+ ' l:' + list.length );\r
472                                 child.childNodes && child.childNodes.length && XMLWrapper_fetchElements( list, child, tag );\r
473                         };\r
474                 };\r
475         };\r
476 \r
477         function XMLWrapper_funcSelectorChild( type, flag_all, flags, xmlList ){\r
478                 var res      = [],\r
479                         flag_not = flags.not,\r
480                         i = 0, n = -1, xml, node,\r
481                         tagName, tmp;\r
482                 for( ; xml = xmlList[ i ]; ++i ){\r
483                         tagName = flag_all || xml.tagName;\r
484                         tmp     = null;\r
485                         if( /* tmp === null && */ type <= 0 ){\r
486                                 for( node = xml.previousSibling; node; node = node.previousSibling ){\r
487                                         if( node.nodeType === 1 && ( flag_all || tagName === node.tagName ) ){\r
488                                                 tmp = false;\r
489                                                 break;\r
490                                         };\r
491                                 };\r
492                         };\r
493                         if( tmp === null && 0 <= type ){\r
494                                 for( node = xml.nextSibling; node; node = node.nextSibling ){\r
495                                         if( node.nodeType === 1 && ( flag_all || tagName === node.tagName ) ){\r
496                                                 tmp = false;\r
497                                                 break;\r
498                                         };              \r
499                                 };                                              \r
500                         };\r
501                         if( tmp === null ) tmp = true;\r
502                         if( tmp ^ flag_not ) res[ ++n ] = xml;\r
503                 };\r
504                 return res;\r
505         };\r
506         function XMLWrapper_funcSelectorNth( pointer, sibling, flag_all, flags, xmlList, a, b ){\r
507                 var uids     = X_Array_copy( xmlList ),\r
508                         res      = [],\r
509                         checked  = {},\r
510                         flag_not = flags.not,\r
511                         i = 0, n = -1,\r
512                         c, xml, tmp, node, tagName, uid;\r
513 \r
514                 for( ; xml = xmlList[ i ]; ++i ){\r
515                         tmp = checked[ i ];\r
516                         if( tmp === undefined ){\r
517                                 for( c = 0, node = xml.parentNode[ pointer ], tagName = flag_all || xml.tagName; node; node = node[ sibling ] ){\r
518                                         if( node.nodeType === 1 && ( flag_all || tagName === node.tagName ) ){\r
519                                                 ++c;\r
520                                                 uid = uids.indexOf( node );\r
521                                                 if( uid === -1 ) uids[ uid = uids.length ] = node;\r
522                                                 checked[ uid ] = a === 0 ? c === b : (c - b) % a === 0 && (c - b) / a >= 0;\r
523                                         };\r
524                                 };\r
525                                 tmp = checked[ i ];\r
526                         };\r
527                         if( tmp ^ flag_not ) res[ ++n ] = xml;\r
528                 };\r
529                 return res;\r
530         };\r
531         /*\r
532         function XMLWrapper_funcSelectorProp( prop, flag, flags, xmlList ){\r
533                 var res = [],\r
534                         flag_not = flag ? flags.not : !flags.not,\r
535                         i = 0, n = -1, xml;\r
536                 for( ; xml = xmlList[ i ]; ++i ){\r
537                         if( xml.getAttributeNode( prop ) ^ flag_not ) res[ ++n ] = xml;\r
538                 };\r
539                 return res;\r
540         }; */\r
541 \r
542 var XMLWrapper_filter = {\r
543         'first-child' : {\r
544                 m : function( flags, xmlList ){ return XMLWrapper_funcSelectorChild( -1, true, flags, xmlList ); }\r
545         },\r
546         'last-child' : {\r
547                 m : function( flags, xmlList ){ return XMLWrapper_funcSelectorChild( 1, true, flags, xmlList ); }\r
548         },\r
549         'only-child' : {\r
550                 m : function( flags, xmlList ){ return XMLWrapper_funcSelectorChild( 0, true, flags, xmlList ); }\r
551         },\r
552         'first-of-type' : {\r
553                 m : function( flags, xmlList ){ return XMLWrapper_funcSelectorChild( -1, false, flags, xmlList ); }\r
554         },\r
555         'last-of-type' : {\r
556                 m : function( flags, xmlList ){ return XMLWrapper_funcSelectorChild( 1, false, flags, xmlList ); }\r
557         },\r
558         'only-of-type' : {\r
559                 m : function( flags, xmlList ){ return XMLWrapper_funcSelectorChild( 0, false, flags, xmlList ); }\r
560         },\r
561         'nth-child' : {\r
562                 m : function( flags, xmlList, a, b ){ return XMLWrapper_funcSelectorNth( 'firstChild', 'nextSibling', true, flags, xmlList, a, b ); }\r
563         },\r
564         'nth-last-child' : {\r
565                 m : function( flags, xmlList, a, b ){ return XMLWrapper_funcSelectorNth( 'lastChild', 'previousSibling', true, flags, xmlList, a, b ); }\r
566         },\r
567         'nth-of-type' : {\r
568                 m : function( flags, xmlList, a, b ){ return XMLWrapper_funcSelectorNth( 'firstChild', 'nextSibling', false, flags, xmlList, a, b ); }\r
569         },\r
570         'nth-last-of-type' : {\r
571                 m : function( flags, xmlList, a, b ){ return XMLWrapper_funcSelectorNth( 'lastChild', 'previousSibling', false, flags, xmlList, a, b ); }\r
572         },\r
573         'empty' : {\r
574                 m : function( flags, xmlList ){\r
575                         var res = [],\r
576                                 flag_not = flags.not,\r
577                                 i = 0, n = -1, xml, tmp, node;\r
578                         for( ; xml = xmlList[i]; ++i ){\r
579                                 tmp = true;\r
580                                 for( node = xml.firstChild; node; node = node.nextSibling ){\r
581                                         if( node.nodeType === 1 || ( node.nodeType === 3 && node.nodeValue ) ){\r
582                                                 tmp = false;\r
583                                                 break;\r
584                                         };                              \r
585                                 };\r
586                                 if( tmp ^ flag_not ) res[ ++n ] = xml;\r
587                         };\r
588                         return res;\r
589                 }\r
590         },\r
591         'contains' : {\r
592                 m : function( flags, xmlList, arg ){\r
593                         var res = [],\r
594                                 flag_not = flags.not,\r
595                                 i = 0, n = -1, xml, text = '';\r
596 \r
597                         for( ; xml = xmlList[ i ]; ++i ){\r
598                                 switch( xml.nodeType ){\r
599                                         case 1 :\r
600                                                 text = xml.innerText || xml.text || xml.textContent;\r
601                                                 break;\r
602                                         //case 2 :\r
603                                         case 3 :\r
604                                                 text = xml.nodeValue;\r
605                                                 break;\r
606                                 };\r
607                                 if ( ( -1 < text.indexOf( arg ) ) ^ flag_not ) res[ ++n ] = xml;                \r
608                         };\r
609                         return res;\r
610                 }\r
611         }\r
612 };\r
613 \r
614 /**\r
615  * XML配列を扱う XML 探索用のラッパークラスです\r
616  * @alias X.XMLList\r
617  * @class XMLList XML配列を扱う XML 探索用のラッパークラスです\r
618  * @constructor\r
619  * @extends {X.XML}\r
620  */\r
621 function XMLListWrapper( xmlList ){\r
622         var i = 0, l = xmlList ? xmlList.length : 0;\r
623         for( ; i < l; ++i ){\r
624                 this[ i ] = xmlList[ i ];\r
625         };\r
626         this.length = l;\r
627 };\r
628 \r
629 var XMLListWrapper_0 = new XMLListWrapper();\r
630 \r
631 XMLListWrapper.prototype.length      = 0;\r
632 XMLListWrapper.prototype._wraps      = null;\r
633 XMLListWrapper.prototype[ 'parent' ] = XMLWrapper_parent;\r
634 XMLListWrapper.prototype[ 'has' ]    = XMLWrapper_has;\r
635 XMLListWrapper.prototype[ 'get' ]    = XMLWrapper_get;\r
636 XMLListWrapper.prototype[ 'val' ]    = XMLWrapper_val;\r
637 XMLListWrapper.prototype[ 'find' ]   = XMLWrapper_find;\r