summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkanzure <kanzure@gmail.com>2009-07-24 22:38:12 -0500
committerkanzure <kanzure@gmail.com>2009-07-24 22:38:12 -0500
commita6ad5d5b9a68a531a8454980cd9f94dd44d73fd4 (patch)
treef79d31eeba2d5a64764f7aa2a008ccbff7c69b8b
parentb97e7974b963e968ba932e23bd845af737f40da9 (diff)
downloadpyscholar-a6ad5d5b9a68a531a8454980cd9f94dd44d73fd4.tar.gz
pyscholar-a6ad5d5b9a68a531a8454980cd9f94dd44d73fd4.zip
BSXPath added
-rwxr-xr-xBSXPath_ver001e/BSXPath.py2692
-rw-r--r--BSXPath_ver001e/BSXPath.pycbin0 -> 90518 bytes
-rw-r--r--BSXPath_ver001e/TEST_BSXPath.py368
-rw-r--r--BSXPath_ver001e/ex.html11
-rw-r--r--BSXPath_ver001e/testbsx.cmd11
-rw-r--r--BSXPath_ver001e/testbsxresult/r0000.txt200
-rw-r--r--BSXPath_ver001e/testbsxresult/r0001.txt515
-rw-r--r--BSXPath_ver001e/testbsxresult/r0002.txt587
-rw-r--r--BSXPath_ver001e/testbsxresult/r0003.txt88
-rw-r--r--BSXPath_ver001e/testbsxresult/r0004.txt53
-rw-r--r--BSXPath_ver001e/testbsxresult/r0005.txt494
-rw-r--r--BSXPath_ver001e/testbsxresult/r0006.txt172
-rw-r--r--BSXPath_ver001e/testbsxresult/r0007.txt116
-rw-r--r--BSXPath_ver001e/testbsxresult/r0008.txt116
-rw-r--r--BSXPath_ver001e/testbsxresult/r0009.txt102
-rw-r--r--BSXPath_ver001e/testbsxresult/r0010.txt32
-rw-r--r--BSXPath_ver001e/testbsxresult/r0011.txt46
-rw-r--r--BSXPath_ver001e/testbsxresult/r0012.txt46
18 files changed, 5649 insertions, 0 deletions
diff --git a/BSXPath_ver001e/BSXPath.py b/BSXPath_ver001e/BSXPath.py
new file mode 100755
index 0000000..a55e587
--- /dev/null
+++ b/BSXPath_ver001e/BSXPath.py
@@ -0,0 +1,2692 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+BSXPath.py: XPathEvaluator Extension for BeautifulSoup
+
+"""
+__version__ = '0.01e' # based on JavaScript-XPath 0.1.11 (c) 2007 Cybozu Labs, Inc. (http://coderepos.org/share/wiki/JavaScript-XPath)
+__date__ = '2009-04-12'
+__license__ = 'MIT-style license'
+__author__ = 'furyu' # http://furyu.tea-nifty.com/annex/
+ # http://d.hatena.ne.jp/furyu-tei/
+"""
+Usage:
+ from BSXPath import BSXPathEvaluator,XPathResult
+
+ #*** PREPARATION (create object)
+ document = BSXPathEvaluator(<html>) # BSXPathEvaluator is sub-class of BeautifulSoup
+ # html: HTML (text string)
+
+ #*** BASIC OPERATIONS
+ result = document.evaluate(<expression>,<node>,None,<type>,None)
+ # expression: XPath expression
+ # node : base context-node(document is document-root)
+ # type : XPathResult.<name>
+ # name : ANY_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, UNORDERED_NODE_ITERATOR_TYPE, ORDERED_NODE_ITERATOR_TYPE
+ # UNORDERED_NODE_SNAPSHOT_TYPE, ORDERED_NODE_SNAPSHOT_TYPE, ANY_UNORDERED_NODE_TYPE, FIRST_ORDERED_NODE_TYPE
+ # (*) 3rd(resolver) and 5th(result) arguments are not implemented
+ length = result.snapshotLength
+ node = result.snapshotItem(<number>)
+
+ #*** USEFUL WRAPPER-FUNCTIONS
+ nodes = document.getItemList(<expression>[,<node>])
+ first = document.getFirstItem(<expression>[,<node>])
+ # expression: XPath expression
+ # node(optional): base context-node(default: document(document-root))
+
+
+Examples:
+ from BSXPath import BSXPathEvaluator,XPathResult
+
+ html = '<html><head><title>Hello, DOM 3 XPath!</title></head><body><h1>Hello, DOM 3 XPath!</h1><p>This is XPathEvaluator Extension for BeautifulSoup.</p><p>This is based on JavaScript-XPath!</p></body>'
+
+ document = BSXPathEvaluator(html)
+
+ result = document.evaluate('//h1/text()[1]',document,None,XPathResult.STRING_TYPE,None)
+ print result.stringValue
+ # Hello, DOM 3 XPath!
+
+ result = document.evaluate('//h1',document,None,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,None)
+ print result.snapshotLength
+ # 1
+ print result.snapshotItem(0)
+ # <h1>Hello, DOM 3 XPath!</h1>
+
+ nodes = document.getItemList('//p')
+ print len(nodes)
+ # 2
+ print nodes
+ # [<p>This is XPathEvaluator Extension for BeautifulSoup.</p>, <p>This is based on JavaScript-XPath!</p>]
+
+ first = document.getFirstItem('//p')
+ print first
+ # <p>This is XPathEvaluator Extension for BeautifulSoup.</p>
+
+
+Notice:
+ - This is based on JavaScript-XPath (c) 2007 Cybozu Labs, Inc. (http://coderepos.org/share/wiki/JavaScript-XPath)
+ - Required:
+ - Python 2.5+
+ - BeautifulSoup 3.0.7+(recommended) or 3.1.0+
+
+"""
+import re,types,math,datetime
+#import logging
+from BeautifulSoup import *
+
+try:
+ if DEFAULT_OUTPUT_ENCODING:
+ pass
+except:
+ DEFAULT_OUTPUT_ENCODING='utf-8'
+
+
+#***** Optional Parameters
+USE_NODE_CACHE=True
+USE_NODE_INDEX=True
+
+
+#***** General Functions
+def throwError(str):
+ raise ValueError, str
+
+
+def typeof(obj):
+ if isinstance(obj,bool):
+ return 'boolean'
+ if isinstance(obj,int) or isinstance(obj,float):
+ return 'number'
+ if isinstance(obj,basestring):
+ return 'string'
+ if isinstance(obj,types.FunctionType):
+ return 'function'
+ return 'object'
+
+
+def isNaN(obj):
+ if isinstance(obj,int) or isinstance(obj,float):
+ return False
+ if not isinstance(obj,basestring):
+ return True
+ if obj.isdigit():
+ return False
+ try:
+ float(obj)
+ return False
+ except:
+ return True
+
+
+def toNumber(obj):
+ if isinstance(obj,int) or isinstance(obj,float):
+ return obj
+ if isinstance(obj,basestring):
+ if obj.isdigit():
+ return int(obj)
+ try:
+ return float(obj)
+ except:
+ return obj
+ return obj
+
+def toBoolean(obj):
+ return bool(obj)
+
+
+def toString(obj):
+ if isinstance(obj,bool):
+ return u'true' if obj else u'false'
+ if isinstance(obj,str) or isinstance(obj,int) or isinstance(obj,float):
+ return unicode(obj)
+ return obj
+
+
+
+#***** General Classes
+class ExtDict(dict):
+ def __getattr__(self,name):
+ try:
+ attr=super(ExtDict,self).__getattr__(name)
+ except:
+ if not self.has_key(name):
+ raise AttributeError,name
+ attr=self.get(name)
+ return attr
+
+
+
+#***** Common Definitions
+indent_space=' '
+
+
+#{ // Regular Expressions
+re_has_ualpha=re.compile(r'(?![0-9])[\w]')
+re_seqspace=re.compile(r'\s+')
+re_firstspace=re.compile(r'^\s')
+re_lastspace=re.compile(r'\s$')
+#} // end of Regular Expressions
+
+
+#{ // NodeTypeDOM
+NodeTypeDOM=ExtDict({
+ 'ANY_NODE' :0
+, 'ELEMENT_NODE' :1
+, 'ATTRIBUTE_NODE' :2
+, 'TEXT_NODE' :3
+, 'CDATA_SECTION_NODE' :4
+, 'ENTITY_REFERENCE_NODE' :5
+, 'ENTITY_NODE' :6
+, 'PROCESSING_INSTRUCTION_NODE':7
+, 'COMMENT_NODE' :8
+, 'DOCUMENT_NODE' :9
+, 'DOCUMENT_TYPE_NODE' :10
+, 'DOCUMENT_FRAGMENT_NODE' :11
+, 'NOTATION_NODE' :12
+})
+
+NodeTypeBS=ExtDict({
+ 'BSXPathEvaluator' :NodeTypeDOM.DOCUMENT_NODE
+, 'NavigableString' :NodeTypeDOM.TEXT_NODE
+, 'CData' :NodeTypeDOM.CDATA_SECTION_NODE
+, 'ProcessingInstruction':NodeTypeDOM.PROCESSING_INSTRUCTION_NODE
+, 'Comment' :NodeTypeDOM.COMMENT_NODE
+, 'Declaration' :NodeTypeDOM.ANY_NODE
+, 'Tag' :NodeTypeDOM.ELEMENT_NODE
+})
+#} // end of NodeTypeDOM
+
+
+#{ // NodeUtil
+def makeNodeUtils():
+ re_type_document_type=re.compile(r'^DOCTYPE\s')
+ re_type_entity =re.compile(r'^ENTITY\s')
+ re_type_notation =re.compile(r'^NOTATION\s')
+
+ #re_processing_instruction=re.compile(r'^(.*?)\s+(.*?)\?*$')
+ re_processing_instruction=re.compile(r'^(.*?)(\s+.*?)\?*$')
+
+ re_declaration_name=re.compile(r'^([^\s]+)\s+([\%]?)\s*([^\s]+)\s')
+
+ def makeNU_BS():
+ def _nodeType(node):
+ if getattr(node,'nodeType',None)==NodeTypeDOM.ATTRIBUTE_NODE:
+ return node.nodeType
+ nodeType=NodeTypeBS.get(node.__class__.__name__)
+ if nodeType==NodeTypeDOM.ANY_NODE:
+ str=NavigableString.encode(node,DEFAULT_OUTPUT_ENCODING)
+ if re_type_document_type.search(str):
+ nodeType=NodeTypeDOM.DOCUMENT_TYPE_NODE
+ elif re_type_entity.search(str):
+ nodeType=NodeTypeDOM.ENTITY_NODE
+ elif re_type_notation.search(str):
+ nodeType=NodeTypeDOM.NOTATION_NODE
+ return nodeType
+
+ def _nodeName(node):
+ if getattr(node,'nodeType',None)==NodeTypeDOM.ATTRIBUTE_NODE:
+ return node.nodeName.lower()
+ nodeType=_nodeType(node)
+ if nodeType==NodeTypeDOM.DOCUMENT_NODE:
+ return '#document'
+ elif nodeType==NodeTypeDOM.TEXT_NODE:
+ return '#text'
+ elif nodeType==NodeTypeDOM.CDATA_SECTION_NODE:
+ return '#cdata-section'
+ elif nodeType==NodeTypeDOM.PROCESSING_INSTRUCTION_NODE:
+ mrslt=re_processing_instruction.search(NavigableString.encode(node,DEFAULT_OUTPUT_ENCODING))
+ if mrslt:
+ return mrslt.group(1)
+ else:
+ return NavigableString.encode(node,DEFAULT_OUTPUT_ENCODING)
+ elif nodeType==NodeTypeDOM.COMMENT_NODE:
+ return '#comment'
+ elif nodeType==NodeTypeDOM.DOCUMENT_TYPE_NODE or nodeType==NodeTypeDOM.ENTITY_NODE or nodeType==NodeTypeDOM.NOTATION_NODE:
+ mrslt=re_declaration_name.search(NavigableString.encode(node,DEFAULT_OUTPUT_ENCODING))
+ if mrslt:
+ return mrslt.group(2)
+ else:
+ return NavigableString.encode(node,DEFAULT_OUTPUT_ENCODING)
+ else:
+ return node.name.lower()
+
+ def _nodeValue(node):
+ if getattr(node,'nodeType',None)==NodeTypeDOM.ATTRIBUTE_NODE:
+ return node.nodeValue
+ nodeType=_nodeType(node)
+ if nodeType==NodeTypeDOM.CDATA_SECTION_NODE or \
+ nodeType==NodeTypeDOM.COMMENT_NODE or \
+ nodeType==NodeTypeDOM.TEXT_NODE:
+ return NavigableString.encode(node, DEFAULT_OUTPUT_ENCODING)
+ if nodeType==NodeTypeDOM.PROCESSING_INSTRUCTION_NODE:
+ mrslt=re_processing_instruction.search(NavigableString.encode(node,DEFAULT_OUTPUT_ENCODING))
+ if mrslt:
+ return mrslt.group(2)
+ else:
+ return None
+ return None
+
+ def _nodeAttrValue(node,attrName):
+ if getattr(node,'nodeType',None)==NodeTypeDOM.ATTRIBUTE_NODE:
+ return None
+ nodeType=_nodeType(node)
+ if nodeType!=NodeTypeDOM.ELEMENT_NODE:
+ return None
+ return node.get(attrName)
+
+ def _parentNode(node):
+ if getattr(node,'nodeType',None)==NodeTypeDOM.ATTRIBUTE_NODE:
+ return node.parentNode
+ return node.parent
+
+ def _ownerDocument(node):
+ owner=getattr(node,'_owner',None)
+ if owner:
+ return owner
+ if getattr(node,'nodeType',None)==NodeTypeDOM.ATTRIBUTE_NODE:
+ owner=node.parentNode
+ else:
+ owner=node
+ while True:
+ parent=owner.parent
+ if not parent:
+ break
+ owner=parent
+ try:
+ node._owner=owner
+ except:
+ pass
+ return owner
+
+ def pairwise(iterable):
+ itnext = iter(iterable).next
+ while True:
+ yield itnext(), itnext()
+
+ def _attributes(node):
+ if _nodeType(node)==NodeTypeDOM.ELEMENT_NODE:
+ #return node._getAttrMap()
+ if not getattr(node,'attrMap'):
+ node.attrMap=dict(pairwise(node.attrs))
+ return node.attrMap
+ else:
+ return None
+
+ def _contains(node,cnode):
+ if _nodeType(node)==NodeTypeDOM.ATTRIBUTE_NODE: node=node.parentNode
+ if _nodeType(cnode)==NodeTypeDOM.ATTRIBUTE_NODE: cnode=cnode.parentNode
+ return node in cnode.findParents()
+
+ def _preceding(node,cnode):
+ if _nodeType(node)==NodeTypeDOM.ATTRIBUTE_NODE: node=node.parentNode
+ if _nodeType(cnode)==NodeTypeDOM.ATTRIBUTE_NODE: cnode=cnode.parentNode
+ #return cnode in node.findAllPrevious()
+ return cnode in node.findPreviousSiblings()
+
+ def _following(node,cnode):
+ if _nodeType(node)==NodeTypeDOM.ATTRIBUTE_NODE: node=node.parentNode
+ if _nodeType(cnode)==NodeTypeDOM.ATTRIBUTE_NODE: cnode=cnode.parentNode
+ #return cnode in node.findAllNext()
+ return cnode in node.findNextSiblings()
+
+ def d_getattr(self,name):
+ raise AttributeError,name
+
+ #{ // ExtPageElement
+ class ExtPageElement:
+ def __getattr__(self,name):
+ if name=='nodeType': return _nodeType(self)
+ if name=='nodeName': return _nodeName(self)
+ if name=='nodeValue': return _nodeValue(self)
+ if name=='parentNode': return _parentNode(self)
+ if name=='ownerDocument': return _ownerDocument(self)
+ if name=='attributes': return _attributes(self)
+ if name=='get': return self.get
+ if name=='contains': return self.contains
+ if name=='preceding': return self.preceding
+ if name=='following': return self.following
+ d_getattr(self,name)
+
+ def get(self,key,default=None):
+ return _nodeAttrValue(self,key)
+
+ def contains(self,cnode):
+ return _contains(self,cnode)
+
+ def preceding(self,cnode):
+ return _preceding(self,cnode)
+
+ def following(self,cnode):
+ return _following(self,cnode)
+
+ PageElement.__bases__+=(ExtPageElement,)
+ BeautifulSoup.__bases__+=(ExtPageElement,)
+ NavigableString.__bases__+=(ExtPageElement,)
+ CData.__bases__+=(ExtPageElement,)
+ ProcessingInstruction.__bases__+=(ExtPageElement,)
+ Comment.__bases__+=(ExtPageElement,)
+ Declaration.__bases__+=(ExtPageElement,)
+ Tag.__bases__+=(ExtPageElement,)
+
+ #} // ExtPageElement
+
+ #{ // _extBeautifulSoup
+ def _extBeautifulSoup():
+ o_getattr=getattr(BeautifulSoup,'__getattr__',d_getattr)
+ def e_getattr(self,name):
+ if name=='nodeType': return NodeTypeDOM.DOCUMENT_NODE
+ if name=='nodeName': return '#document'
+ if name=='nodeValue': return None
+ if name=='parentNode': return None
+ if name=='ownerDocument': return None
+ if name=='attributes': return None
+ return o_getattr(self,name)
+ BeautifulSoup.__getattr__=e_getattr
+ _extBeautifulSoup()
+ #} // _extBeautifulSoup
+
+ #{ // _extNavigableString
+ def _extNavigableString():
+ o_getattr=getattr(NavigableString,'__getattr__',d_getattr)
+ def e_getattr(self,name):
+ if name=='nodeType': return NodeTypeDOM.TEXT_NODE
+ if name=='nodeName': return '#text'
+ if name=='nodeValue': return NavigableString.encode(self,DEFAULT_OUTPUT_ENCODING)
+ if name=='parentNode': return self.parent
+ if name=='ownerDocument': return _ownerDocument(self)
+ if name=='attributes': return None
+ return o_getattr(self,name)
+ NavigableString.__getattr__=e_getattr
+ _extNavigableString()
+ #} // _extNavigableString
+
+ #{ // _extCData
+ def _extCData():
+ o_getattr=getattr(CData,'__getattr__',d_getattr)
+ def e_getattr(self,name):
+ if name=='nodeType': return NodeTypeDOM.CDATA_SECTION_NODE
+ if name=='nodeName': return '#cdata-section'
+ if name=='nodeValue': return NavigableString.encode(self,DEFAULT_OUTPUT_ENCODING)
+ if name=='parentNode': return self.parent
+ if name=='ownerDocument': return _ownerDocument(self)
+ if name=='attributes': return None
+ return o_getattr(self,name)
+ CData.__getattr__=e_getattr
+ _extCData()
+ #} // _extCData
+
+ #{ // _extProcessingInstruction
+ def _extProcessingInstruction():
+ o_getattr=getattr(ProcessingInstruction,'__getattr__',d_getattr)
+ def e_getattr(self,name):
+ if name=='nodeType': return NodeTypeDOM.PROCESSING_INSTRUCTION_NODE
+ if name=='nodeName':
+ mrslt=re_processing_instruction.search(NavigableString.encode(self,DEFAULT_OUTPUT_ENCODING))
+ return mrslt.group(1) if mrslt else NavigableString.encode(self,DEFAULT_OUTPUT_ENCODING)
+ if name=='nodeValue':
+ mrslt=re_processing_instruction.search(NavigableString.encode(self,DEFAULT_OUTPUT_ENCODING))
+ return mrslt.group(2) if mrslt else None
+ if name=='parentNode': return self.parent
+ if name=='ownerDocument': return _ownerDocument(self)
+ if name=='attributes': return None
+ return o_getattr(self,name)
+ ProcessingInstruction.__getattr__=e_getattr
+ _extProcessingInstruction()
+ #} // _extProcessingInstruction
+
+ #{ // _extComment
+ def _extComment():
+ o_getattr=getattr(Comment,'__getattr__',d_getattr)
+ def e_getattr(self,name):
+ if name=='nodeType': return NodeTypeDOM.COMMENT_NODE
+ if name=='nodeName': return '#comment'
+ if name=='nodeValue': return NavigableString.encode(self, DEFAULT_OUTPUT_ENCODING)
+ if name=='parentNode': return self.parent
+ if name=='ownerDocument': return _ownerDocument(self)
+ if name=='attributes': return None
+ return o_getattr(self,name)
+ Comment.__getattr__=e_getattr
+ _extComment()
+ #} // _extComment
+
+ #{ // _extDeclaration
+ def _extDeclaration():
+ o_getattr=getattr(Declaration,'__getattr__',d_getattr)
+ def e_getattr(self,name):
+ if name=='nodeType':
+ str=NavigableString.encode(self,DEFAULT_OUTPUT_ENCODING)
+ if re_type_document_type.search(str):
+ return NodeTypeDOM.DOCUMENT_TYPE_NODE
+ elif re_type_entity.search(str):
+ return NodeTypeDOM.ENTITY_NODE
+ elif re_type_notation.search(str):
+ return NodeTypeDOM.NOTATION_NODE
+ else:
+ return NodeTypeDOM.ANY_NODE
+ if name=='nodeName':
+ mrslt=re_declaration_name.search(NavigableString.encode(self,DEFAULT_OUTPUT_ENCODING))
+ return mrslt.group(2) if mrslt else NavigableString.encode(self,DEFAULT_OUTPUT_ENCODING)
+ if name=='nodeValue': return None
+ if name=='parentNode': return self.parent
+ if name=='ownerDocument': return _ownerDocument(self)
+ if name=='attributes': return None
+ return o_getattr(self,name)
+ Declaration.__getattr__=e_getattr
+ _extDeclaration()
+ #} // _extDeclaration
+
+ #{ // _extTag
+ def _extTag():
+ o_getattr=getattr(Tag,'__getattr__',d_getattr)
+ def e_getattr(self,name):
+ if name=='nodeType': return NodeTypeDOM.ELEMENT_NODE
+ if name=='nodeName': return self.name.lower()
+ if name=='nodeValue': return None
+ if name=='parentNode': return self.parent
+ if name=='ownerDocument': return _ownerDocument(self)
+ if name=='attributes': return self._getAttrMap()
+ return o_getattr(self,name)
+ Tag.__getattr__=e_getattr
+ _extTag()
+ #} // _extTag
+
+ def _it_deepNodes(node):
+ child_next=iter(getattr(node,'contents',[])).next
+ while True:
+ child=child_next()
+ yield child
+ for gchild in _it_deepNodes(child):
+ yield gchild
+
+ return ExtDict({
+ 'nodeType' :_nodeType
+ , 'nodeName' :_nodeName
+ , 'nodeValue' :_nodeValue
+ , 'nodeAttrValue':_nodeAttrValue
+ , 'parentNode' :_parentNode
+ , 'ownerDocument':_ownerDocument
+ , 'attributes' :_attributes
+ , 'contains' :_contains
+ , 'preceding' :_preceding
+ , 'following' :_following
+ , 'it_deepNodes' :_it_deepNodes
+ })
+ return
+
+ def makeNU():
+ def _to(valueType,node):
+ if typeof(node)=='string':
+ result=node
+ else:
+ nodeType=node.nodeType
+ if nodeType==NodeTypeDOM.ATTRIBUTE_NODE:
+ result=node.nodeValue
+ else:
+ strings=[]
+ for _node in NodeUtilBS.it_deepNodes(node):
+ if _node.nodeType==NodeTypeDOM.TEXT_NODE:
+ strings.append(unicode(_node))
+ result=''.join(strings)
+
+ if valueType=='number':
+ return toNumber(result)
+ elif valueType=='boolean':
+ return toBoolean(result)
+ else:
+ return result
+
+ def _attrMatch(node,attrName,attrValue):
+ if not attrName or \
+ not attrValue and node.get(attrName) or \
+ (attrValue and node.get(attrName)==attrValue):
+ return True
+ else:
+ return False
+
+ def _getDescendantNodes(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ if prevNodeset:
+ prevNodeset.delDescendant(node,prevIndex)
+
+ if USE_NODE_CACHE:
+ _cachemap=getattr(node,'_cachemap',None)
+ if not _cachemap:
+ _cachemap=node._cachemap=ExtDict({'attrib':ExtDict({}),'all':None,'tag':ExtDict({})})
+
+ if attrValue and attrName:
+ _cm=_cachemap.attrib
+ _anmap=_cm.get(attrName)
+ if not _anmap:
+ _anmap=_cm[attrName]=ExtDict({})
+ nodes=_anmap.get(attrValue)
+ if not nodes:
+ nodes=_anmap[attrValue]=[]
+ if getattr(node,'findAll',None):
+ nodes.extend(node.findAll(attrs={attrName:attrValue}))
+ for elm in nodes:
+ if test.match(elm):
+ nodeset.push(elm)
+
+ elif getattr(test,'notOnlyElement',None):
+ nodes=_cachemap.all
+ if not nodes:
+ nodes=_cachemap.all=[]
+ for elm in NodeUtilBS.it_deepNodes(node):
+ nodes.append(elm)
+
+ for elm in nodes:
+ if NodeUtil.attrMatch(elm,attrName,attrValue) and test.match(elm):
+ nodeset.push(elm)
+
+ else:
+ nodeType=node.nodeType
+ if nodeType==NodeTypeDOM.ELEMENT_NODE or nodeType==NodeTypeDOM.DOCUMENT_NODE:
+ _cm=_cachemap.tag
+ name=getattr(test,'name',None)
+ if not name or name=='*':
+ nodes=_cm.get('*')
+ if not nodes:
+ nodes=_cm['*']=node.findAll()
+ else:
+ nodes=_cm.get(name)
+ if not nodes:
+ nodes=_cm[name]=node.findAll([name])
+ for elm in nodes:
+ if NodeUtil.attrMatch(elm,attrName,attrValue):
+ nodeset.push(elm)
+
+ else: # USE_NODE_CACHE is False
+ if attrValue and attrName:
+ if getattr(node,'findAll',None):
+ for elm in node.findAll(attrs={attrName:attrValue}):
+ if test.match(elm):
+ nodeset.push(elm)
+
+ elif getattr(test,'notOnlyElement',None):
+ for elm in NodeUtilBS.it_deepNodes(node):
+ if NodeUtil.attrMatch(elm,attrName,attrValue) and test.match(elm):
+ nodeset.push(elm)
+
+ else:
+ nodeType=node.nodeType
+ if nodeType==NodeTypeDOM.ELEMENT_NODE or nodeType==NodeTypeDOM.DOCUMENT_NODE:
+ name=getattr(test,'name',None)
+ if not name or name=='*':
+ nodes=node.findAll()
+ else:
+ nodes=node.findAll([name])
+ for elm in nodes:
+ if NodeUtil.attrMatch(elm,attrName,attrValue):
+ nodeset.push(elm)
+
+ return nodeset
+
+ def _getChildNodes(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ contents=getattr(node,'contents',[])
+ for elm in contents:
+ if NodeUtil.attrMatch(elm,attrName,attrValue) and test.match(elm):
+ nodeset.push(elm)
+
+ return nodeset
+
+ return ExtDict({
+ 'to' :_to
+ , 'attrMatch' :_attrMatch
+ , 'getDescendantNodes':_getDescendantNodes
+ , 'getChildNodes' :_getChildNodes
+ })
+
+ return (makeNU_BS(),makeNU())
+
+(NodeUtilBS,NodeUtil)=makeNodeUtils()
+
+#} // end of NodeUtil
+
+
+
+#***** Application Classes
+#{ // Lexer
+class Lexer(object):
+ def __init__(self,source):
+ tokens=self.tokens=[]
+ def anlz_token(mrslt):
+ token=mrslt.group()
+ if not self.re_strip.search(token):
+ tokens.append(token)
+ return token
+ self.re_token.sub(anlz_token,source,count=0)
+ self.index=0
+
+ def peek(self,i=0):
+ token=self.tokens[self.index+i] if self.index+i<len(self.tokens) else None
+ return token
+
+ def next(self):
+ token=self.tokens[self.index] if self.index<len(self.tokens) else None
+ self.index+=1
+ return token
+
+ def back(self):
+ self.index-=1
+ token=self.tokens[self.index] if self.index<len(self.tokens) else None
+
+ def empty(self):
+ return (len(self.tokens)<=self.index)
+
+ re_token=re.compile(r'\$?(?:(?![0-9-])[\w-]+:)?(?![0-9-])[\w-]+|\/\/|\.\.|::|\d+(?:\.\d*)?|\.\d+|"[^"]*"|\'[^\']*\'|[!<>]=|(?![0-9-])[\w-]+:\*|\s+|.')
+ re_strip=re.compile(r'^\s')
+
+#} // end of Lexer
+
+
+#{ // Ctx
+class Ctx(object):
+ def __init__(self,node,position=1,last=1):
+ self.node=node
+ self.position=position
+ self.last=last
+
+#} // end of Ctx
+
+
+#{ // AttributeWrapper
+class AttributeWrapper(object):
+ def __init__(self,name,value,parent):
+ self.nodeType=NodeTypeDOM.ATTRIBUTE_NODE
+ self.nodeName=name
+ self.nodeValue=value
+ self.parentNode=parent
+ self.ownerElement=parent
+
+ def get(self,key,default=None):
+ return None
+
+ def contains(self,cnode):
+ return NodeUtilBS.contains(self,cnode)
+
+ def preceding(self,cnode):
+ return NodeUtilBS.preceding(self,cnode)
+
+ def following(self,cnode):
+ return NodeUtilBS.following(self,cnode)
+
+ def __str__(self,encoding=DEFAULT_OUTPUT_ENCODING):
+ if encoding:
+ return self.nodeValue.encode(encoding)
+ else:
+ return self.nodeValue
+
+ def __unicode__(self):
+ return str(self).decode(DEFAULT_OUTPUT_ENCODING)
+
+ @classmethod
+ def getAttributeWrapper(cls,name,value,parent):
+ _mapattr=getattr(parent,'_mapattr',None)
+ if not _mapattr:
+ _mapattr=parent._mapattr=ExtDict({})
+ if _mapattr.get(name):
+ return _mapattr[name]
+ _mapattr[name]=cls(name,value,parent)
+ return _mapattr[name]
+
+#} // end of AttributeWrapper
+
+
+#{ // BaseExpr
+class BaseExpr(object):
+ def __init__(self):
+ pass
+
+ def number(self,ctx):
+ exrs=self.evaluate(ctx)
+ if getattr(exrs,'isNodeSet',None):
+ result=exrs.number()
+ else:
+ result=toNumber(exrs)
+ return result
+
+ def string(self,ctx):
+ exrs=self.evaluate(ctx)
+ if getattr(exrs,'isNodeSet',None):
+ result=exrs.string()
+ else:
+ result=toString(exrs)
+ return result
+
+ def bool(self,ctx):
+ exrs=self.evaluate(ctx)
+ if getattr(exrs,'isNodeSet',None):
+ result=exrs.bool()
+ else:
+ result=toBoolean(exrs)
+ return result
+
+#} // end of BaseExpr
+
+
+#{ // BaseExprHasPredicates
+class BaseExprHasPredicates(BaseExpr):
+ def __init__(self):
+ pass
+
+ def evaluatePredicates(self,nodeset,start=0):
+ reverse=getattr(self,'reverse',False)
+ predicates=getattr(self,'predicates',[])
+
+ nodeset.sort()
+
+ l0=len(predicates)
+ for i in range(start,l0):
+ predicate=predicates[i]
+ deleteIndexes=[]
+ nodes=nodeset.list()
+
+ l1=len(nodes)
+ for j in range(0,l1):
+ position=(l1-j) if reverse else (j+1)
+ exrs=predicate.evaluate(Ctx(nodes[j],position,l1))
+
+ if typeof(exrs)=='number':
+ exrs=(position==exrs)
+ elif typeof(exrs)=='string':
+ exrs=False if exrs=='' else True
+ elif typeof(exrs)=='object':
+ exrs=exrs.bool()
+
+ if not exrs:
+ deleteIndexes.append(j)
+
+ r=range(0,len(deleteIndexes))
+ r.sort(reverse=True)
+ for j in r:
+ nodeset._del(deleteIndexes[j])
+
+ return nodeset
+
+ @classmethod
+ def parsePredicates(cls,lexer,expr):
+ while lexer.peek()=='[':
+ lexer.next()
+ if lexer.empty():
+ throwError(u'missing predicate expr')
+ predicate=BinaryExpr.parse(lexer)
+ expr.predicate(predicate)
+ if lexer.empty():
+ throwError(u'unclosed predicate expr')
+ if lexer.next() != ']':
+ lexer.back()
+ throwError(u'bad token: %s' % (lexer.next()))
+
+#} // end of BaseExprHasPredicates
+
+
+#{ // BinaryExpr
+class BinaryExpr(BaseExpr):
+ def __init__(self,op,left,right):
+ self.op=op
+ self.left=left
+ self.right=right
+ self.dataType=BinaryExpr.ops[op][2]
+ (lneedContextPosition,rneedContextPosition)=(getattr(left,'needContextPosition',None),getattr(right,'needContextPosition',None))
+ (lneedContextNode,rneedContextNode)=(getattr(left,'needContextNode',None),getattr(right,'needContextNode',None))
+ self.needContextPosition=lneedContextPosition or rneedContextPosition
+ self.needContextNode=lneedContextNode or rneedContextNode
+
+ if op=='=':
+ (ldatatype,rdatatype)=(getattr(left,'datatype',None),getattr(right,'datatype',None))
+ (lqattr,rqattr)=(getattr(left,'quickAttr',None),getattr(right,'quickAttr',None))
+
+ if not rneedContextNode and not rneedContextPosition and rdatatype!='nodeset' and rdatatype!='void' and lqattr:
+ self.quickAttr=True
+ self.attrName=left.attrName
+ self.attrValueExpr=right
+ elif not lneedContextNode and not lneedContextPosition and ldatatype!='nodeset' and ldatatype!='void' and rqattr:
+ self.quickAttr=True
+ self.attrName=right.attrName
+ self.attrValueExpr=left
+
+ def evaluate(self,ctx):
+ result=BinaryExpr.ops[self.op][1](self.left,self.right,ctx)
+ return result
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'binary: '+self.op+'\n'
+ indent+=indent_space
+ t+=self.left.show(indent)
+ t+=self.right.show(indent)
+ return t
+
+ # --- Local Functions
+ @staticmethod
+ def _compare(op,comp,left,right,ctx):
+ left=left.evaluate(ctx)
+ right=right.evaluate(ctx)
+
+ if getattr(left,'isNodeSet',None) and getattr(right,'isNodeSet',None):
+ lnodes=left.list()
+ rnodes=right.list()
+ for lnode in lnodes:
+ for rnode in rnodes:
+ if comp(NodeUtil.to('string',lnode),NodeUtil.to('string',rnode)):
+ return True
+ return False
+
+ if getattr(left,'isNodeSet',None) or getattr(right,'isNodeSet',None):
+ if getattr(left,'isNodeSet',None):
+ (nodeset,primitive)=(left,right)
+ else:
+ (nodeset,primitive)=(right,left)
+
+ nodes=nodeset.list()
+ type=typeof(primitive)
+ for node in nodes:
+ if comp(NodeUtil.to(type,node),primitive):
+ return True
+ return False
+
+ if op=='=' or op=='!=':
+ if typeof(left)=='boolean' or typeof(right)=='boolean':
+ return comp(toBoolean(left),toBoolean(right))
+ if typeof(left)=='number' or typeof(right)=='number':
+ return comp(toNumber(left),toNumber(right))
+ return comp(left,right)
+
+ return comp(toNumber(left),toNumber(right))
+
+ def _div(left,right,ctx):
+ l=left.number(ctx)
+ r=right.number(ctx)
+ if typeof(l)!='number' or typeof(r)!='number': return 'NaN'
+ if r==0:
+ sign=int(getattr(left,'op','+')+'1')*int(getattr(right,'op','+')+'1')
+ if l==0: return 'NaN'
+ elif sign<0: return '-Infinity'
+ else: return 'Infinity'
+ n=float(l) / float(r)
+ n1=int(n)
+ return n1 if n1==n else n
+
+ def _mod(left,right,ctx):
+ l=left.number(ctx)
+ r=right.number(ctx)
+ if typeof(l)!='number' or typeof(r)!='number': return 'NaN'
+ if r==0:
+ if l==0: return 'NaN'
+ else: return 0
+ return l % r
+
+ def _mul(left,right,ctx):
+ l=left.number(ctx)
+ r=right.number(ctx)
+ if typeof(l)!='number' or typeof(r)!='number': return 'NaN'
+ n=l * r
+ n1=int(n)
+ return n1 if n1==n else n
+
+ def _add(left,right,ctx):
+ l=left.number(ctx)
+ r=right.number(ctx)
+ if typeof(l)!='number' or typeof(r)!='number': return 'NaN'
+ n=l + r
+ n1=int(n)
+ return n1 if n1==n else n
+
+ def _sub(left,right,ctx):
+ l=left.number(ctx)
+ r=right.number(ctx)
+ if typeof(l)!='number' or typeof(r)!='number': return 'NaN'
+ n=l - r
+ n1=int(n)
+ return n1 if n1==n else n
+
+ def _lt(left,right,ctx):
+ return BinaryExpr._compare('<',(lambda a,b:a<b),left,right,ctx)
+
+ def _gt(left,right,ctx):
+ return BinaryExpr._compare('>',(lambda a,b:a>b),left,right,ctx)
+
+ def _le(left,right,ctx):
+ return BinaryExpr._compare('<=',(lambda a,b:a<=b),left,right,ctx)
+
+ def _ge(left,right,ctx):
+ return BinaryExpr._compare('>=',(lambda a,b:a>=b),left,right,ctx)
+
+ def _eq(left,right,ctx):
+ return BinaryExpr._compare('=',(lambda a,b:a==b),left,right,ctx)
+
+ def _ne(left,right,ctx):
+ return BinaryExpr._compare('!=',(lambda a,b:a!=b),left,right,ctx)
+
+ def _and(left,right,ctx):
+ return left.bool(ctx) & right.bool(ctx)
+
+ def _or(left,right,ctx):
+ return left.bool(ctx) | right.bool(ctx)
+
+ ops=ExtDict({
+ 'div':[6,_div,'number' ]
+ , 'mod':[6,_mod,'number' ]
+ , '*' :[6,_mul,'number' ]
+ , '+' :[5,_add,'number' ]
+ , '-' :[5,_sub,'number' ]
+ , '<' :[4,_lt ,'boolean']
+ , '>' :[4,_gt ,'boolean']
+ , '<=' :[4,_le ,'boolean']
+ , '>=' :[4,_ge ,'boolean']
+ , '=' :[3,_eq ,'boolean']
+ , '!=' :[3,_ne ,'boolean']
+ , 'and':[2,_and,'boolean']
+ , 'or' :[1,_or ,'boolean']
+ })
+
+ @classmethod
+ def parse(cls,lexer):
+ ops=cls.ops
+ stack=[]
+ index=lexer.index
+
+ while True:
+ if lexer.empty():
+ throwError(u'missing right expression')
+ expr=UnaryExpr.parse(lexer)
+
+ op=lexer.next()
+ if not op:
+ break
+
+ info=ops.get(op)
+ precedence=info and info[0]
+ if not precedence:
+ lexer.back()
+ break
+
+ while 0<len(stack) and precedence<=ops[stack[len(stack)-1]][0]:
+ expr=BinaryExpr(stack.pop(),stack.pop(),expr)
+
+ stack.extend([expr,op])
+
+ while 0<len(stack):
+ expr=BinaryExpr(stack.pop(),stack.pop(),expr)
+
+ return expr
+
+#} // end of BinaryExpr
+
+
+#{ // UnaryExpr
+class UnaryExpr(BaseExpr):
+ def __init__(self,op,expr):
+ self.op=op
+ self.expr=expr
+
+ self.needContextPosition=getattr(expr,'needContextPosition',None)
+ self.needContextNode=getattr(expr,'needContextNode',None)
+
+ self.datatype='number'
+
+ def evaluate(self,ctx):
+ result=-self.expr.number(ctx)
+ return result
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'unary: '+self.op+'\n'
+ indent+=indent_space
+ t+=self.expr.show(indent)
+ return t
+
+ ops=ExtDict({
+ '-':1
+ })
+
+ @classmethod
+ def parse(cls,lexer):
+ ops=cls.ops
+ if ops.get(lexer.peek()):
+ return cls(lexer.next(),cls.parse(lexer))
+ else:
+ return UnionExpr.parse(lexer)
+
+#} // end of UnaryExpr
+
+
+#{ // UnionExpr
+class UnionExpr(BaseExpr):
+ def __init__(self):
+ self.paths=[]
+ self.datatype='nodeset'
+
+ def evaluate(self,ctx):
+ paths=self.paths
+ nodeset=NodeSet()
+ for path in paths:
+ exrs=path.evaluate(ctx)
+ if not getattr(exrs,'isNodeSet',None):
+ throwError(u'PathExpr must be nodeset')
+ nodeset.merge(exrs)
+
+ return nodeset
+
+ def path(self,path):
+ self.paths.append(path)
+
+ if getattr(path,'needContextPosition',None):
+ self.needContextPosition=True
+ if getattr(path,'needContextNode',None):
+ self.needContextNode=True
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'union: '+'\n'
+ indent+=indent_space
+ for path in self.paths:
+ t+=path.show(indent)
+ return t
+
+ ops=ExtDict({
+ '|':1
+ })
+
+ @classmethod
+ def parse(cls,lexer):
+ ops=cls.ops
+ expr=PathExpr.parse(lexer)
+ if not ops.get(lexer.peek()):
+ return expr
+
+ union=UnionExpr()
+ union.path(expr)
+
+ while True:
+ if not ops.get(lexer.next()):
+ break
+ if lexer.empty():
+ throwError(u'missing next union location path')
+ union.path(PathExpr.parse(lexer))
+
+ lexer.back()
+ return union
+
+#} // end of UnionExpr
+
+
+#{ // PathExpr
+class PathExpr(BaseExpr):
+ def __init__(self,filter):
+ self.filter=filter
+ self.steps=[]
+ self.datatype=filter.datatype
+ self.needContextPosition=filter.needContextPosition
+ self.needContextNode=filter.needContextNode
+
+ def evaluate(self,ctx):
+ nodeset=self.filter.evaluate(ctx)
+ if not getattr(nodeset,'isNodeSet',None):
+ throwException('Filter nodeset must be nodeset type')
+
+ for _step in self.steps:
+ if nodeset.length<=0:
+ break
+ step=_step[1] # _step=[op,step]
+ reverse=step.reverse
+ iter=nodeset.iterator(reverse)
+ prevNodeset=nodeset
+ nodeset=None
+ needContextPosition=getattr(step,'needContextPosition',None)
+ axis=step.axis
+ if not needContextPosition and axis=='following':
+ node=iter()
+ while True:
+ next=iter()
+ if not next:
+ break
+ if not node.contains(next):
+ break
+ node=next
+
+ nodeset=step.evaluate(Ctx(node))
+
+ elif not needContextPosition and axis=='preceding':
+ node=iter()
+ nodeset=step.evaluate(Ctx(node))
+
+ else:
+ node=iter()
+ j=0
+ nodeset=step.evaluate(Ctx(node),False,prevNodeset,j)
+ while True:
+ node=iter()
+ if not node:
+ break
+ j+=1
+ nodeset.merge(step.evaluate(Ctx(node),False,prevNodeset,j))
+
+ return nodeset
+
+ def step(self,op,step):
+ step.op=op
+ self.steps.append([op,step])
+ self.quickAttr=False
+
+ if len(self.steps)==1:
+ if op=='/' and step.axis=='attribute':
+ test=step.test
+ if not getattr(test,'notOnlyElement',None) and test.name!='*':
+ self.quickAttr=True
+ self.attrName=test.name
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'path: '+'\n'
+ indent+=indent_space
+ t+=indent+'filter:'+'\n'
+ t+=self.filter.show(indent+indent_space)
+ if 0<len(self.steps):
+ t+=indent+'steps:'+'\n'
+ indent+=indent_space
+ for _step in self.steps:
+ t+=indent+'operator: '+step[0]+'\n'
+ t+=_step[1].show(indent) # _step=[op,step]
+ return t
+
+ ops=ExtDict({
+ '//':1
+ , '/': 1
+ })
+
+ @classmethod
+ def parse(cls,lexer):
+ ops=cls.ops
+ if ops.get(lexer.peek()):
+ op=lexer.next()
+ token=lexer.peek()
+
+ if op=='/' and lexer.empty() or (token!='.' and token!='..' and token!='@' and token!='*' and not re_has_ualpha.search(token)):
+ return FilterExpr.root()
+
+ path=PathExpr(FilterExpr.root()) # RootExpr
+
+ if lexer.empty():
+ throwError(u'missing next location step')
+ expr=Step.parse(lexer)
+ path.step(op,expr)
+
+ else:
+ expr=FilterExpr.parse(lexer)
+ if not expr:
+ expr=Step.parse(lexer)
+ path=PathExpr(FilterExpr.context())
+ path.step('/',expr)
+ elif not ops.get(lexer.peek()):
+ return expr
+ else:
+ path=PathExpr(expr)
+
+ while True:
+ if not ops.get(lexer.peek()):
+ break
+ op=lexer.next()
+ if lexer.empty():
+ throwError(u'missing next location step')
+ path.step(op,Step.parse(lexer))
+
+ return path
+
+#} // end of PathExpr
+
+
+#{ // FilterExpr
+class FilterExpr(BaseExprHasPredicates):
+ def __init__(self,primary):
+ self.primary=primary
+ self.predicates=[]
+ self.datatype=primary.datatype
+ self.needContextPosition=primary.needContextPosition
+ self.needContextNode=primary.needContextNode
+
+ def evaluate(self,ctx):
+ nodeset=self.primary.evaluate(ctx)
+ if not getattr(nodeset,'isNodeSet',None):
+ if 0<len(self.predicates):
+ throwError(u'Primary result must be nodeset type if filter have predicate expression')
+ return nodeset
+
+ return self.evaluatePredicates(nodeset)
+
+ def predicate(self,predicate):
+ self.predicates.append(predicate)
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'filter: '+'\n'
+ indent+=indent_space
+ t+=self.primary.show(indent+indent_space)
+ if 0<len(self.predicates):
+ t+=indent+'predicates:'+'\n'
+ indent+=indent_space
+ for predicate in self.predicates:
+ t+=predicate.show(indent)
+ return t
+
+ @classmethod
+ def root(cls):
+ return FunctionCall('root-node')
+
+ @classmethod
+ def context(cls):
+ return FunctionCall('context-node')
+
+ @classmethod
+ def parse(cls,lexer):
+ token=lexer.peek()
+ ch=token[0:1]
+
+ if ch=='$':
+ expr=VariableReference.parse(lexer)
+ elif ch=='(':
+ lexer.next()
+ expr=BinaryExpr.parse(lexer)
+ if lexer.empty():
+ throwError(u'unclosed "("')
+ if lexer.next()!=')':
+ lexer.back()
+ throwError(u'bad token: %s' % (lexer.next()))
+ elif ch=='"' or ch=="'":
+ expr=Literal.parse(lexer)
+ else:
+ if not isNaN(token):
+ expr=Number.parse(lexer)
+ elif NodeType.types.get(token):
+ return None
+ elif re_has_ualpha.search(ch) and lexer.peek(1)=='(':
+ expr=FunctionCall.parse(lexer)
+ else:
+ return None
+
+ if lexer.peek()!='[':
+ return expr
+
+ filter=FilterExpr(expr)
+
+ BaseExprHasPredicates.parsePredicates(lexer,filter)
+
+ return filter
+
+#} // end of FilterExpr
+
+
+#{ // Step
+class Step(BaseExprHasPredicates):
+ def __init__(self,axis,test):
+ self.axis=axis
+ self.reverse=self.axises[axis][0]
+ self.func=self.axises[axis][1]
+ self.test=test
+ self.predicates=[]
+ self._quickAttr=self.axises[axis][2]
+ self.quickAttr=False
+ self.needContextPosition=False
+
+ def evaluate(self,ctx,special=False,prevNodeset=None,prevIndex=None):
+ node=ctx.node
+ reverse=False
+
+ if not special and getattr(self,'op',None)=='//':
+ if not self.needContextPosition and self.axis=='child':
+ if getattr(self,'quickAttr',None):
+ attrValueExpr=getattr(self,'attrValueExpr',None)
+ attrValue=attrValueExpr.string(ctx) if attrValueExpr else None
+ nodeset=NodeUtil.getDescendantNodes(self.test,node,NodeSet(),self.attrName,attrValue,prevNodeset,prevIndex)
+ nodeset=self.evaluatePredicates(nodeset,1)
+ else:
+ nodeset=NodeUtil.getDescendantNodes(self.test,node,NodeSet(),None,None,prevNodeset,prevIndex)
+ nodeset=self.evaluatePredicates(nodeset)
+ else:
+ step=Step('descendant-or-self',NodeType('node'))
+ nodes=step.evaluate(ctx,False,prevNodeset,prevIndex).list()
+ nodeset=None
+ step.op='/'
+ for _node in nodes:
+ if not nodeset:
+ nodeset=self.evaluate(Ctx(_node),True,None,None)
+ else:
+ nodeset.merge(self.evaluate(Ctx(_node),True,None,None))
+ nodeset=nodeset or NodeSet()
+ else:
+ if getattr(self,'needContextPosition',None):
+ prevNodeset=None
+ prevIndex=None
+ if getattr(self,'quickAttr',None):
+ attrValueExpr=getattr(self,'attrValueExpr',None)
+ attrValue=attrValueExpr.string(ctx) if attrValueExpr else None
+ nodeset=self.func(self.test,node,NodeSet(),self.attrName,attrValue,prevNodeset,prevIndex)
+ nodeset=self.evaluatePredicates(nodeset,1)
+ else:
+ nodeset=self.func(self.test,node,NodeSet(),None,None,prevNodeset,prevIndex)
+ nodeset=self.evaluatePredicates(nodeset)
+ if prevNodeset:
+ prevNodeset.doDel()
+
+ return nodeset
+
+ def predicate(self,predicate):
+ self.predicates.append(predicate)
+ datatype=getattr(predicate,'datatype',None)
+ if getattr(predicate,'needContextPosition',None) or datatype=='number' or datatype=='void':
+ self.needContextPosition=True
+
+ if getattr(self,'_quickAttr',None) and len(self.predicates)==1 and getattr(predicate,'quickAttr',None):
+ attrName=predicate.attrName
+ self.attrName=attrName
+ self.attrValueExpr=getattr(predicate,'attrValueExpr',None)
+ self.quickAttr=True
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'step: '+'\n'
+ indent+=indent_space
+ if self.axis:
+ t+=indent+'axis: '+self.axis+'\n'
+ t+=self.test.show(indent)
+ if 0<len(self.predicates):
+ t+=indent+'predicates:'+'\n'
+ indent+=indent_space
+ for predicate in self.predicates:
+ t+=predicate.show(indent)
+ return t
+
+ # --- Local Functions
+ def _ancestor(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ while True:
+ node=node.parentNode
+ if not node:
+ break
+ if prevNodeset and node.nodeType==NodeTypeDOM.ELEMENT_NODE:
+ prevNodeset.reserveDelByNode(node,prevIndex,True)
+ if test.match(node):
+ nodeset.unshift(node)
+ return nodeset
+
+ def _ancestorOrSelf(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ while True:
+ if prevNodeset and node.nodeType==NodeTypeDOM.ELEMENT_NODE:
+ prevNodeset.reserveDelByNode(node,prevIndex,True)
+ if test.match(node):
+ nodeset.unshift(node)
+ node=node.parentNode
+ if not node:
+ break
+ return nodeset
+
+ def _attribute(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ attrs=node.attributes
+ if attrs:
+ if getattr(test,'notOnlyElement',None) and test.type==NodeTypeDOM.ANY_NODE or test.name=='*':
+ for name in attrs.keys():
+ #nodeset.push(AttributeWrapper(name,attrs[name],node))
+ nodeset.push(AttributeWrapper.getAttributeWrapper(name,attrs[name],node))
+ else:
+ attr=attrs.get(test.name)
+ if attr!=None:
+ #nodeset.push(AttributeWrapper(test.name,attr,node))
+ nodeset.push(AttributeWrapper.getAttributeWrapper(test.name,attr,node))
+ return nodeset
+
+ def _child(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ return NodeUtil.getChildNodes(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex)
+
+ def _descendant(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ return NodeUtil.getDescendantNodes(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex)
+
+ def _descendantOrSelf(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ if NodeUtil.attrMatch(node,attrName,attrValue) and test.match(node):
+ nodeset.push(node)
+ return NodeUtil.getDescendantNodes(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex)
+
+ def _following(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ while True:
+ child=node
+ while True:
+ child=child.nextSibling
+ if not child:
+ break
+ if NodeUtil.attrMatch(child,attrName,attrValue) and test.match(child):
+ nodeset.push(child)
+ nodeset=NodeUtil.getDescendantNodes(test,child,nodeset,attrName,attrValue,None,None)
+ node=node.parentNode
+ if not node:
+ break
+ return nodeset
+
+ def _followingSibling(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ while True:
+ node=node.nextSibling
+ if not node:
+ break
+ if prevNodeset and node.nodeType==NodeTypeDOM.ELEMENT_NODE:
+ prevNodeset.reserveDelByNode(node,prevIndex)
+ if test.match(node):
+ nodeset.push(node)
+ return nodeset;
+
+ def _namespace(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ # not implemented
+ return nodeset
+
+ def _parent(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ nodeType=node.nodeType
+ if nodeType==NodeTypeDOM.DOCUMENT_NODE:
+ return nodeset
+ if nodeType==NodeTypeDOM.ATTRIBUTE_NODE:
+ nodeset.push(node.ownerElement)
+ return nodeset
+ node=node.parentNode
+ if test.match(node):
+ nodeset.push(node)
+ return nodeset
+
+ def _preceding(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ parents=[]
+ while True:
+ parents.insert(0,node)
+ node=node.parentNode
+ if not node:
+ break
+
+ for node in parents[1:]:
+ siblings=[]
+ while True:
+ node=node.previousSibling
+ if not node:
+ break
+ siblings.insert(0,node)
+
+ for node in siblings:
+ if NodeUtil.attrMatch(node,attrName,attrValue) and test.match(node):
+ nodeset.push(node)
+ nodeset=NodeUtil.getDescendantNodes(test,node,nodeset,attrName,attrValue,None,None)
+ return nodeset
+
+ def _precedingSibling(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ while True:
+ node=node.previousSibling
+ if not node:
+ break
+ if prevNodeset and node.nodeType==NodeTypeDOM.ELEMENT_NODE:
+ prevNodeset.reserveDelByNode(node,prevIndex,True)
+ if test.match(node):
+ nodeset.unshift(node)
+ return nodeset
+
+ def _self(test,node,nodeset,attrName,attrValue,prevNodeset,prevIndex):
+ if test.match(node):
+ nodeset.push(node)
+ return nodeset
+
+ axises=ExtDict({
+ 'ancestor' :[True ,_ancestor ,False]
+ , 'ancestor-or-self' :[True ,_ancestorOrSelf ,False]
+ , 'attribute' :[False,_attribute ,False]
+ , 'child' :[False,_child,True ,False]
+ , 'descendant' :[False,_descendant ,True ]
+ , 'descendant-or-self':[False,_descendantOrSelf,True ]
+ , 'following' :[False,_following ,True ]
+ , 'following-sibling' :[False,_followingSibling,False]
+ , 'namespace' :[False,_namespace ,False]
+ , 'parent' :[False,_parent ,False]
+ , 'preceding' :[True ,_preceding ,True ]
+ , 'preceding-sibling' :[True ,_precedingSibling,False]
+ , 'self' :[False,_self ,False]
+ })
+
+ @classmethod
+ def _cself(cls):
+ return cls('self',NodeType('node'))
+
+ @classmethod
+ def parent(cls):
+ return cls('parent',NodeType('node'))
+
+ @classmethod
+ def parse(cls,lexer):
+ (parent,_cself,axises)=(cls.parent,cls._cself,cls.axises)
+ if lexer.peek()=='.':
+ step=_cself()
+ lexer.next()
+ elif lexer.peek()=='..':
+ step=parent()
+ lexer.next()
+ else:
+ if lexer.peek()=='@':
+ axis='attribute'
+ lexer.next()
+ if lexer.empty():
+ throwError(u'missing attribute name')
+ else:
+ if lexer.peek(1)=='::':
+ ch=lexer.peek()[0:1]
+ if not re_has_ualpha.search(ch):
+ throwError(u'bad token: %s' % (lexer.next()))
+
+ axis=lexer.next()
+ lexer.next()
+
+ if not axises.get(axis):
+ throwError(u'invalid axis: %s' % (axis))
+
+ if lexer.empty():
+ throwError(u'missing node name')
+ else:
+ axis='child'
+
+ token=lexer.peek()
+ ch=token[0:1]
+ if not re_has_ualpha.search(ch):
+ if token=='*':
+ test=NameTest.parse(lexer)
+ else:
+ throwError(u'bad token: %s' % (lexer.next()))
+ else:
+ if lexer.peek(1)=='(':
+ if not NodeType.types.get(token):
+ throwError(u'invalid node type: %s' % (token))
+ test=NodeType.parse(lexer)
+ else:
+ test=NameTest.parse(lexer)
+ step=Step(axis,test)
+
+ BaseExprHasPredicates.parsePredicates(lexer,step)
+
+ return step
+
+#} // end of Step
+
+
+#{ // NodeType
+class NodeType(BaseExpr):
+ def __init__(self,name,literal=None):
+ self.name=name
+ self.literal=literal
+ self.type=NodeType.typeNums.get(name,NodeType.typeNums.node)
+ self.notOnlyElement=True
+
+ def match(self,node):
+ return self.type==NodeTypeDOM.ANY_NODE or self.type==node.nodeType
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'nodetype: '+toString(self.type)+'\n'
+ if self.literal:
+ indent+=indent_space
+ t+=self.literal.show(indent)
+ return t
+
+ types=ExtDict({
+ 'comment' :1
+ , 'text' :1
+ , 'processing-instruction':1
+ , 'node' :1
+ })
+
+ typeNums=ExtDict({
+ 'comment' :NodeTypeDOM.COMMENT_NODE
+ , 'text' :NodeTypeDOM.TEXT_NODE
+ , 'processing-instruction':NodeTypeDOM.PROCESSING_INSTRUCTION_NODE
+ , 'node' :NodeTypeDOM.ANY_NODE
+ })
+
+ @classmethod
+ def parse(cls,lexer):
+ type=lexer.next()
+ lexer.next()
+ if lexer.empty():
+ throwError(u'bad nodetype')
+ ch=lexer.peek()[0:1]
+ literal=None
+ if ch=='"' or ch=="'":
+ literal=Literal.parse(lexer)
+ if lexer.empty():
+ throwError(u'bad nodetype')
+ if lexer.next()!=')':
+ lexer.back()
+ throwError(u'bad token: %s' % (lexer.next()))
+
+ return cls(type,literal)
+
+#} // end of NodeType
+
+
+#{ // NameTest
+class NameTest(BaseExpr):
+ def __init__(self,name):
+ self.name=name.lower()
+
+ def match(self,node):
+ type=node.nodeType
+ if type==NodeTypeDOM.ELEMENT_NODE or type==NodeTypeDOM.ATTRIBUTE_NODE:
+ if self.name=='*' or self.name==node.nodeName:
+ return True
+ return False
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'nametest: '+self.name+'\n'
+ return t
+
+ @classmethod
+ def parse(cls,lexer):
+ if lexer.peek()!= '*' and lexer.peek(1)==':' and lexer.peek(2)=='*':
+ return cls(lexer.next()+lexer.next()+lexer.next())
+ return cls(lexer.next())
+
+#} // end of NameTest
+
+
+#{ // VariableReference
+class VariableReference(BaseExpr):
+ def __init__(self,name):
+ self.name=name[1:]
+ self.datatype='void'
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'variable: '+self.name+'\n'
+ return t
+
+ @classmethod
+ def parse(cls,lexer):
+ token=lexer.next()
+ if len(token)<2:
+ throwError(u'unnamed variable reference')
+ return cls(token)
+
+#} // end of VariableReference
+
+
+#{ // Literal
+class Literal(BaseExpr):
+ def __init__(self,text):
+ self.text=text[1:-1]
+ self.datatype='string'
+
+ def evaluate(self,ctx):
+ result=self.text
+ return result
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'literal: '+self.text+'\n'
+ return t
+
+ @classmethod
+ def parse(cls,lexer):
+ token=lexer.next()
+ if len(token)<2:
+ throwError(u'unclosed literal string')
+ return cls(token)
+
+#} // end of Literal
+
+
+#{ // Number
+class Number(BaseExpr):
+ def __init__(self,digit):
+ self.digit=toNumber(digit)
+ self.datatype='number'
+
+ def evaluate(self,ctx):
+ result=self.digit
+ return result
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'number: '+toString(self.digit)+'\n'
+ return t
+
+ @classmethod
+ def parse(cls,lexer):
+ return cls(lexer.next())
+
+#} // end of Number
+
+
+#{ // FunctionCall
+class FunctionCall(BaseExpr):
+ def __init__(self,name):
+ info=self.funcs.get(name)
+ if not info:
+ throwError(u'%s is not a function' % (name))
+ self.name=name
+ self.func=info[0]
+ self.args=[]
+ self.datatype=info[1]
+ self.needContextPosition=True if info[2] else False
+ self.needContextNodeInfo=info[3]
+ self.needContextNode=self.needContextNodeInfo[0] if 0<len(self.needContextNodeInfo) else False
+
+ def evaluate(self,ctx):
+ result=self.func(ctx,*self.args)
+ return result
+
+ def arg(self,arg):
+ self.args.append(arg)
+ if getattr(arg,'needContextPosition',None):
+ self.needContextPosition=True
+ args=self.args
+ if getattr(arg,'needContextNode',None):
+ #args.needContextNode=True
+ self.needContextNode=True
+ #self.needContextNode=args.needContextNode or self.needContextNodeInfo[len(args)]
+ if not getattr(self,'needContextNode',None) and len(args)<len(self.needContextNodeInfo):
+ self.needContextNode=self.needContextNodeInfo[len(args)]
+
+ def show(self,indent=''):
+ t=''
+ t+=indent+'function: '+self.name+'\n'
+ indent+=indent_space
+ if 0<len(self.args):
+ t+=indent+'arguments: '+'\n'
+ indent+=indent_space
+ for arg in self.args:
+ t+=arg.show(indent)
+ return t
+
+ # --- Local Functions
+ def _contextNode(self,*arguments):
+ if len(arguments)!=0:
+ throwError(u'Function context-node expects ()')
+ nodeset=NodeSet()
+ nodeset.push(self.node)
+ return nodeset
+
+ def _rootNode(self,*arguments):
+ if len(arguments)!=0:
+ throwError(u'Function root-node expects ()')
+ nodeset=NodeSet()
+ ctxn=self.node
+ if ctxn.nodeType==NodeTypeDOM.DOCUMENT_NODE:
+ nodeset.push(ctxn)
+ else:
+ nodeset.push(ctxn.ownerDocument)
+ return nodeset
+
+ def _last(self,*arguments):
+ if len(arguments)!=0:
+ throwError(u'Function last expects ()')
+ return self.last
+
+ def _position(self,*arguments):
+ if len(arguments)!=0:
+ throwError(u'Function position expects ()')
+ return self.position
+
+ def _count(self,*arguments):
+ if len(arguments)!=1:
+ throwError(u'Function count expects (nodeset)')
+ nodeset=arguments[0].evaluate(self)
+ if not nodeset.isNodeSet:
+ throwError(u'Function count expects (nodeset)')
+ return nodeset.length
+
+ def _id(self,*arguments):
+ if len(arguments)!=1:
+ throwError(u'Function id expects (object)')
+
+ s=arguments[0]
+ ctxn=self.node
+ if ctxn.nodeType==NodeTypeDOM.DOCUMENT_NODE:
+ doc=ctxn
+ else:
+ doc=ctxn.ownerDocument
+
+ s=s.string(self)
+ ids=re_seqspace.split(s)
+ nodeset=NodeSet()
+ for id in ids:
+ for elm in doc.findAll(id=id):
+ nodeset.push(elm)
+ nodeset.isSorted=False
+ return nodeset
+
+ def _localName(self,*arguments):
+ alen=len(arguments)
+ if alen<0 or 1<alen:
+ throwError(u'Function local-name expects (nodeset?)')
+ if alen==0:
+ node=self.node
+ else:
+ nodeset=arguments[0]
+ nodeset=nodeset.evaluate(self)
+ if getattr(nodeset,'isNodeSet',None):
+ node=nodeset.first()
+ return ''+node.nodeName
+
+
+ def _name(self,*arguments):
+ # not implemented
+ return FunctionCall.funcs['local-name'][0](self,*arguments)
+
+ def _namespaceUri(self,*arguments):
+ # not implemented
+ return ''
+
+ def _string(self,*arguments):
+ alen=len(arguments)
+ if alen==0:
+ s=NodeUtil.to('string',self.node)
+ elif alen==1:
+ s=arguments[0]
+ s=s.string(self)
+ else:
+ throwError(u'Function string expects (object?)')
+ return s
+
+ def _concat(self,*arguments):
+ if len(arguments)<2:
+ throwError('Function concat expects (string, string[, ...])')
+ t=''
+ for argument in arguments:
+ t+=argument.string(self)
+ return t
+
+ def _startsWith(self,*arguments):
+ if len(arguments)!=2:
+ throwError('Function starts-with expects (string, string)')
+ (s1,s2)=(arguments[0],arguments[1])
+ s1=s1.string(self)
+ s2=s2.string(self)
+ #if s2 in s1 and s1.index(s2)==0:
+ # return True
+ #else:
+ # return False
+ if s1.find(s2)==0:
+ return True
+ else:
+ return False
+
+ def _contains(self,*arguments):
+ if len(arguments)!=2:
+ throwError('Function contains expects (string, string)')
+ (s1,s2)=(arguments[0],arguments[1])
+ s1=s1.string(self)
+ s2=s2.string(self)
+ #if s2 in s1:
+ # return True
+ #else:
+ # return False
+ n=s1.find(s2)
+ if n<0:
+ return False
+ else:
+ return True
+
+ def _substring(self,*arguments):
+ alen=len(arguments)
+ if alen<2 or 3<alen:
+ throwError(u'Function substring expects (string, string)')
+ (s,n1)=(arguments[0],arguments[1])
+ s=s.string(self)
+ n1=n1.number(self)
+ if alen==2:
+ n2=len(s)-n1+1
+ elif alen==3:
+ n2=arguments[2]
+ n2=n2.number(self)
+
+ if n1=='NaN' or n2=='NaN' or n1=='-Infinity' or n2=='-Infinity' or n1=='Infinity':
+ return u''
+
+ # n1,n2:origin=1 a1,a2:origin=0
+ n1=int(round(n1))
+ a1=n1-1
+ if a1<0: a1=0
+ if n2=='Infinity':
+ return s[a1:]
+ else:
+ n2=int(round(n2))
+ a2=n1+n2-1
+ return s[a1:a2]
+
+ def _substringBefore(self,*arguments):
+ if len(arguments)!=2:
+ throwError('Function substring-before expects (string, string)')
+ (s1,s2)=(arguments[0],arguments[1])
+ s1=s1.string(self)
+ s2=s2.string(self)
+ #if s2 in s1:
+ # n=s1.index(s2)
+ #else:
+ # return ''
+ n=s1.find(s2)
+ if n<0:
+ return ''
+ return s1[:n]
+
+ def _substringAfter(self,*arguments):
+ if len(arguments)!=2:
+ throwError('Function substring-after expects (string, string)')
+ (s1,s2)=(arguments[0],arguments[1])
+ s1=s1.string(self)
+ s2=s2.string(self)
+ #if s2 in s1:
+ # n=s1.index(s2)
+ #else:
+ # return ''
+ n=s1.find(s2)
+ if n<0:
+ return ''
+ return s1[n+len(s2):]
+
+ def _substringLength(self,*arguments):
+ alen=len(arguments)
+ if alen==0:
+ s=NodeUtil.to('string',self.node)
+ elif alen==1:
+ s=arguments[0]
+ s=s.string(self)
+ else:
+ throwError(u'Function string-length expects (string?)')
+ return len(s)
+
+ def _normalizeSpace(self,*arguments):
+ alen=len(arguments)
+ if alen==0:
+ s=NodeUtil.to('string',self.node)
+ elif alen==1:
+ s=arguments[0]
+ s=s.string(self)
+ else:
+ throwError(u'Function normalize-space expects (string?)')
+ return re_lastspace.sub('',re_firstspace.sub('',re_seqspace.sub(' ',s)))
+
+ def _translate(self,*arguments):
+ if len(arguments)!=3:
+ throwError('Function translate expects (string, string, string)')
+ (s1,s2,s3)=(arguments[0],arguments[1],arguments[2])
+ s1=s1.string(self)
+ s2=s2.string(self)
+ s3=s3.string(self)
+ _map={}
+ for i in range(0,len(s2)):
+ ch=s2[i]
+ if not _map.get(ch):
+ _map[ch]=s3[i] if i<len(s3) else ''
+ t=''
+ for ch in s1:
+ replace=_map.get(ch)
+ t+=replace if replace!=None else ch
+ return t
+
+ def _boolean(self,*arguments):
+ if len(arguments)!=1:
+ throwError(u'Function not expects (object)')
+ b=arguments[0]
+ b=b.bool(self)
+ return b
+
+ def _not(self,*arguments):
+ if len(arguments)!=1:
+ throwError(u'Function not expects (object)')
+ b=arguments[0]
+ b=b.bool(self)
+ return not b
+
+ def _true(self,*arguments):
+ if len(arguments)!=0:
+ throwError(u'Function false expects ()')
+ return True
+
+ def _false(self,*arguments):
+ if len(arguments)!=0:
+ throwError(u'Function false expects ()')
+ return False
+
+ def _lang(self,*arguments):
+ # not implemented
+ return False
+
+ def _number(self,*arguments):
+ alen=len(arguments)
+ if alen==0:
+ n=NodeUtil.to('number',self.node)
+ elif alen==1:
+ n=arguments[0]
+ n=n.number(self)
+ else:
+ throwError(u'Function number expects (object?)')
+ if isinstance(n,int):
+ return n
+ elif isinstance(n,float):
+ n1=int(n)
+ return n1 if n1==n else n
+ else:
+ return 'NaN'
+
+ def _sum(self,*arguments):
+ if len(arguments)!=1:
+ throwError(u'Function sum expects (nodeset)')
+ nodeset=arguments[0]
+ nodeset=nodeset.evaluate(self)
+ if not getattr(nodeset,'isNodeSet',None):
+ throwError(u'Function sum expects (nodeset)')
+ nodes=nodeset.list()
+ n=0
+ for node in nodes:
+ n+=NodeUtil.to('number',node)
+ return n
+
+ def _floor(self,*arguments):
+ if len(arguments)!=1:
+ throwError(u'Function floor expects (number)')
+ n=arguments[0]
+ n=n.number(self)
+ return int(math.floor(n))
+
+ def _ceiling(self,*arguments):
+ if len(arguments)!=1:
+ throwError(u'Function ceiling expects (number)')
+ n=arguments[0]
+ n=n.number(self)
+ return int(math.ceil(n))
+
+ def _round(self,*arguments):
+ if len(arguments)!=1:
+ throwError(u'Function round expects (number)')
+ n=arguments[0]
+ n=n.number(self)
+ return int(round(n))
+
+ funcs=ExtDict({
+ 'context-node' :[_contextNode ,'nodeset',False,[True]]
+ , 'root-node' :[_rootNode ,'nodeset',False,[]]
+ , 'last' :[_last ,'number' ,True ,[]]
+ , 'position' :[_position ,'number' ,True ,[]]
+ , 'count' :[_count ,'number' ,False,[]]
+ , 'id' :[_id ,'nodeset',False,[]]
+ , 'local-name' :[_localName ,'string' ,False,[True ,False]]
+ , 'name' :[_name ,'string' ,False,[True ,False]]
+ , 'namespace-uri' :[_namespaceUri ,'string' ,False,[True ,False]]
+ , 'string' :[_string ,'string' ,False,[True ,False]]
+ , 'concat' :[_concat ,'string' ,False,[]]
+ , 'starts-with' :[_startsWith ,'boolean',False,[]]
+ , 'contains' :[_contains ,'boolean',False,[]]
+ , 'substring' :[_substring ,'string' ,False,[]]
+ , 'substring-before':[_substringBefore,'string' ,False,[]]
+ , 'substring-after' :[_substringAfter ,'string' ,False,[]]
+ , 'string-length' :[_substringLength,'number' ,False,[True ,False]]
+ , 'normalize-space' :[_normalizeSpace ,'string' ,False,[True ,False]]
+ , 'translate' :[_translate ,'string' ,False,[]]
+ , 'boolean' :[_boolean ,'boolean',False,[]]
+ , 'not' :[_not ,'boolean',False,[]]
+ , 'true' :[_true ,'boolean',False,[]]
+ , 'false' :[_false ,'boolean',False,[]]
+ , 'lang' :[_lang ,'boolean',False,[]]
+ , 'number' :[_number ,'number' ,False,[True ,False]]
+ , 'sum' :[_sum ,'number' ,False,[]]
+ , 'floor' :[_floor ,'number' ,False,[]]
+ , 'ceiling' :[_ceiling ,'number' ,False,[]]
+ , 'round' :[_round ,'number' ,False,[]]
+ })
+
+ @classmethod
+ def parse(cls,lexer):
+ func=cls(lexer.next())
+ lexer.next()
+ while lexer.peek()!=')':
+ if lexer.empty():
+ throwError(u'missing function argument list')
+ expr=BinaryExpr.parse(lexer)
+ func.arg(expr)
+ if lexer.peek()!=',':
+ break
+ lexer.next()
+ if lexer.empty():
+ throwError(u'unclosed function argument list')
+ if lexer.next()!=')':
+ lexer.back()
+ throwError(u'bad token: %s' % (lexer.next()))
+ return func
+
+#} // end of FunctionCall
+
+
+#{ // NodeSet
+class NodeSet(object):
+ def __init__(self):
+ self.length=0
+ self.nodes=[]
+ self.seen={}
+ self.idIndexMap=None
+ self.reserveDels=[]
+ self.isNodeSet=True
+ self.isSorted=True
+ self.sortOff=False
+ self.only=None
+
+ def merge(self,nodeset):
+ self.isSorted=False
+ if getattr(nodeset,'only',None):
+ return self.push(nodeset.only)
+
+ if getattr(self,'only',None):
+ only=self.only
+ self.only=None
+ self.push(only)
+ self.length-=1
+
+ map(self._add,nodeset.nodes)
+
+ def sort(self):
+ if getattr(self,'only',None):
+ return
+ if getattr(self,'sortOff',None):
+ return
+ if getattr(self,'isSorted',None):
+ return
+
+ self.isSorted=True
+ self.idIndexMap=None
+ nodes=self.nodes
+
+ def _comp(a,b):
+ if a.nodeType==NodeTypeDOM.ATTRIBUTE_NODE: a=a.parentNode
+ if b.nodeType==NodeTypeDOM.ATTRIBUTE_NODE: b=b.parentNode
+ if a==b:
+ return 0
+ (node1,node2)=(a,b)
+ (ancestor1,ancestor2)=(a,b)
+ (deep1,deep2)=(0,0)
+
+ while True:
+ ancestor1=ancestor1.parentNode
+ if not ancestor1:
+ break
+ deep1+=1
+
+ while True:
+ ancestor2=ancestor2.parentNode
+ if not ancestor2:
+ break
+ deep2+=1
+
+ if deep1>deep2:
+ while deep1!=deep2:
+ deep1-=1
+ node1=node1.parentNode
+ if node1==node2:
+ return 1
+ elif deep2>deep1:
+ while deep2!=deep1:
+ deep2-=1
+ node2=node2.parentNode
+ if node1==node2:
+ return -1
+
+ while True:
+ ancestor1=node1.parentNode
+ ancestor2=node2.parentNode
+ if ancestor1==ancestor2:
+ break
+ node1=ancestor1
+ node2=ancestor2
+
+ while True:
+ node1=node1.nextSibling
+ if not node1:
+ break
+ if node1==node2:
+ return -1
+
+ return 1
+
+ def index_comp(a,b):
+ if a.nodeType==NodeTypeDOM.ATTRIBUTE_NODE: a=a.parentNode
+ if b.nodeType==NodeTypeDOM.ATTRIBUTE_NODE: b=b.parentNode
+ return cmp(a._sortindex,b._sortindex)
+
+ if USE_NODE_INDEX:
+ nodes.sort(index_comp)
+ else:
+ nodes.sort(_comp)
+
+ def reserveDelByNodeID(self,id,offset,reverse):
+ _map=self.createIdIndexMap()
+ index=_map.get(id)
+ if index:
+ if reverse and index<(self.length-offset-1) or not reverse and offset<index:
+ self.reserveDels.append(index)
+
+ def reserveDelByNode(self,node,offset,reverse=False):
+ self.reserveDelByNodeID(self.NodeID.get(node),offset,reverse)
+
+ def doDel(self):
+ if len(self.reserveDels)<=0:
+ return
+ map(self._del,sorted(self.reserveDels,lambda x,y:cmp(y,x)))
+ self.reserveDels=[]
+ self.idIndexMap=None
+
+ def createIdIndexMap(self):
+ if getattr(self,'idIndexMap',None):
+ return self.idIndexMap
+ else:
+ _map=self.idIndexMap={}
+ nodes=self.nodes
+ for i in range(0,len(nodes)):
+ node=nodes[i]
+ id=self.NodeID.get(node)
+ _map[id]=i
+ return _map
+
+ def _del(self,index):
+ self.length-=1
+ if getattr(self,'only',None):
+ self.only=None
+ else:
+ node=self.nodes[index]
+ if getattr(self,'_first',None)==node:
+ self._first=None
+ self._firstSourceIndex=None
+ self._firstSubIndex=None
+ del(self.seen[self.NodeID.get(node)])
+ del(self.nodes[index])
+
+ def delDescendant(self,elm,offset):
+ if getattr(self,'only',None):
+ return
+ nodeType=elm.nodeType
+ if nodeType!=NodeTypeDOM.ELEMENT_NODE and nodeType!=NodeTypeDOM.DOCUMENT_NODE:
+ return
+
+ nodes=self.nodes
+ i=offset+1
+ while i<len(nodes):
+ if elm.contains(nodes[i]):
+ self._del(i)
+ i-=1
+ i+=1
+
+ def _add(self,node,reverse=False):
+ seen=self.seen
+ id=self.NodeID.get(node)
+ if seen.get(id):
+ return
+ seen[id]=True
+ self.length+=1
+ if reverse:
+ self.nodes.insert(0,node)
+ else:
+ self.nodes.append(node)
+
+ def unshift(self,node):
+ if self.length<=0:
+ self.length+=1
+ self.only=node
+ return
+ if getattr(self,'only',None):
+ only=self.only
+ self.only=None
+ self.unshift(only)
+ self.length-=1
+ return self._add(node,True)
+
+ def push(self,node):
+ if self.length<=0:
+ self.length+=1
+ self.only=node
+ return
+ if getattr(self,'only',None):
+ only=self.only
+ self.only=None
+ self.push(only)
+ self.length-=1
+ return self._add(node)
+
+ def first(self):
+ if getattr(self,'only',None):
+ return self.only
+ if 0<len(self.nodes):
+ self.sort()
+ return self.nodes[0]
+ else:
+ return None
+
+ def list(self):
+ if getattr(self,'only',None):
+ return [self.only]
+ self.sort()
+ return self.nodes
+
+ def string(self):
+ node=self.only or self.first()
+ return NodeUtil.to('string',node) if node else ''
+
+ def bool(self):
+ return toBoolean(self.length or self.only)
+
+ def number(self):
+ return toNumber(self.string())
+
+ def iterator(self,reverse=False):
+ self.sort()
+ _info=ExtDict({
+ 'nodeset':self
+ , 'count':0
+ })
+ if not reverse:
+ calcIndex=(lambda x,y:x)
+ else:
+ calcIndex=(lambda x,y:y.length-x-1)
+ def iter():
+ nodeset=_info.nodeset
+ index=calcIndex(_info.count,nodeset)
+ _info['count']+=1
+ if getattr(nodeset,'only',None) and index==0:
+ return nodeset.only
+ return nodeset.nodes[index] if 0<=index and index<len(nodeset.nodes) else None
+ return iter
+
+ class nodeID(object):
+ def __init__(self):
+ self.uuid=1
+
+ def get(self,node):
+ id=getattr(node,'__bsxpath_id__',None)
+ if id:
+ return id
+ id=node.__bsxpath_id__=self.uuid
+ self.uuid+=1
+ return id
+
+ NodeID=nodeID()
+
+#} // end of NodeSet
+
+
+#{ // XPathEvaluator
+class XPathResult(object):
+ ANY_TYPE =0
+ NUMBER_TYPE =1
+ STRING_TYPE =2
+ BOOLEAN_TYPE =3
+ UNORDERED_NODE_ITERATOR_TYPE=4
+ ORDERED_NODE_ITERATOR_TYPE =5
+ UNORDERED_NODE_SNAPSHOT_TYPE=6
+ ORDERED_NODE_SNAPSHOT_TYPE =7
+ ANY_UNORDERED_NODE_TYPE =8
+ FIRST_ORDERED_NODE_TYPE =9
+
+ def __init__(self,value,type):
+ if type==XPathResult.ANY_TYPE:
+ tov=typeof(value)
+ if tov=='object' : type=self.UNORDERED_NODE_ITERATOR_TYPE
+ if tov=='boolean': type=self.BOOLEAN_TYPE
+ if tov=='string' : type=self.STRING_TYPE
+ if tov=='number' : type=self.NUMBER_TYPE
+
+ if type<self.NUMBER_TYPE or self.FIRST_ORDERED_NODE_TYPE<type:
+ throwError(u'unknown type: %d' %(type))
+ self.resultType=type
+
+ if type==self.NUMBER_TYPE:
+ self.numberValue=value.number() if getattr(value,'isNodeSet',None) else toNumber(value)
+ elif type==self.STRING_TYPE:
+ self.stringValue=value.string() if getattr(value,'isNodeSet',None) else toString(value)
+ elif type==self.BOOLEAN_TYPE:
+ self.booleanValue=value.bool() if getattr(value,'isNodeSet',None) else toBoolean(value)
+ elif type==self.ANY_UNORDERED_NODE_TYPE or type==self.FIRST_ORDERED_NODE_TYPE:
+ self.singleNodeValue=value.first()
+ else:
+ self.nodes=value.list()
+ self.snapshotLength=value.length
+ self.index=0
+ self.invalidIteratorState=False
+
+ def iterateNext(self):
+ node=self.nodes[self.index]
+ self.index+=1
+ return node
+
+ def snapshotItem(self,i):
+ return self.nodes[i]
+
+
+class XPathExpression(object):
+ def __init__(self,expr,resolver):
+ if len(expr)<=0:
+ throwError(u'no expression')
+ lexer=self.lexer=Lexer(expr)
+
+ if lexer.empty():
+ throwError(u'no expression')
+ self.expr=BinaryExpr.parse(lexer)
+ if not lexer.empty():
+ throwError(u'bad token: %s' % (lexer.next()))
+
+ def evaluate(self,node,type):
+ return XPathResult(self.expr.evaluate(Ctx(node)),type)
+
+
+class BSXPathEvaluator(BeautifulSoup):
+ def __init__(self, *args, **kwargs):
+ BeautifulSoup.__init__(self, *args, **kwargs)
+ self._string=u'[object HTMLDocument]'
+ self._fix_table()
+
+ self._init_index()
+
+ SELF_CLOSING_TAGS=buildTagMap(None,['br','hr','input','img','meta','spacer','frame','base'])
+ # exclude 'link' for XML
+
+ def _init_index(self):
+ idx=self._sortindex=1
+ self._cachemap=None
+
+ for node in NodeUtilBS.it_deepNodes(self):
+ idx=node._sortindex=idx+1
+ for node in self.findAll():
+ node.attrMap=dict(node.attrs)
+
+ def _fix_table(self):
+ tables=self.findAll('table')
+ for table in tables:
+ parent=table.parent
+ contents=getattr(table,'contents',[])
+ if len(contents)<=0: continue
+ (tbody,tr)=(None,None)
+ node=table.contents[0]
+ while node:
+ _next=node.nextSibling
+ name=getattr(node,'name',None)
+ if name in ('thead','tbody','tfoot',):
+ (tbody,tr)=(None,None)
+ elif name in ('tr',):
+ tr=None
+ if not tbody:
+ tbody=Tag(self,'tbody')
+ table.insert(table.contents.index(node),tbody)
+ tbody.append(node)
+ elif name in ('th','td',):
+ if not tbody:
+ tbody=Tag(self,'tbody')
+ table.insert(table.contents.index(node),tbody)
+ if not tr:
+ tr=Tag(self,'tr')
+ tbody.append(tr)
+ tr.append(node)
+ else:
+ parent.insert(parent.contents.index(table),node)
+ node=_next
+
+ def __str__(self,encoding=DEFAULT_OUTPUT_ENCODING):
+ return self._string
+
+ def __unicode__(self):
+ return self._string
+
+ def decode(self):
+ return self._string
+
+ def createExpression(self,expr,resolver):
+ return XPathExpression(expr,resolver)
+
+ def createNSResolver(self,nodeResolver):
+ # not implemented
+ pass
+
+ def evaluate(self,expr,context,resolver,type,result):
+ if not context:
+ context=self
+ if isinstance(context,list):
+ context=context[0]
+ return self.createExpression(expr,resolver).evaluate(context,type)
+
+ def getItemList(self,expr,context=None):
+ elms=[]
+ result=self.evaluate(expr,context,None,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,None)
+ for i in range(0,result.snapshotLength):
+ elms.append(result.snapshotItem(i))
+ return elms
+
+ def getFirstItem(self,expr,context=None):
+ elm=self.evaluate(expr,context,None,XPathResult.FIRST_ORDERED_NODE_TYPE,None).singleNodeValue
+ return elm
+
+ def applyXPath(self,context,expr):
+ start_t=datetime.datetime.now()
+ expression=self.createExpression(expr,None)
+ result=expression.evaluate(context,XPathResult.ANY_TYPE)
+ time=datetime.datetime.now()-start_t
+
+ resultType=result.resultType
+ if XPathResult.BOOLEAN_TYPE<resultType:
+ result=expression.evaluate(context,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE)
+ array=[]
+ for i in range(0,result.snapshotLength):
+ array.append(result.snapshotItem(i))
+ resultItems=array
+ else:
+ if resultType==XPathResult.NUMBER_TYPE:
+ resultItems=result.numberValue
+ elif resultType==XPathResult.STRING_TYPE:
+ resultItems=result.stringValue
+ elif resultType==XPathResult.BOOLEAN_TYPE:
+ resultItems=result.booleanValue
+ else:
+ resultItems=None
+
+ return (resultItems,time,resultType)
+
+
+#} // end of XPathEvaluator
+
+
+
+if __name__ == '__main__':
+ import sys
+ import optparse
+ import pdb
+
+ options=None
+
+ def prn(obj):
+ def prn_sub(obj,indent):
+ indent+=u' '
+ if isinstance(obj,list):
+ for i in range(0,len(obj)):
+ print u'[%d]' % (i)
+ prn_sub(obj[i],indent)
+ elif isinstance(obj,dict):
+ for mem in obj:
+ print u'[%s]' % (mem)
+ prn_sub(obj[mem],indent)
+ elif getattr(obj,'nodeType',None) or isinstance(obj,basestring):
+ str=indent+re.sub(r'([\r?\n])',r'\1'+indent,unicode(obj))
+ print str
+ else:
+ print obj
+ prn_sub(obj,u'')
+
+ def test():
+ global options
+
+ if options.expr:
+ if options.html:
+ document=BSXPathEvaluator(options.html)
+ elif options.file:
+ fp=open(options.file)
+ document=BSXPathEvaluator(fp.read())
+ fp.close()
+ else:
+ document=BSXPathEvaluator(sys.stdin.read())
+
+ (result,time,resultType)=document.applyXPath(document,options.expr)
+
+ prn(result)
+
+ else:
+ optparser.print_help()
+
+ optparser=optparse.OptionParser()
+ optparser.add_option(
+ '-e','--expr'
+ , action='store'
+ , metavar='<expression>'
+ , help=u'expression: XPATH expression'
+ , dest='expr'
+ )
+ optparser.add_option(
+ '-t','--html'
+ , action='store'
+ , metavar='<text>'
+ , help=u'text: HTML text'
+ , dest='html'
+ )
+ optparser.add_option(
+ '-f','--file'
+ , action='store'
+ , metavar='<filename>'
+ , help=u'filename: HTML filename'
+ , dest='file'
+ )
+ optparser.add_option(
+ '-d','--debug'
+ , action='store_true'
+ , help=u'use pdb'
+ , dest='debug'
+ )
+ (options,args)=optparser.parse_args()
+
+ if options.debug:
+ pdb.run('test()')
+ else:
+ test()
+
+#[History]
+#
+# 0.01e: 2009-04-12
+# - exclude 'link' tag from SELF_CLOSING_TAGS (for XML)
+# - add __str__() and __unicode__() to AttributeWrapper class
+#
+# 0.01d: 2009-03-28
+# - performance improvement: node searching(make attrMap in advance)
+#
+# 0.01c: 2009-03-28
+# - performance improvement: node sorting(indexing) and node search(caching)
+#
+# 0.01b: 2009-03-27
+# - fixed 'singleNodeValue' bug
+# result = document.evaluate('//title[1]',document,None,XPathResult.FIRST_ORDERED_NODE_TYPE,None).singleNodeValue
+# # returnd 'None', even though first-value exists
+#
+# 0.01a: 2009-03-27
+# - fixed string() bug
+# BSXPath.py -e "boolean(//p[contains(string(),\"br\")])" -t "<html><head></head><body><p>text before<br />text after</p></body></html>"
+# # returned 'True', even though 'False' is right
+# - cope with <table> problems on malformed HTML
+# may convert '<table><th></th><td></td></table>' to '<table><tbody><tr><th></th><td></td></tr></tbody></table>' automatically
+#
+# 0.01 : 2009-03-25
+# first release
+#
+#â–  End of BSXPath.py
diff --git a/BSXPath_ver001e/BSXPath.pyc b/BSXPath_ver001e/BSXPath.pyc
new file mode 100644
index 0000000..e1d3264
--- /dev/null
+++ b/BSXPath_ver001e/BSXPath.pyc
Binary files differ
diff --git a/BSXPath_ver001e/TEST_BSXPath.py b/BSXPath_ver001e/TEST_BSXPath.py
new file mode 100644
index 0000000..37fe307
--- /dev/null
+++ b/BSXPath_ver001e/TEST_BSXPath.py
@@ -0,0 +1,368 @@
+# -*- coding: utf-8 -*-
+
+"""
+TEST_BSXPath.py: Test Script for BSXPath
+
+"""
+
+import sys,os,glob,re,datetime,optparse
+import urllib2
+import pdb
+
+from BSXPath import BSXPathEvaluator,XPathResult
+from BSXPath import ExtDict,typeof,toString
+
+(document,options,url_data)=(None,None,u'http://svn.coderepos.org/share/lang/javascript/javascript-xpath/trunk/test/functional/data/')
+DEFAULT_TESTDIR='testdata'
+
+uai={'gecko':True,'opera95':True} # User Agent(dummy)
+
+def escapeStr(str):
+ return re.sub(r'\r?\n',r'\\n',re.sub(r'\\',r'\\\\',re.sub(r'"',r'\\"',str)))
+
+def parseTestData(datafile,web=False):
+ try:
+ f=urllib2.urlopen(datafile) if web else open(datafile)
+ data=f.read()
+ f.close()
+ (comment,html,contextExpr,testData)=data.split('\n--------\n')
+ testDataSplited=testData.split('\n')
+
+ tests=[]
+ for testline in testDataSplited:
+ if re.search(r'^\s*#',testline): continue
+ #mrslt=re.search(r'^\s*(.*?)\s*=>\s*(.*?)?\s*$',testline)
+ mrslt=re.search(r'^\s*(.*?)\s*=>\s*(.*?)\s*$',testline)
+ if mrslt:
+ tests.append(ExtDict({'expr':mrslt.group(1),'data':mrslt.group(2)}))
+ return ExtDict({'comment':comment,'html':html,'contextExpr':contextExpr,'tests':tests})
+ except:
+ return None
+
+#{ // NodeTest
+class NodeTest(object):
+ def __init__(self,data):
+ self.nodes=[]
+ if not data: data=''
+
+ if re.search(r'^\s*\(none\)\s*$',data): return
+
+ def chktoken(mrslt):
+ token=mrslt.group()
+ uas = nodeData = nodeType = nodeName = nodeValue = None
+ m=re.search(r'([\w-]+)\(((([\w-]+)=)?("[^"]*"|\'[^\']*\'|-?\d+|NaN|-?Infinity|true|false)?)\)((:\w+)*)',token)
+ if m:
+ nodeType=self.typeMap[m.group(1)]
+ if nodeType==0:
+ nodeName = '#value'
+ nodeValue = m.group(2)
+ elif nodeType==2 or nodeType==7:
+ nodeName = m.group(4)
+ nodeValue = m.group(5)
+ elif nodeType==3:
+ nodeName = '#text'
+ nodeValue = m.group(2)
+ elif nodeType==4:
+ nodeName = '#cdata-section'
+ nodeValue = m.group(2)
+ elif nodeType==8:
+ nodeName = '#comment'
+ nodeValue = m.group(2)
+ elif nodeType==9:
+ nodeName = '#document'
+ nodeValue = None
+ else:
+ nodeValue = m.group(2)
+
+ if nodeValue and nodeType != 0:
+ first = nodeValue[0]
+ last = nodeValue[-1]
+ if last==first and (first == '"' or first == "'"):
+ nodeValue = eval(nodeValue)
+ uas = m.group(6).split(':')
+ else:
+ m = re.search(r'((\w+)((\.[\w-]+|#[\w-]+|\[[\w-]+=("[^"]*"|\'[^\']*\')\])*))((:\w+)*)',token)
+ nodeType = 1
+ nodeName = m.group(2)
+ nodeDatas = m.group(3)
+ nodeDatas = re.findall(r'\.[\w-]+|#[\w-]+|\[[\w-]+=(?:"[^"]*"|\'[^\']*\')\]',nodeDatas)
+
+ class nd_class(object):
+ def __init__(self,name):
+ self.type='class'
+ self.name=name
+ def match(self,node):
+ classes=re.split(r'\s+',node.get('class',''))
+ for _class in classes:
+ if _class==self.name:
+ return True
+ return False
+
+ class nd_id(object):
+ def __init__(self,name):
+ self.type='attr'
+ self.name=name
+ def match(self,node):
+ return node.get('id')==self.name
+
+ class nd_attr(object):
+ def __init__(self,name,value):
+ self.type='attr'
+ self.name=name
+ self.value=value
+ def match(self,node):
+ return node.get(self.name)==self.value
+
+ nodeData = []
+ for data in nodeDatas:
+ ch=data[0]
+ if ch=='.':
+ nodeData.append(nd_class(data[1:]))
+ elif ch=='#':
+ nodeData.append(nd_id(data[1:]))
+ elif ch=='[':
+ data = data[1:-1].split('=')
+ #nodeData.append(nd_attr(data[0],data[1]))
+ nodeData.append(nd_attr(data[0],eval(data[1])))
+ else:
+ pass
+
+ uas = m.group(6).split(':')
+
+ if uas: uas=filter(lambda x:x,uas)
+
+ def createNodeInfo(nodeType, nodeName, nodeValue, nodeData):
+ def _match(snode,node):
+ if node.nodeType != snode.nodeType: return False
+ if node.nodeName != snode.nodeName: return False
+ if node.nodeValue != snode.nodeValue: return False
+ if snode.nodeData:
+ for nodeData in snode.nodeData:
+ if not nodeData.match(node): return False
+ return True
+
+ return ExtDict({
+ 'nodeType' : nodeType
+ , 'nodeName' : nodeName
+ , 'nodeValue': nodeValue
+ , 'nodeData' : nodeData
+ , 'match' : _match
+ })
+
+ #self.nodes.append(createNodeInfo(nodeType, nodeName, nodeValue, nodeData))
+ if uas:
+ for ua in uas:
+ if uai.get(ua):
+ self.nodes.append(createNodeInfo(nodeType, nodeName, nodeValue, nodeData))
+ else:
+ self.nodes.append(createNodeInfo(nodeType, nodeName, nodeValue, nodeData))
+
+ return token
+
+ tokens=re.sub(r'([\w-]+\(.*?\)|\w+(\.[\w-]+|#[\w-]+|\[[\w-]+=("[^"]*"|\'[^\']*\')\])*)(:\w+)*',chktoken,data)
+
+ if len(self.nodes)==1 and self.nodes[0].nodeType==0:
+ self.primitive = True
+ #self.value = self.nodes[0].nodeValue
+ nodeValue=self.nodes[0].nodeValue
+ try:
+ self.value = eval(nodeValue)
+ except:
+ if nodeValue=='true':
+ self.value = True
+ elif nodeValue=='false':
+ self.value = False
+
+ typeMap = {
+ 'value' : 0
+ , 'element' : 1
+ , 'attribute' : 2
+ , 'text' : 3
+ , 'cdata-section' : 4
+ , 'entity-reference' : 5
+ , 'entity' : 6
+ , 'processing-instruction': 7
+ , 'comment' : 8
+ , 'document' : 9
+ , 'document-type' : 10
+ , 'document-fragment' : 11
+ , 'notation' : 12
+ }
+
+ def test(self,nodes):
+ if len(nodes)!=len(self.nodes):
+ print u' (*) node number error: %d vs %d' % (len(nodes),len(self.nodes))
+ return False
+ for i in range(0,len(nodes)):
+ snode=self.nodes[i]
+ if not snode.match(snode,nodes[i]):
+ print u'%s' % (snode)
+ print u'%s' % (nodes[i])
+ try:
+ print u' (*) node error: %s' % (nodes[i])
+ except:
+ print u' (*) node error:'
+ print nodes[i]
+ return False;
+ return True
+
+#} // NodeTest
+
+
+def testNodes(nodes,data):
+ tester=NodeTest(data)
+ if getattr(tester,'primitive',False):
+ if tester.value == nodes:
+ return ExtDict({'status':'OK','detail':'-'})
+ else:
+ if typeof(tester.value)!='string':
+ return ExtDict({'status':'NG','detail':'value(' + toString(nodes) + ')'})
+ else:
+ return ExtDict({'status':'NG','detail':'value("' + escapeStr(toString(nodes)) + '")'})
+
+ if tester.test(nodes):
+ return ExtDict({'status':'OK','detail':'-'})
+
+ detail = []
+ for node in nodes:
+ t = ''
+ nodeType=node.nodeType
+ if nodeType==1:
+ t += node.nodeName
+ if node.id:
+ t += '#' + node.id
+ if node.className:
+ classes = re.split(r'\s+',node.className)
+ t += '.' + '.'.join(classes)
+ elif nodeType==3:
+ t += 'text("' + escapeStr(toString(node.nodeValue)) + '")'
+ elif nodeType==7:
+ t += 'processing-instruction(' + node.nodeName+'="' + escapeStr(toString(node.nodeValue)) + '")'
+ elif nodeType==8:
+ t += 'comment("' + escapeStr(node.nodeValue) + '")'
+ elif nodeType==9:
+ t += 'document()'
+ else:
+ t += 'unknown'
+ detail.append(t)
+
+ return ExtDict({'status':'NG','detail':' '.join(detail)})
+
+def test():
+ global document,options,DEFAULT_TESTDIR,url_data
+
+ def nodesStr(nodes):
+ def tagstr(node):
+ try:
+ strs=['<'+node.name]
+ i=node.get('id')
+ c=node.get('class')
+ if i:
+ strs.append('id='+i)
+ if c:
+ strs.append('class='+c)
+ return escapeStr(' '.join(strs)+'>')
+ except:
+ return escapeStr(unicode(node))
+
+ if isinstance(nodes,list):
+ return ' '.join([tagstr(node) for node in nodes])
+ elif getattr(nodes,'nodeType',None) or isinstance(nodes,basestring):
+ return escapeStr(unicode(nodes))
+ else:
+ return nodes
+
+ if options.web:
+ fp=urllib2.urlopen(url_data)
+ dirdoc=BSXPathEvaluator(fp.read())
+ files=map(lambda node:node.get('href'),dirdoc.getItemList('//li/a[@href!="../"]'))
+ else:
+ if options.path:
+ testdir=options.path
+ else:
+ testdir=DEFAULT_TESTDIR
+ files=os.listdir(testdir)
+
+ tnames=','.join(options.names).split(',') if options.names else None
+ tnumbers=','.join(options.numbers).split(',') if options.numbers else None
+ for name in files:
+ if tnames:
+ fname=re.sub(r'\..*$','',name)
+ if not fname in tnames: continue
+ target=url_data+'/'+name if options.web else os.path.join(testdir,name)
+ data=parseTestData(target,options.web)
+ print '[%s]\n%s\n' % (name,data.comment)
+ document=BSXPathEvaluator(data.html)
+ context=document.evaluate(data.contextExpr,document,None,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,None).snapshotItem(0)
+ tests=data.tests
+ cnt=0
+ for test in tests:
+ cnt=cnt+1
+ if tnumbers:
+ if not str(cnt) in tnumbers: continue
+ print u'No.%d' % cnt
+ expr=test.expr
+ print u'expr : %s' % (expr)
+
+ (nodes,time,resultType)=document.applyXPath(context,expr)
+
+ print u'time : %d.%06d sec' % (time.seconds,time.microseconds)
+ print u'result: %s' % nodesStr(nodes)
+ print u'expect: %s' % (test.data)
+
+ judge=testNodes(nodes,test.data)
+
+ print u'judge : %s (%s)' % (judge.status,judge.detail)
+ print u''
+
+ print u''
+
+def getoptions():
+ #parser=optparse.OptionParser(usage=u'%prog')
+ parser=optparse.OptionParser()
+ parser.add_option(
+ '-t','--test'
+ , action='append'
+ , metavar='<name>'
+ , help=u'name: test name'
+ , dest='names'
+ )
+ parser.add_option(
+ '-n','--number'
+ , action='append'
+ , metavar='<number>'
+ , help=u'number: test number'
+ , dest='numbers'
+ )
+ parser.add_option(
+ '-p','--path'
+ , action='store'
+ , metavar='<path>'
+ , help=u'path: path of test file directory'
+ , dest='path'
+ )
+ parser.add_option(
+ '-w','--webdata'
+ , action='store_true'
+ , help=u'use data on web (%s)' % (url_data)
+ , dest='web'
+ )
+ parser.add_option(
+ '-d','--debug'
+ , action='store_true'
+ , help=u'use pdb'
+ , dest='debug'
+ )
+ return parser.parse_args()
+
+if __name__ == '__main__':
+
+ (options,args)=getoptions()
+
+ if options.debug:
+ pdb.run('test()')
+ else:
+ test()
+
+
+#â–  End of TEST_BSXPath.py
diff --git a/BSXPath_ver001e/ex.html b/BSXPath_ver001e/ex.html
new file mode 100644
index 0000000..2331df5
--- /dev/null
+++ b/BSXPath_ver001e/ex.html
@@ -0,0 +1,11 @@
+<!doctype html><html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><script>window.google={kEI:"eH5qSovuNaek9ATIj_XFCQ",kEXPI:"17259,20760,21078",kCSIE:"17259,20760,21078",kCSI:{e:"17259,20760,21078",ei:"eH5qSovuNaek9ATIj_XFCQ"},kHL:"en"};
+
+window.google.sn="webhp";window.google.timers={load:{t:{start:(new Date).getTime()}}};try{window.google.pt=window.gtbExternal&&window.gtbExternal.pageT()||window.external&&window.external.pageT}catch(b){}
+window.google.jsrt_kill=1;
+var _gjwl=location;function _gjuc(){var e=_gjwl.href.indexOf("#");if(e>=0){var a=_gjwl.href.substring(e);if(a.indexOf("&q=")>0||a.indexOf("#q=")>=0){a=a.substring(1);if(a.indexOf("#")==-1){for(var c=0;c<a.length;){var d=c;if(a.charAt(d)=="&")++d;var b=a.indexOf("&",d);if(b==-1)b=a.length;var f=a.substring(d,b);if(f.indexOf("fp=")==0){a=a.substring(0,c)+a.substring(b,a.length);b=c}else if(f=="cad=h")return 0;c=b}_gjwl.href="/search?"+a+"&cad=h";return 1}}}return 0}function _gjp(){!(window._gjwl.hash&&
+window._gjuc())&&setTimeout(_gjp,500)};
+window._gjp && _gjp()</script><style>td{line-height:.8em;}.gac_m td{line-height:17px;}form{margin-bottom:20px;}body,td,a,p,.h{font-family:arial,sans-serif}.h{color:#36c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}#gbar{height:22px}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#guser{padding-bottom:7px !important;text-align:right}#gbar,#guser{font-size:13px;padding-top:1px !important}@media all{.gb1,.gb3{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb3{color:#00c !important}.gb3{text-decoration:none}</style><script>google.y={};google.x=function(e,g){google.y[e.id]=[e,g];return false};</script></head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onload="document.f.q.focus();if(document.images)new Image().src='/images/nav_logo6.png'" topmargin=3 marginheight=3><textarea id=csi style=display:none></textarea><iframe name=wgjf style=display:none></iframe><div id=gbar><nobr><b class=gb1>Web</b> <a href="http://images.google.com/imghp?hl=en&tab=wi" class=gb1>Images</a> <a href="http://video.google.com/?hl=en&tab=wv" class=gb1>Videos</a> <a href="http://maps.google.com/maps?hl=en&tab=wl" class=gb1>Maps</a> <a href="http://news.google.com/nwshp?hl=en&tab=wn" class=gb1>News</a> <a href="http://www.google.com/prdhp?hl=en&tab=wf" class=gb1>Shopping</a> <a href="http://mail.google.com/mail/?hl=en&tab=wm" class=gb1>Gmail</a> <a href="http://www.google.com/intl/en/options/" class=gb3><u>more</u> &raquo;</a></nobr></div><div id=guser width=100%><nobr><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.com/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNFA18XPfgb7dKnXfKz7x7g1GDH1tg">iGoogle</a> | <a href="https://www.google.com/accounts/Login?hl=en&continue=http://www.google.com/">Sign in</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div><center><br clear=all id=lgpd><img alt="Google" height=110 src="/intl/en_ALL/images/logo.gif" width=276 id=logo onload="window.lol&&lol()"><br><br><form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top><td width=25%>&nbsp;</td><td align=center nowrap><input name=hl type=hidden value=en><input type=hidden name=ie value="ISO-8859-1"><input autocomplete="off" maxlength=2048 name=q size=55 title="Google Search" value=""><br><input name=btnG type=submit value="Google Search"><input name=btnI type=submit value="I'm Feeling Lucky"></td><td nowrap width=25% align=left><font size=-2>&nbsp;&nbsp;<a href=/advanced_search?hl=en>Advanced Search</a><br>&nbsp;&nbsp;<a href=/preferences?hl=en>Preferences</a><br>&nbsp;&nbsp;<a href=/language_tools?hl=en>Language Tools</a></font></td></tr></table></form><br><font size=-1><font color=red>New!</font> <a href="/aclk?sa=L&ai=Chvmr3XdqSvf1M5288gSGrMkkr42rhgHhn63XDMHZnNkTEAEgwVRQ76H57Pr_____AWBNqgQJT9B6N6oM_lD1&num=1&sig=AGiWqtxk0LhViGspQkwahqtdqEsspwyq8Q&q=http://www.google.com/help/ig/comicsthemes/">Get Comics Themes</a> from Superman, The Hulk, Peanuts, and more.</font><br><br><br><font size=-1><a href="/intl/en/ads/">Advertising&nbsp;Programs</a> - <a href="/services/">Business Solutions</a> - <a href="/intl/en/about.html">About Google</a></font><p><font size=-2>&copy;2009 - <a href="/intl/en/privacy.html">Privacy</a></font></p></center><div id=xjsd></div><div id=xjsi><script>if(google.y)google.y.first=[];if(google.y)google.y.first=[];google.dstr=[];google.rein=[];window.setTimeout(function(){var a=document.createElement("script");a.src="/extern_js/f/CgJlbhICdXMgACswCjgiQAgsKzAOOAUsKzAYOAQsKzAlOMmIASwrMCY4BSwrMCc4Aiw/PntwpfCwb-Y.js";(document.getElementById("xjsd")||document.body).appendChild(a)},0);
+;google.y.first.push(function(){google.ac.m=0;google.ac.i(document.f,document.f.q,'','')});google.xjs&&google.j&&google.j.xi&&google.j.xi()</script></div><script>(function(){
+function a(){google.timers.load.t.ol=(new Date).getTime();google.report&&google.report(google.timers.load,google.kCSI)}if(window.addEventListener)window.addEventListener("load",a,false);else if(window.attachEvent)window.attachEvent("onload",a);google.timers.load.t.prt=(new Date).getTime();
+})();
+</script> \ No newline at end of file
diff --git a/BSXPath_ver001e/testbsx.cmd b/BSXPath_ver001e/testbsx.cmd
new file mode 100644
index 0000000..370db80
--- /dev/null
+++ b/BSXPath_ver001e/testbsx.cmd
@@ -0,0 +1,11 @@
+@echo off
+
+SET TESTDIR="testbsxresult"
+
+dir %TESTDIR% > nul 2>&1 || mkdir %TESTDIR%
+
+echo "--- START"
+for %%F in (0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 0012) do TEST_BSXPath.py -w -t %%F > %TESTDIR%\r%%F.txt
+echo "--- END"
+
+:END
diff --git a/BSXPath_ver001e/testbsxresult/r0000.txt b/BSXPath_ver001e/testbsxresult/r0000.txt
new file mode 100644
index 0000000..d825a79
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0000.txt
@@ -0,0 +1,200 @@
+[0000]
+Preceding and Folloing Test
+
+No.1
+expr : id("t1")/following::*
+time : 0.016000 sec
+result: <li> <li id=t2> <p class=2> <div> <p class=3> <ul> <li id=t3> <li> <li id=t4> <p class=4>
+expect: li li#t2 p.2 div p.3 ul li#t3 li li#t4 p.4
+judge : OK (-)
+
+No.2
+expr : id("t2")/following::*
+time : 0.000000 sec
+result: <p class=2> <div> <p class=3> <ul> <li id=t3> <li> <li id=t4> <p class=4>
+expect: p.2 div p.3 ul li#t3 li li#t4 p.4
+judge : OK (-)
+
+No.3
+expr : id("t3")/following::*
+time : 0.000000 sec
+result: <li> <li id=t4> <p class=4>
+expect: li li#t4 p.4
+judge : OK (-)
+
+No.4
+expr : id("t4")/following::*
+time : 0.000000 sec
+result: <p class=4>
+expect: p.4
+judge : OK (-)
+
+No.5
+expr : id("t3 t4")/following::*
+time : 0.015000 sec
+result: <li> <li id=t4> <p class=4>
+expect: li li#t4 p.4
+judge : OK (-)
+
+No.6
+expr : id("t2 t3 t4")/following::*
+time : 0.016000 sec
+result: <p class=2> <div> <p class=3> <ul> <li id=t3> <li> <li id=t4> <p class=4>
+expect: p.2 div p.3 ul li#t3 li li#t4 p.4
+judge : OK (-)
+
+No.7
+expr : id("t1 t2 t3 t4")/following::*
+time : 0.015000 sec
+result: <li> <li id=t2> <p class=2> <div> <p class=3> <ul> <li id=t3> <li> <li id=t4> <p class=4>
+expect: li li#t2 p.2 div p.3 ul li#t3 li li#t4 p.4
+judge : OK (-)
+
+No.8
+expr : id("t1 t2 t3 t4")/preceding::*
+time : 0.015000 sec
+result: <head> <title> <div> <p class=1> <ul> <li id=t1> <li> <li id=t2> <p class=2> <p class=3> <li id=t3> <li>
+expect: head title div p.1 ul li#t1 li li#t2 p.2 p.3 li#t3 li
+judge : OK (-)
+
+No.9
+expr : id("t1 t2 t3")/preceding::*
+time : 0.016000 sec
+result: <head> <title> <div> <p class=1> <ul> <li id=t1> <li> <li id=t2> <p class=2> <p class=3>
+expect: head title div p.1 ul li#t1 li li#t2 p.2 p.3
+judge : OK (-)
+
+No.10
+expr : id("t1 t2")/preceding::*
+time : 0.000000 sec
+result: <head> <title> <p class=1> <li id=t1> <li>
+expect: head title p.1 li#t1 li
+judge : OK (-)
+
+No.11
+expr : id("t1")/preceding::*
+time : 0.000000 sec
+result: <head> <title> <p class=1>
+expect: head title p.1
+judge : OK (-)
+
+No.12
+expr : id("t2")/preceding::*
+time : 0.016000 sec
+result: <head> <title> <p class=1> <li id=t1> <li>
+expect: head title p.1 li#t1 li
+judge : OK (-)
+
+No.13
+expr : id("t3")/preceding::*
+time : 0.015000 sec
+result: <head> <title> <div> <p class=1> <ul> <li id=t1> <li> <li id=t2> <p class=2> <p class=3>
+expect: head title div p.1 ul li#t1 li li#t2 p.2 p.3
+judge : OK (-)
+
+No.14
+expr : id("t4")/preceding::*
+time : 0.016000 sec
+result: <head> <title> <div> <p class=1> <ul> <li id=t1> <li> <li id=t2> <p class=2> <p class=3> <li id=t3> <li>
+expect: head title div p.1 ul li#t1 li li#t2 p.2 p.3 li#t3 li
+judge : OK (-)
+
+No.15
+expr : id("t1")/following::*[1]
+time : 0.015000 sec
+result: <li>
+expect: li
+judge : OK (-)
+
+No.16
+expr : id("t2")/following::*[1]
+time : 0.000000 sec
+result: <p class=2>
+expect: p.2
+judge : OK (-)
+
+No.17
+expr : id("t3")/following::*[1]
+time : 0.000000 sec
+result: <li>
+expect: li
+judge : OK (-)
+
+No.18
+expr : id("t4")/following::*[1]
+time : 0.016000 sec
+result: <p class=4>
+expect: p.4
+judge : OK (-)
+
+No.19
+expr : id("t3 t4")/following::*[1]
+time : 0.015000 sec
+result: <li> <p class=4>
+expect: li p.4
+judge : OK (-)
+
+No.20
+expr : id("t2 t3 t4")/following::*[1]
+time : 0.016000 sec
+result: <p class=2> <li> <p class=4>
+expect: p.2 li p.4
+judge : OK (-)
+
+No.21
+expr : id("t1 t2 t3 t4")/following::*[1]
+time : 0.015000 sec
+result: <li> <p class=2> <li> <p class=4>
+expect: li p.2 li p.4
+judge : OK (-)
+
+No.22
+expr : id("t1 t2 t3 t4")/preceding::*[1]
+time : 0.031000 sec
+result: <p class=1> <li> <p class=3> <li>
+expect: p.1 li p.3 li
+judge : OK (-)
+
+No.23
+expr : id("t1 t2 t3")/preceding::*[1]
+time : 0.016000 sec
+result: <p class=1> <li> <p class=3>
+expect: p.1 li p.3
+judge : OK (-)
+
+No.24
+expr : id("t1 t2")/preceding::*[1]
+time : 0.016000 sec
+result: <p class=1> <li>
+expect: p.1 li
+judge : OK (-)
+
+No.25
+expr : id("t1")/preceding::*[1]
+time : 0.015000 sec
+result: <p class=1>
+expect: p.1
+judge : OK (-)
+
+No.26
+expr : id("t2")/preceding::*[1]
+time : 0.016000 sec
+result: <li>
+expect: li
+judge : OK (-)
+
+No.27
+expr : id("t3")/preceding::*[1]
+time : 0.016000 sec
+result: <p class=3>
+expect: p.3
+judge : OK (-)
+
+No.28
+expr : id("t4")/preceding::*[1]
+time : 0.000000 sec
+result: <li>
+expect: li
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0001.txt b/BSXPath_ver001e/testbsxresult/r0001.txt
new file mode 100644
index 0000000..aa7c3d9
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0001.txt
@@ -0,0 +1,515 @@
+[0001]
+Simple Value Test
+
+No.1
+expr : local-name(/html)
+time : 0.000000 sec
+result: html
+expect: value("html")
+judge : OK (-)
+
+No.2
+expr : count(/)
+time : 0.000000 sec
+result: 1
+expect: value(1)
+judge : OK (-)
+
+No.3
+expr : count(//li)
+time : 0.000000 sec
+result: 5
+expect: value(5)
+judge : OK (-)
+
+No.4
+expr : boolean(id('b'))
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.5
+expr : boolean(/..)
+time : 0.000000 sec
+result: False
+expect: value(false)
+judge : OK (-)
+
+No.6
+expr : boolean(0)
+time : 0.000000 sec
+result: False
+expect: value(false)
+judge : OK (-)
+
+No.7
+expr : boolean(NaN)
+time : 0.000000 sec
+result: False
+expect: value(false)
+judge : OK (-)
+
+No.8
+expr : boolean(1)
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.9
+expr : boolean(-1)
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.10
+expr : boolean("")
+time : 0.000000 sec
+result: False
+expect: value(false)
+judge : OK (-)
+
+No.11
+expr : boolean("Nice boat.")
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.12
+expr : not(true())
+time : 0.000000 sec
+result: False
+expect: value(false)
+judge : OK (-)
+
+No.13
+expr : true() and true()
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.14
+expr : true() or false()
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.15
+expr : number(id('b'))
+time : 0.031000 sec
+result: 3
+expect: value(3)
+judge : OK (-)
+
+No.16
+expr : number("1")
+time : 0.000000 sec
+result: 1
+expect: value(1)
+judge : OK (-)
+
+No.17
+expr : number("-1")
+time : 0.000000 sec
+result: -1
+expect: value(-1)
+judge : OK (-)
+
+No.18
+expr : number(" 1")
+time : 0.000000 sec
+result: 1
+expect: value(1)
+judge : OK (-)
+
+No.19
+expr : number(" -1")
+time : 0.000000 sec
+result: -1
+expect: value(-1)
+judge : OK (-)
+
+No.20
+expr : number(true())
+time : 0.000000 sec
+result: True
+expect: value(1)
+judge : OK (-)
+
+No.21
+expr : number(false())
+time : 0.000000 sec
+result: False
+expect: value(0)
+judge : OK (-)
+
+No.22
+expr : sum(id("numbers")/li)
+time : 0.016000 sec
+result: 15
+expect: value(15)
+judge : OK (-)
+
+No.23
+expr : 1 + 1
+time : 0.000000 sec
+result: 2
+expect: value(2)
+judge : OK (-)
+
+No.24
+expr : 1+1
+time : 0.000000 sec
+result: 2
+expect: value(2)
+judge : OK (-)
+
+No.25
+expr : 1 - 1
+time : 0.000000 sec
+result: 0
+expect: value(0)
+judge : OK (-)
+
+No.26
+expr : 1-1
+time : 0.000000 sec
+result: 0
+expect: value(0)
+judge : OK (-)
+
+No.27
+expr : string(html - html)
+time : 0.000000 sec
+result: NaN
+expect: value("NaN")
+judge : OK (-)
+
+No.28
+expr : html-html
+time : 0.000000 sec
+result:
+expect: (none)
+judge : OK (-)
+
+No.29
+expr : normalize-space(string())
+time : 0.016000 sec
+result: Title hoge 3 1 2 3 4 5
+expect: value("Title hoge 3 1 2 3 4 5"):gecko:opera:applewebkit value("Titlehoge 3 1 2 3 4 5"):ie
+judge : OK (-)
+
+No.30
+expr : normalize-space(string(.))
+time : 0.000000 sec
+result: Title hoge 3 1 2 3 4 5
+expect: value("Title hoge 3 1 2 3 4 5"):gecko:opera:applewebkit value("Titlehoge 3 1 2 3 4 5"):ie
+judge : OK (-)
+
+No.31
+expr : normalize-space(string(/))
+time : 0.000000 sec
+result: Title hoge 3 1 2 3 4 5
+expect: value("Title hoge 3 1 2 3 4 5"):gecko:opera:applewebkit value("Titlehoge 3 1 2 3 4 5"):ie
+judge : OK (-)
+
+No.32
+expr : normalize-space(string(/html))
+time : 0.000000 sec
+result: Title hoge 3 1 2 3 4 5
+expect: value("Title hoge 3 1 2 3 4 5"):gecko:opera:applewebkit value("Titlehoge 3 1 2 3 4 5"):ie
+judge : OK (-)
+
+No.33
+expr : normalize-space(string(//div))
+time : 0.015000 sec
+result: hoge 3
+expect: value('hoge 3')
+judge : OK (-)
+
+No.34
+expr : string(//*//*//*)
+time : 0.016000 sec
+result: Title
+expect: value("Title")
+judge : OK (-)
+
+No.35
+expr : string(/..)
+time : 0.000000 sec
+result:
+expect: value("")
+judge : OK (-)
+
+No.36
+expr : string(number('Nice boat.'))
+time : 0.000000 sec
+result: NaN
+expect: value("NaN")
+judge : OK (-)
+
+No.37
+expr : string(1 div 0)
+time : 0.000000 sec
+result: Infinity
+expect: value("Infinity")
+judge : OK (-)
+
+No.38
+expr : string(1 div -0)
+time : 0.000000 sec
+result: -Infinity
+expect: value("-Infinity")
+judge : OK (-)
+
+No.39
+expr : string(0)
+time : 0.000000 sec
+result: 0
+expect: value("0")
+judge : OK (-)
+
+No.40
+expr : string(-0)
+time : 0.000000 sec
+result: 0
+expect: value("0")
+judge : OK (-)
+
+No.41
+expr : string(1)
+time : 0.000000 sec
+result: 1
+expect: value("1")
+judge : OK (-)
+
+No.42
+expr : string(-1)
+time : 0.000000 sec
+result: -1
+expect: value("-1")
+judge : OK (-)
+
+No.43
+expr : string(true())
+time : 0.016000 sec
+result: true
+expect: value("true")
+judge : OK (-)
+
+No.44
+expr : string(false())
+time : 0.000000 sec
+result: false
+expect: value("false")
+judge : OK (-)
+
+No.45
+expr : string-length("")
+time : 0.000000 sec
+result: 0
+expect: value(0)
+judge : OK (-)
+
+No.46
+expr : string-length("a")
+time : 0.000000 sec
+result: 1
+expect: value(1)
+judge : OK (-)
+
+No.47
+expr : contains("abcdefg", "def")
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.48
+expr : contains("abcdefg", "zzz")
+time : 0.000000 sec
+result: False
+expect: value(false)
+judge : OK (-)
+
+No.49
+expr : starts-with("abcdefg", "abc")
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.50
+expr : starts-with("abcdefg", "def")
+time : 0.000000 sec
+result: False
+expect: value(false)
+judge : OK (-)
+
+No.51
+expr : concat("abc", "def")
+time : 0.000000 sec
+result: abcdef
+expect: value("abcdef")
+judge : OK (-)
+
+No.52
+expr : concat("abc", "def", "ghi")
+time : 0.000000 sec
+result: abcdefghi
+expect: value("abcdefghi")
+judge : OK (-)
+
+No.53
+expr : concat("abc", "def", "ghi", "jkl")
+time : 0.000000 sec
+result: abcdefghijkl
+expect: value("abcdefghijkl")
+judge : OK (-)
+
+No.54
+expr : translate("bar","abc","ABC")
+time : 0.000000 sec
+result: BAr
+expect: value("BAr")
+judge : OK (-)
+
+No.55
+expr : translate("--aaa--","abc-","ABC")
+time : 0.000000 sec
+result: AAA
+expect: value("AAA")
+judge : OK (-)
+
+No.56
+expr : substring("12345", 2, 3)
+time : 0.000000 sec
+result: 234
+expect: value("234")
+judge : OK (-)
+
+No.57
+expr : substring("12345", 2)
+time : 0.000000 sec
+result: 2345
+expect: value("2345")
+judge : OK (-)
+
+No.58
+expr : substring("12345", 1.5, 2.6)
+time : 0.000000 sec
+result: 234
+expect: value("234")
+judge : OK (-)
+
+No.59
+expr : substring("12345", 0, 3)
+time : 0.000000 sec
+result: 12
+expect: value("12")
+judge : OK (-)
+
+No.60
+expr : substring("12345", 0 div 0, 3)
+time : 0.015000 sec
+result:
+expect: value("")
+judge : OK (-)
+
+No.61
+expr : substring("12345", 1, 0 div 0)
+time : 0.000000 sec
+result:
+expect: value("")
+judge : OK (-)
+
+No.62
+expr : substring("12345", -42, 1 div 0)
+time : 0.000000 sec
+result: 12345
+expect: value("12345")
+judge : OK (-)
+
+No.63
+expr : substring("12345", -1 div 0, 1 div 0)
+time : 0.000000 sec
+result:
+expect: value("")
+judge : OK (-)
+
+No.64
+expr : substring-after("1999/04/01","/")
+time : 0.000000 sec
+result: 04/01
+expect: value("04/01")
+judge : OK (-)
+
+No.65
+expr : substring-after("1999/04/01","19")
+time : 0.000000 sec
+result: 99/04/01
+expect: value("99/04/01")
+judge : OK (-)
+
+No.66
+expr : substring-before("1999/04/01","/")
+time : 0.000000 sec
+result: 1999
+expect: value("1999")
+judge : OK (-)
+
+No.67
+expr : normalize-space(id("numbers")/li) = "1"
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.68
+expr : id("numbers")/li = id("numbers")/li
+time : 0.016000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.69
+expr : "" = false()
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.70
+expr : false() = ""
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.71
+expr : "1" = 1
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.72
+expr : 1 = "1"
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.73
+expr : "1" = "1"
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0002.txt b/BSXPath_ver001e/testbsxresult/r0002.txt
new file mode 100644
index 0000000..c874cc1
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0002.txt
@@ -0,0 +1,587 @@
+[0002]
+Basic Functional Test
+
+No.1
+expr : .//blockquote/*
+time : 0.015000 sec
+result: <br id=n13 class=10> <p id=n14 class=13> <font id=n17 class=14>
+expect: br p font
+judge : OK (-)
+
+No.2
+expr : .//blockquote/child::*
+time : 0.000000 sec
+result: <br id=n13 class=10> <p id=n14 class=13> <font id=n17 class=14>
+expect: br p font
+judge : OK (-)
+
+No.3
+expr : .//blockquote/parent::*
+time : 0.000000 sec
+result: <center id=n5 class=22>
+expect: center
+judge : OK (-)
+
+No.4
+expr : .//blockquote/descendant::*
+time : 0.000000 sec
+result: <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14>
+expect: br p del ins font
+judge : OK (-)
+
+No.5
+expr : .//blockquote/descendant-or-self::*
+time : 0.000000 sec
+result: <blockquote id=n12 class=15> <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14>
+expect: blockquote br p del ins font
+judge : OK (-)
+
+No.6
+expr : .//blockquote/ancestor::*
+time : 0.000000 sec
+result: <html> <body> <div id=n1 class=26> <center id=n5 class=22>
+expect: html body div center
+judge : OK (-)
+
+No.7
+expr : .//blockquote/ancestor-or-self::*
+time : 0.000000 sec
+result: <html> <body> <div id=n1 class=26> <center id=n5 class=22> <blockquote id=n12 class=15>
+expect: html body div center blockquote
+judge : OK (-)
+
+No.8
+expr : .//blockquote/following-sibling::*
+time : 0.000000 sec
+result: <h3 id=n18 class=18> <h4 id=n21 class=21>
+expect: h3 h4
+judge : OK (-)
+
+No.9
+expr : .//blockquote/preceding-sibling::*
+time : 0.015000 sec
+result: <h1 id=n6 class=6> <h2 id=n9 class=9>
+expect: h1 h2
+judge : OK (-)
+
+No.10
+expr : .//blockquote/following::*
+time : 0.000000 sec
+result: <h3 id=n18 class=18> <dfn id=n19 class=16> <a id=n20 class=17> <h4 id=n21 class=21> <sub id=n22 class=19> <sup id=n23 class=20> <span id=n24 class=25> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: h3 dfn a h4 sub sup span acronym q
+judge : OK (-)
+
+No.11
+expr : .//blockquote/preceding::*
+time : 0.016000 sec
+result: <head> <title> <dl id=n2 class=3> <dt id=n3 class=1> <dd id=n4 class=2> <h1 id=n6 class=6> <em id=n7 class=4> <strong id=n8 class=5> <h2 id=n9 class=9> <b id=n10 class=7> <s id=n11 class=8>
+expect: head title dl dt dd h1 em strong h2 b s
+judge : OK (-)
+
+No.12
+expr : .//blockquote/self::*
+time : 0.000000 sec
+result: <blockquote id=n12 class=15>
+expect: blockquote
+judge : OK (-)
+
+No.13
+expr : .//blockquote/attribute::id/parent::*
+time : 0.016000 sec
+result: <blockquote id=n12 class=15>
+expect: blockquote
+judge : OK (-)
+
+No.14
+expr : .//blockquote/@id/parent::*
+time : 0.000000 sec
+result: <blockquote id=n12 class=15>
+expect: blockquote
+judge : OK (-)
+
+No.15
+expr : .//*[blockquote]
+time : 0.015000 sec
+result: <center id=n5 class=22>
+expect: center
+judge : OK (-)
+
+No.16
+expr : .//*[child::blockquote]
+time : 0.000000 sec
+result: <center id=n5 class=22>
+expect: center
+judge : OK (-)
+
+No.17
+expr : .//*[parent::blockquote]
+time : 0.000000 sec
+result: <br id=n13 class=10> <p id=n14 class=13> <font id=n17 class=14>
+expect: br p font
+judge : OK (-)
+
+No.18
+expr : .//*[descendant::blockquote]
+time : 0.032000 sec
+result: <div id=n1 class=26> <center id=n5 class=22>
+expect: div center
+judge : OK (-)
+
+No.19
+expr : .//*[descendant-or-self::blockquote]
+time : 0.015000 sec
+result: <div id=n1 class=26> <center id=n5 class=22> <blockquote id=n12 class=15>
+expect: div center blockquote
+judge : OK (-)
+
+No.20
+expr : .//*[ancestor::blockquote]
+time : 0.000000 sec
+result: <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14>
+expect: br p del ins font
+judge : OK (-)
+
+No.21
+expr : .//*[ancestor-or-self::blockquote]
+time : 0.015000 sec
+result: <blockquote id=n12 class=15> <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14>
+expect: blockquote br p del ins font
+judge : OK (-)
+
+No.22
+expr : .//*[following-sibling::blockquote]
+time : 0.015000 sec
+result: <h1 id=n6 class=6> <h2 id=n9 class=9>
+expect: h1 h2
+judge : OK (-)
+
+No.23
+expr : .//*[preceding-sibling::blockquote]
+time : 0.016000 sec
+result: <h3 id=n18 class=18> <h4 id=n21 class=21>
+expect: h3 h4
+judge : OK (-)
+
+No.24
+expr : .//*[following::blockquote]
+time : 0.047000 sec
+result: <dl id=n2 class=3> <dt id=n3 class=1> <dd id=n4 class=2> <h1 id=n6 class=6> <em id=n7 class=4> <strong id=n8 class=5> <h2 id=n9 class=9> <b id=n10 class=7> <s id=n11 class=8>
+expect: dl dt dd h1 em strong h2 b s
+judge : OK (-)
+
+No.25
+expr : .//*[preceding::blockquote]
+time : 0.047000 sec
+result: <h3 id=n18 class=18> <dfn id=n19 class=16> <a id=n20 class=17> <h4 id=n21 class=21> <sub id=n22 class=19> <sup id=n23 class=20> <span id=n24 class=25> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: h3 dfn a h4 sub sup span acronym q
+judge : OK (-)
+
+No.26
+expr : .//*[self::blockquote]
+time : 0.000000 sec
+result: <blockquote id=n12 class=15>
+expect: blockquote
+judge : OK (-)
+
+No.27
+expr : .//*[@id]
+time : 0.000000 sec
+result: <div id=n1 class=26> <dl id=n2 class=3> <dt id=n3 class=1> <dd id=n4 class=2> <center id=n5 class=22> <h1 id=n6 class=6> <em id=n7 class=4> <strong id=n8 class=5> <h2 id=n9 class=9> <b id=n10 class=7> <s id=n11 class=8> <blockquote id=n12 class=15> <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14> <h3 id=n18 class=18> <dfn id=n19 class=16> <a id=n20 class=17> <h4 id=n21 class=21> <sub id=n22 class=19> <sup id=n23 class=20> <span id=n24 class=25> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: div dl dt dd center h1 em strong h2 b s blockquote br p del ins font h3 dfn a h4 sub sup span acronym q
+judge : OK (-)
+
+No.28
+expr : .//*[attribute::id]
+time : 0.000000 sec
+result: <div id=n1 class=26> <dl id=n2 class=3> <dt id=n3 class=1> <dd id=n4 class=2> <center id=n5 class=22> <h1 id=n6 class=6> <em id=n7 class=4> <strong id=n8 class=5> <h2 id=n9 class=9> <b id=n10 class=7> <s id=n11 class=8> <blockquote id=n12 class=15> <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14> <h3 id=n18 class=18> <dfn id=n19 class=16> <a id=n20 class=17> <h4 id=n21 class=21> <sub id=n22 class=19> <sup id=n23 class=20> <span id=n24 class=25> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: div dl dt dd center h1 em strong h2 b s blockquote br p del ins font h3 dfn a h4 sub sup span acronym q
+judge : OK (-)
+
+No.29
+expr : .//blockquote/text()
+time : 0.000000 sec
+result: \n \n blockquoteText1:\n \n blockquoteText2\n \n \n \n
+expect: text('\n '):opera:gecko:applewebkit text(' '):netfront text('\n blockquoteText1:\n '):opera:gecko:applewebkit text('blockquoteText1: '):ie text(' blockquoteText1: '):netfront text('\n blockquoteText2\n '):opera:gecko:applewebkit text('blockquoteText2 '):ie text(' blockquoteText2 '):netfront text('\n '):opera text('\n '):opera text('\n \n '):gecko text('\n '):applewebkit text('\n '):opera:gecko:applewebkit text(' '):ie:netfront text(' '):netfront
+ (*) node number error: 6 vs 5
+judge : NG (text("\n") text("\n blockquoteText1:\n ") text("\n blockquoteText2\n ") text("\n") text("\n") text("\n"))
+
+No.30
+expr : .//blockquote/comment()
+time : 0.000000 sec
+result: <!--blockquoteComment-->
+expect: comment('blockquoteComment'):opera:gecko:applewebkit3:ie:netfront comment(' hoge'):ie
+judge : OK (-)
+
+No.31
+expr : .//blockquote/processing-instruction()
+time : 0.000000 sec
+result: <?pi hoge ??>
+expect: processing-instruction(pi='hoge '):opera92 processing-instruction(pi=' hoge '):opera95
+judge : OK (-)
+
+No.32
+expr : .//blockquote/processing-instruction("pi")
+time : 0.000000 sec
+result: <?pi hoge ??>
+expect: processing-instruction(pi='hoge '):opera92 processing-instruction(pi=' hoge '):opera95
+judge : OK (-)
+
+No.33
+expr : .//blockquote/node()
+time : 0.000000 sec
+result: \n <!--blockquoteComment--> \n blockquoteText1:\n <br id=n13 class=10> \n blockquoteText2\n <p id=n14 class=13> \n <?pi hoge ??> \n <font id=n17 class=14> \n
+expect: text('\n '):opera:gecko:applewebkit text(' '):netfront comment('blockquoteComment'):opera:gecko:ie:applewebkit3:netfront text('\n blockquoteText1:\n '):opera:gecko:applewebkit text('blockquoteText1: '):ie text(' blockquoteText1: '):netfront br text('\n blockquoteText2\n '):opera:gecko:applewebkit text('blockquoteText2 '):ie text(' blockquoteText2 '):netfront p text('\n '):opera comment(' hoge'):ie processing-instruction(pi='hoge '):opera92 processing-instruction(pi=' hoge '):opera95 text('\n '):opera text('\n \n '):gecko text('\n '):applewebkit text(' '):netfront font text('\n '):opera:gecko:applewebkit text(' '):ie:netfront
+ (*) node number error: 11 vs 10
+judge : NG (text("\n") comment("blockquoteComment") text("\n blockquoteText1:\n ") br text("\n blockquoteText2\n ") p text("\n") processing-instruction(pi=" hoge ") text("\n") font text("\n"))
+
+No.34
+expr : .//blockquote/p
+time : 0.000000 sec
+result: <p id=n14 class=13>
+expect: p
+judge : OK (-)
+
+No.35
+expr : .//blockquote/*
+time : 0.000000 sec
+result: <br id=n13 class=10> <p id=n14 class=13> <font id=n17 class=14>
+expect: br p font
+judge : OK (-)
+
+No.36
+expr : .//*[child::* and preceding::font]
+time : 0.063000 sec
+result: <h3 id=n18 class=18> <h4 id=n21 class=21> <span id=n24 class=25>
+expect: h3 h4 span
+judge : OK (-)
+
+No.37
+expr : .//*[not(child::*) and preceding::font]
+time : 0.062000 sec
+result: <dfn id=n19 class=16> <a id=n20 class=17> <sub id=n22 class=19> <sup id=n23 class=20> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: dfn a sub sup acronym q
+judge : OK (-)
+
+No.38
+expr : .//*[preceding::blockquote or following::blockquote]
+time : 0.109000 sec
+result: <dl id=n2 class=3> <dt id=n3 class=1> <dd id=n4 class=2> <h1 id=n6 class=6> <em id=n7 class=4> <strong id=n8 class=5> <h2 id=n9 class=9> <b id=n10 class=7> <s id=n11 class=8> <h3 id=n18 class=18> <dfn id=n19 class=16> <a id=n20 class=17> <h4 id=n21 class=21> <sub id=n22 class=19> <sup id=n23 class=20> <span id=n24 class=25> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: dl dt dd h1 em strong h2 b s h3 dfn a h4 sub sup span acronym q
+judge : OK (-)
+
+No.39
+expr : .//blockquote/ancestor::* | .//blockquote/descendant::*
+time : 0.000000 sec
+result: <html> <body> <div id=n1 class=26> <center id=n5 class=22> <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14>
+expect: html body div center br p del ins font
+judge : OK (-)
+
+No.40
+expr : .//*[.="sub"]
+time : 0.016000 sec
+result: <sub id=n22 class=19>
+expect: sub
+judge : OK (-)
+
+No.41
+expr : .//*[@title > 12 and @class < 15]
+time : 0.032000 sec
+result: <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14>
+expect: br p del ins font
+judge : OK (-)
+
+No.42
+expr : .//*[@title != @class]
+time : 0.015000 sec
+result: <div id=n1 class=26> <dl id=n2 class=3> <dt id=n3 class=1> <dd id=n4 class=2> <center id=n5 class=22> <em id=n7 class=4> <strong id=n8 class=5> <b id=n10 class=7> <s id=n11 class=8> <blockquote id=n12 class=15> <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14> <dfn id=n19 class=16> <a id=n20 class=17> <sub id=n22 class=19> <sup id=n23 class=20> <span id=n24 class=25> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: div dl dt dd center em strong b s blockquote br p del ins font dfn a sub sup span acronym q
+judge : OK (-)
+
+No.43
+expr : .//*[((@class * @class + @title * @title) div (@class + @title)) > ((@class - @title) * (@class - @title))]
+time : 0.031000 sec
+result: <dl id=n2 class=3> <h1 id=n6 class=6> <h2 id=n9 class=9> <s id=n11 class=8> <blockquote id=n12 class=15> <br id=n13 class=10> <p id=n14 class=13> <font id=n17 class=14> <h3 id=n18 class=18> <dfn id=n19 class=16> <a id=n20 class=17> <h4 id=n21 class=21> <sub id=n22 class=19> <sup id=n23 class=20> <span id=n24 class=25> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: dl h1 h2 s blockquote br p font h3 dfn a h4 sub sup span acronym q
+judge : OK (-)
+
+No.44
+expr : .//*[@title mod 2 = 0]
+time : 0.016000 sec
+result: <dl id=n2 class=3> <dd id=n4 class=2> <h1 id=n6 class=6> <strong id=n8 class=5> <b id=n10 class=7> <blockquote id=n12 class=15> <p id=n14 class=13> <ins id=n16 class=12> <h3 id=n18 class=18> <a id=n20 class=17> <sub id=n22 class=19> <span id=n24 class=25> <q id=n26 class=24>
+expect: dl dd h1 strong b blockquote p ins h3 a sub span q
+judge : OK (-)
+
+No.45
+expr : .//blockquote/child::*[last()]
+time : 0.000000 sec
+result: <font id=n17 class=14>
+expect: font
+judge : OK (-)
+
+No.46
+expr : .//blockquote/descendant::*[position() < 4]
+time : 0.000000 sec
+result: <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11>
+expect: br p del
+judge : OK (-)
+
+No.47
+expr : id(.//font/@face)
+time : 0.000000 sec
+result: <strong id=n8 class=5> <q id=n26 class=24>
+expect: strong q
+judge : OK (-)
+
+No.48
+expr : .//*[name(.) = "sub"]
+time : 0.000000 sec
+result: <sub id=n22 class=19>
+expect: sub
+judge : OK (-)
+
+No.49
+expr : .//*[name() = "sub"]
+time : 0.016000 sec
+result: <sub id=n22 class=19>
+expect: sub
+judge : OK (-)
+
+No.50
+expr : .//blockquote/child::*[2]
+time : 0.000000 sec
+result: <p id=n14 class=13>
+expect: p
+judge : OK (-)
+
+No.51
+expr : .//blockquote/descendant::*[4]
+time : 0.000000 sec
+result: <ins id=n16 class=12>
+expect: ins
+judge : OK (-)
+
+No.52
+expr : .//blockquote/descendant-or-self::*[4]
+time : 0.000000 sec
+result: <del id=n15 class=11>
+expect: del
+judge : OK (-)
+
+No.53
+expr : .//blockquote/ancestor::*[2]
+time : 0.000000 sec
+result: <div id=n1 class=26>
+expect: div
+judge : OK (-)
+
+No.54
+expr : .//blockquote/ancestor-or-self::*[2]
+time : 0.000000 sec
+result: <center id=n5 class=22>
+expect: center
+judge : OK (-)
+
+No.55
+expr : .//blockquote/following-sibling::*[1]
+time : 0.000000 sec
+result: <h3 id=n18 class=18>
+expect: h3
+judge : OK (-)
+
+No.56
+expr : .//blockquote/preceding-sibling::*[1]
+time : 0.015000 sec
+result: <h2 id=n9 class=9>
+expect: h2
+judge : OK (-)
+
+No.57
+expr : .//blockquote/following::*[4]
+time : 0.000000 sec
+result: <h4 id=n21 class=21>
+expect: h4
+judge : OK (-)
+
+No.58
+expr : .//blockquote/preceding::*[4]
+time : 0.000000 sec
+result: <strong id=n8 class=5>
+expect: strong
+judge : OK (-)
+
+No.59
+expr : .//*[starts-with(.,"s")]
+time : 0.016000 sec
+result: <strong id=n8 class=5> <s id=n11 class=8> <sub id=n22 class=19> <sup id=n23 class=20>
+expect: strong s h4:ie sub sup
+judge : OK (-)
+
+No.60
+expr : .//*[string(@title - 1) = "0"]
+time : 0.016000 sec
+result: <div id=n1 class=26>
+expect: div
+judge : OK (-)
+
+No.61
+expr : .//*[string() = "sub"]
+time : 0.016000 sec
+result: <sub id=n22 class=19>
+expect: sub
+judge : OK (-)
+
+No.62
+expr : .//*[string(.) = "sub"]
+time : 0.016000 sec
+result: <sub id=n22 class=19>
+expect: sub
+judge : OK (-)
+
+No.63
+expr : .//*[normalize-space(concat(.,..)) = "sub sub sup"]
+time : 0.062000 sec
+result: <sub id=n22 class=19>
+expect: sub:opera:gecko:applewebkit:netfront
+judge : OK (-)
+
+No.64
+expr : .//sub[concat(.,..) = "subsub sup "]
+time : 0.000000 sec
+result:
+expect: sub:ie
+judge : OK (-)
+
+No.65
+expr : .//node()[normalize-space(concat(.,..,../..)) = "bb b s"]
+time : 0.328000 sec
+result: b
+expect: text('b'):opera:gecko:applewebkit:netfront
+judge : OK (-)
+
+No.66
+expr : .//node()[concat(.,..,../..) = "bbb s "]
+time : 0.328000 sec
+result:
+expect: text('b'):ie
+judge : OK (-)
+
+No.67
+expr : .//*[substring-before(.,"u") = "s"]
+time : 0.015000 sec
+result: <sub id=n22 class=19> <sup id=n23 class=20>
+expect: h4:ie sub sup
+judge : OK (-)
+
+No.68
+expr : .//*[substring-after(.,"on") = "t"]
+time : 0.016000 sec
+result: <font id=n17 class=14>
+expect: font
+judge : OK (-)
+
+No.69
+expr : .//*[substring(.,2,1) = "u"]
+time : 0.016000 sec
+result: <sub id=n22 class=19> <sup id=n23 class=20>
+expect: h4:ie sub sup
+judge : OK (-)
+
+No.70
+expr : .//*[substring(.,2) = "up"]
+time : 0.015000 sec
+result: <sup id=n23 class=20>
+expect: sup
+judge : OK (-)
+
+No.71
+expr : .//*[contains(.,"b")]
+time : 0.015000 sec
+result: <div id=n1 class=26> <center id=n5 class=22> <h2 id=n9 class=9> <b id=n10 class=7> <blockquote id=n12 class=15> <h4 id=n21 class=21> <sub id=n22 class=19>
+expect: div center h2 b blockquote h4 sub
+judge : OK (-)
+
+No.72
+expr : .//*[name() != 'dt' and name() != 'dd' and string-length() = 3]
+time : 0.016000 sec
+result: <del id=n15 class=11> <ins id=n16 class=12> <dfn id=n19 class=16> <sub id=n22 class=19> <sup id=n23 class=20>
+expect: del ins dfn sub sup
+judge : OK (-)
+
+No.73
+expr : .//*[string-length(normalize-space(.)) = 3]
+time : 0.016000 sec
+result: <h2 id=n9 class=9> <del id=n15 class=11> <ins id=n16 class=12> <dfn id=n19 class=16> <sub id=n22 class=19> <sup id=n23 class=20>
+expect: h2 del ins dfn sub sup
+judge : OK (-)
+
+No.74
+expr : .//*[.=translate(normalize-space(" s u b ")," ","")]
+time : 0.015000 sec
+result: <sub id=n22 class=19>
+expect: sub
+judge : OK (-)
+
+No.75
+expr : .//*[normalize-space()="q"]
+time : 0.015000 sec
+result: <q id=n26 class=24>
+expect: q
+judge : OK (-)
+
+No.76
+expr : .//*[boolean(@title - 1) = false()]
+time : 0.000000 sec
+result: <div id=n1 class=26>
+expect: div
+judge : OK (-)
+
+No.77
+expr : .//*[not(@title - 1) = true()]
+time : 0.000000 sec
+result: <div id=n1 class=26>
+expect: div
+judge : OK (-)
+
+No.78
+expr : .//*[number(@title) < number(@class)]
+time : 0.000000 sec
+result: <div id=n1 class=26> <dl id=n2 class=3> <center id=n5 class=22> <blockquote id=n12 class=15> <span id=n24 class=25>
+expect: div dl center blockquote span
+judge : OK (-)
+
+No.79
+expr : .//*[sum(ancestor::*/@title) < sum(descendant::*/@title)]
+time : 0.047000 sec
+result: <div id=n1 class=26> <dl id=n2 class=3> <center id=n5 class=22> <h1 id=n6 class=6> <h2 id=n9 class=9> <blockquote id=n12 class=15> <p id=n14 class=13> <h3 id=n18 class=18> <h4 id=n21 class=21> <span id=n24 class=25>
+expect: div dl center h1 h2 blockquote p h3 h4 span
+judge : OK (-)
+
+No.80
+expr : .//*[floor(@title div @class) = 1]
+time : 0.016000 sec
+result: <h1 id=n6 class=6> <em id=n7 class=4> <strong id=n8 class=5> <h2 id=n9 class=9> <b id=n10 class=7> <s id=n11 class=8> <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14> <h3 id=n18 class=18> <dfn id=n19 class=16> <a id=n20 class=17> <h4 id=n21 class=21> <sub id=n22 class=19> <sup id=n23 class=20> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: h1 em strong h2 b s br p del ins font h3 dfn a h4 sub sup acronym q
+judge : OK (-)
+
+No.81
+expr : .//*[ceiling(@title div @class) = 1]
+time : 0.000000 sec
+result: <div id=n1 class=26> <dl id=n2 class=3> <center id=n5 class=22> <h1 id=n6 class=6> <h2 id=n9 class=9> <blockquote id=n12 class=15> <h3 id=n18 class=18> <h4 id=n21 class=21> <span id=n24 class=25>
+expect: div dl center h1 h2 blockquote h3 h4 span
+judge : OK (-)
+
+No.82
+expr : .//*[round(@title div @class) = 1]
+time : 0.016000 sec
+result: <dl id=n2 class=3> <h1 id=n6 class=6> <h2 id=n9 class=9> <b id=n10 class=7> <s id=n11 class=8> <blockquote id=n12 class=15> <br id=n13 class=10> <p id=n14 class=13> <del id=n15 class=11> <ins id=n16 class=12> <font id=n17 class=14> <h3 id=n18 class=18> <dfn id=n19 class=16> <a id=n20 class=17> <h4 id=n21 class=21> <sub id=n22 class=19> <sup id=n23 class=20> <span id=n24 class=25> <acronym id=n25 class=23> <q id=n26 class=24>
+expect: dl h1 h2 b s blockquote br p del ins font h3 dfn a h4 sub sup span acronym q
+judge : OK (-)
+
+No.83
+expr : /..
+time : 0.000000 sec
+result:
+expect: (none)
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0003.txt b/BSXPath_ver001e/testbsxresult/r0003.txt
new file mode 100644
index 0000000..cfa8a62
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0003.txt
@@ -0,0 +1,88 @@
+[0003]
+Sort and Merge Test
+
+No.1
+expr : id("container")/*[1]
+time : 0.000000 sec
+result: <li id=li-1>
+expect: li#li-1
+judge : OK (-)
+
+No.2
+expr : id("container")/*[2]
+time : 0.000000 sec
+result: <li id=li-2>
+expect: li#li-2
+judge : OK (-)
+
+No.3
+expr : id("container")/*[3]
+time : 0.000000 sec
+result: <li id=li-3>
+expect: li#li-3
+judge : OK (-)
+
+No.4
+expr : id("container")/*[4]
+time : 0.000000 sec
+result: <li id=li-4>
+expect: li#li-4
+judge : OK (-)
+
+No.5
+expr : id("container")/*[3] | id("container")/*[4] | id("container")/*[2] |id("container")/*[1]
+time : 0.016000 sec
+result: <li id=li-1> <li id=li-2> <li id=li-3> <li id=li-4>
+expect: li#li-1 li#li-2 li#li-3 li#li-4
+judge : OK (-)
+
+No.6
+expr : id("container")/*[4] | id("container")/*[2] | id("container")/*[4] |id("container")/*[3]
+time : 0.015000 sec
+result: <li id=li-2> <li id=li-3> <li id=li-4>
+expect: li#li-2 li#li-3 li#li-4
+judge : OK (-)
+
+No.7
+expr : id("li-1 li-2 li-3 li-4")
+time : 0.000000 sec
+result: <li id=li-1> <li id=li-2> <li id=li-3> <li id=li-4>
+expect: li#li-1 li#li-2 li#li-3 li#li-4
+judge : OK (-)
+
+No.8
+expr : id("li-4 li-3 li-2 li-1")
+time : 0.016000 sec
+result: <li id=li-1> <li id=li-2> <li id=li-3> <li id=li-4>
+expect: li#li-1 li#li-2 li#li-3 li#li-4
+judge : OK (-)
+
+No.9
+expr : id("li-2 li-2 li-1 li-1")
+time : 0.016000 sec
+result: <li id=li-1> <li id=li-2>
+expect: li#li-1 li#li-2
+judge : OK (-)
+
+No.10
+expr : id("container")/* | id("container-0")/*
+time : 0.015000 sec
+result: <li id=li-1> <li id=li-2> <li id=li-3> <li id=li-4> <li id=li-5> <li id=li-6> <li id=li-7> <li id=li-8>
+expect: li#li-1 li#li-2 li#li-3 li#li-4 li#li-5 li#li-6 li#li-7 li#li-8
+judge : OK (-)
+
+No.11
+expr : id("container-0")/* | id("container")/*
+time : 0.016000 sec
+result: <li id=li-1> <li id=li-2> <li id=li-3> <li id=li-4> <li id=li-5> <li id=li-6> <li id=li-7> <li id=li-8>
+expect: li#li-1 li#li-2 li#li-3 li#li-4 li#li-5 li#li-6 li#li-7 li#li-8
+judge : OK (-)
+
+No.12
+expr : id("container-0")/* | id("container")/* | id("container-0")/*
+time : 0.000000 sec
+result: <li id=li-1> <li id=li-2> <li id=li-3> <li id=li-4> <li id=li-5> <li id=li-6> <li id=li-7> <li id=li-8>
+expect: li#li-1 li#li-2 li#li-3 li#li-4 li#li-5 li#li-6 li#li-7 li#li-8
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0004.txt b/BSXPath_ver001e/testbsxresult/r0004.txt
new file mode 100644
index 0000000..b3bdad9
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0004.txt
@@ -0,0 +1,53 @@
+[0004]
+Double-Slash and Descendant Test
+
+No.1
+expr : /descendant::div
+time : 0.000000 sec
+result: <div class=parent> <div class=child first> <div class=grand-child first-1> <div class=grand-child> <div class=grand-child> <div class=child> <div class=grand-child first-2> <div class=grand-child> <div class=grand-child>
+expect: div.parent div.child div.grand-child div.grand-child div.grand-child div.child div.grand-child div.grand-child div.grand-child
+judge : OK (-)
+
+No.2
+expr : //body/descendant::*
+time : 0.015000 sec
+result: <div class=parent> <div class=child first> <div class=grand-child first-1> <p> <div class=grand-child> <p> <div class=grand-child> <p> <div class=child> <div class=grand-child first-2> <p> <div class=grand-child> <p> <div class=grand-child>
+expect: div.parent div.child div.grand-child p div.grand-child p div.grand-child p div.child div.grand-child p div.grand-child p div.grand-child
+judge : OK (-)
+
+No.3
+expr : /descendant::div[1]
+time : 0.000000 sec
+result: <div class=parent>
+expect: div.parent
+judge : OK (-)
+
+No.4
+expr : //div
+time : 0.000000 sec
+result: <div class=parent> <div class=child first> <div class=grand-child first-1> <div class=grand-child> <div class=grand-child> <div class=child> <div class=grand-child first-2> <div class=grand-child> <div class=grand-child>
+expect: div.parent div.child div.grand-child div.grand-child div.grand-child div.child div.grand-child div.grand-child div.grand-child
+judge : OK (-)
+
+No.5
+expr : //body//*
+time : 0.000000 sec
+result: <div class=parent> <div class=child first> <div class=grand-child first-1> <p> <div class=grand-child> <p> <div class=grand-child> <p> <div class=child> <div class=grand-child first-2> <p> <div class=grand-child> <p> <div class=grand-child>
+expect: div.parent div.child div.grand-child p div.grand-child p div.grand-child p div.child div.grand-child p div.grand-child p div.grand-child
+judge : OK (-)
+
+No.6
+expr : //div[1]
+time : 0.000000 sec
+result: <div class=parent> <div class=child first> <div class=grand-child first-1> <div class=grand-child first-2>
+expect: div.parent div.child.first div.grand-child.first-1 div.grand-child.first-2
+judge : OK (-)
+
+No.7
+expr : //div[contains(@class, 'grand-child')]
+time : 0.000000 sec
+result: <div class=grand-child first-1> <div class=grand-child> <div class=grand-child> <div class=grand-child first-2> <div class=grand-child> <div class=grand-child>
+expect: div.grand-child div.grand-child div.grand-child div.grand-child div.grand-child div.grand-child
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0005.txt b/BSXPath_ver001e/testbsxresult/r0005.txt
new file mode 100644
index 0000000..8eafc6a
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0005.txt
@@ -0,0 +1,494 @@
+[0005]
+Attribute Test
+
+No.1
+expr : //blockquote["http://coderepos.org/"=@cite]
+time : 0.000000 sec
+result: <blockquote>
+expect: blockquote
+judge : OK (-)
+
+No.2
+expr : /descendant::*["CodeRepos"=@title]
+time : 0.000000 sec
+result: <blockquote> <a>
+expect: blockquote a
+judge : OK (-)
+
+No.3
+expr : //*[@class]
+time : 0.000000 sec
+result: <input id=bar class=input-1> <input id=foo class=input-2> <img id=fuga class=img-1> <img id=hoge class=img-2> <cite class=cite site>
+expect: input input img img cite
+judge : OK (-)
+
+No.4
+expr : /descendant::node()[@title]
+time : 0.016000 sec
+result: <blockquote> <p id=paragraph> <a>
+expect: blockquote p a
+judge : OK (-)
+
+No.5
+expr : //body/*[@title]
+time : 0.000000 sec
+result: <blockquote>
+expect: blockquote
+judge : OK (-)
+
+No.6
+expr : //blockquote/node()[@title]
+time : 0.016000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.7
+expr : //cite[@class="cite"]
+time : 0.000000 sec
+result:
+expect:
+judge : OK (-)
+
+No.8
+expr : //cite[@class="site"]
+time : 0.000000 sec
+result:
+expect:
+judge : OK (-)
+
+No.9
+expr : //cite[@class="cite site"]
+time : 0.015000 sec
+result: <cite class=cite site>
+expect: cite
+judge : OK (-)
+
+No.10
+expr : //*[@id="paragraph"]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.11
+expr : //body//*[@id="paragraph"]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.12
+expr : //*[@id="bar"]
+time : 0.016000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.13
+expr : //*[@name="foo"]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.14
+expr : //*[@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.15
+expr : //*[@name="bar"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.16
+expr : //p/node()[@id="bar"]
+time : 0.015000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.17
+expr : //p/node()[@name="foo"]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.18
+expr : //p/node()[@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.19
+expr : //p/node()[@name="bar"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.20
+expr : id("pSib")/following-sibling::*[@id][1]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.21
+expr : id("nSib")/preceding-sibling::*[@id][1]
+time : 0.000000 sec
+result: <img id=hoge class=img-2>
+expect: img.img-2
+judge : OK (-)
+
+No.22
+expr : id("pSib")/following-sibling::*[@id="foo"]
+time : 0.015000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.23
+expr : id("nSib")/preceding-sibling::*[@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.24
+expr : id("pSib")/following::*[@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.25
+expr : id("nSib")/preceding::*[@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.26
+expr : /descendant::*[@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.27
+expr : /descendant-or-self::*[@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.28
+expr : id("hoge")/self::*[@id="hoge"]
+time : 0.000000 sec
+result: <img id=hoge class=img-2>
+expect: img.img-2
+judge : OK (-)
+
+No.29
+expr : id("foo")/self::*[@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.30
+expr : id("foo")/parent::*[@id="paragraph"]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.31
+expr : id("foo")/ancestor::*[@id="paragraph"]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.32
+expr : id("foo")/ancestor-or-self::*[@id="paragraph"]
+time : 0.016000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.33
+expr : //*[./@title="CodeRepos"]
+time : 0.000000 sec
+result: <blockquote> <a>
+expect: blockquote a
+judge : OK (-)
+
+No.34
+expr : //node()[./@class]
+time : 0.015000 sec
+result: <input id=bar class=input-1> <input id=foo class=input-2> <img id=fuga class=img-1> <img id=hoge class=img-2> <cite class=cite site>
+expect: input input img img cite
+judge : OK (-)
+
+No.35
+expr : /descendant::node()[./@title]
+time : 0.016000 sec
+result: <blockquote> <p id=paragraph> <a>
+expect: blockquote p a
+judge : OK (-)
+
+No.36
+expr : /descendant::blockquote/*[./@title]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.37
+expr : //blockquote[@*="http://coderepos.org/"]
+time : 0.000000 sec
+result: <blockquote>
+expect: blockquote
+judge : OK (-)
+
+No.38
+expr : //node()[@*="http://coderepos.org/"]
+time : 0.016000 sec
+result: <link> <blockquote> <a>
+expect: link blockquote a
+judge : OK (-)
+
+No.39
+expr : //*[./@*="http://coderepos.org/"]
+time : 0.015000 sec
+result: <link> <blockquote> <a>
+expect: link blockquote a
+judge : OK (-)
+
+No.40
+expr : //*[(@href|@cite)="http://coderepos.org/"]
+time : 0.000000 sec
+result: <link> <blockquote> <a>
+expect: link blockquote a
+judge : OK (-)
+
+No.41
+expr : count(//blockquote/@*) = count(//blockquote/@* | //blockquote/@*)
+time : 0.000000 sec
+result: True
+expect: value(true)
+judge : OK (-)
+
+No.42
+expr : //cite[./@class="cite"]
+time : 0.000000 sec
+result:
+expect:
+judge : OK (-)
+
+No.43
+expr : //cite[./@class="site"]
+time : 0.000000 sec
+result:
+expect:
+judge : OK (-)
+
+No.44
+expr : //cite[./@class="cite site"]
+time : 0.000000 sec
+result: <cite class=cite site>
+expect: cite
+judge : OK (-)
+
+No.45
+expr : //*[./@id="paragraph"]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.46
+expr : //blockquote//*[./@id="paragraph"]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.47
+expr : //*[./@id="bar"]
+time : 0.015000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.48
+expr : //*[./@name="foo"]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.49
+expr : //*[./@id="foo"]
+time : 0.016000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.50
+expr : //*[./@name="bar"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.51
+expr : //p/node()[./@id="bar"]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.52
+expr : //p/node()[./@name="foo"]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.53
+expr : //p/node()[./@id="foo"]
+time : 0.016000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.54
+expr : //p/node()[./@name="bar"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.55
+expr : //node()[./@id="bar"]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.56
+expr : //node()[./@name="foo"]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.57
+expr : //node()[./@id="foo"]
+time : 0.015000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.58
+expr : //node()[./@name="bar"]
+time : 0.016000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.59
+expr : id("pSib")/following-sibling::*[./@id][1]
+time : 0.000000 sec
+result: <input id=bar class=input-1>
+expect: input.input-1
+judge : OK (-)
+
+No.60
+expr : id("nSib")/preceding-sibling::*[./@id][1]
+time : 0.000000 sec
+result: <img id=hoge class=img-2>
+expect: img.img-2
+judge : OK (-)
+
+No.61
+expr : id("pSib")/following-sibling::*[./@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.62
+expr : id("nSib")/preceding-sibling::*[./@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.63
+expr : id("pSib")/following::*[./@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.64
+expr : id("nSib")/preceding::*[./@id="foo"]
+time : 0.015000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.65
+expr : /descendant::*[./@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.66
+expr : /descendant-or-self::*[./@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.67
+expr : id("foo")/self::*[./@id="foo"]
+time : 0.000000 sec
+result: <input id=foo class=input-2>
+expect: input.input-2
+judge : OK (-)
+
+No.68
+expr : id("foo")/parent::*[./@id="paragraph"]
+time : 0.016000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.69
+expr : id("foo")/ancestor::*[./@id="paragraph"]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+No.70
+expr : id("foo")/ancestor-or-self::*[./@id="paragraph"]
+time : 0.000000 sec
+result: <p id=paragraph>
+expect: p
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0006.txt b/BSXPath_ver001e/testbsxresult/r0006.txt
new file mode 100644
index 0000000..68ebbc5
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0006.txt
@@ -0,0 +1,172 @@
+[0006]
+Descendant Test
+
+No.1
+expr : //*
+time : 0.000000 sec
+result: <html> <head> <title> <body> <h1>
+expect: html head title body h1
+judge : OK (-)
+
+No.2
+expr : //node()
+time : 0.015000 sec
+result: <html> <head> <title> title <body> <h1> foo
+expect: html head title text("title"):gecko:opera:applewebkit:netfront body h1 text("foo")
+judge : OK (-)
+
+No.3
+expr : /descendant::*
+time : 0.000000 sec
+result: <html> <head> <title> <body> <h1>
+expect: html head title body h1
+judge : OK (-)
+
+No.4
+expr : /descendant::node()
+time : 0.000000 sec
+result: <html> <head> <title> title <body> <h1> foo
+expect: html head title text("title"):gecko:opera:applewebkit:netfront body h1 text("foo")
+judge : OK (-)
+
+No.5
+expr : /descendant-or-self::*
+time : 0.000000 sec
+result: <html> <head> <title> <body> <h1>
+expect: html head title body h1
+judge : OK (-)
+
+No.6
+expr : /descendant-or-self::node()
+time : 0.000000 sec
+result: <[document]> <html> <head> <title> title <body> <h1> foo
+expect: document() html head title text("title"):gecko:opera:applewebkit:netfront body h1 text("foo")
+judge : OK (-)
+
+No.7
+expr : //*//*
+time : 0.000000 sec
+result: <head> <title> <body> <h1>
+expect: head title body h1
+judge : OK (-)
+
+No.8
+expr : //node()//node()
+time : 0.016000 sec
+result: <head> <title> title <body> <h1> foo
+expect: head title text("title"):gecko:opera:applewebkit:netfront body h1 text("foo")
+judge : OK (-)
+
+No.9
+expr : //*/descendant::*
+time : 0.000000 sec
+result: <head> <title> <body> <h1>
+expect: head title body h1
+judge : OK (-)
+
+No.10
+expr : //node()/descendant::node()
+time : 0.015000 sec
+result: <head> <title> title <body> <h1> foo
+expect: head title text("title"):gecko:opera:applewebkit:netfront body h1 text("foo")
+judge : OK (-)
+
+No.11
+expr : //*/descendant-or-self::*
+time : 0.000000 sec
+result: <html> <head> <title> <body> <h1>
+expect: html head title body h1
+judge : OK (-)
+
+No.12
+expr : //node()/descendant-or-self::node()
+time : 0.016000 sec
+result: <html> <head> <title> title <body> <h1> foo
+expect: html head title text("title"):gecko:opera:applewebkit:netfront body h1 text("foo")
+judge : OK (-)
+
+No.13
+expr : //*[1]
+time : 0.000000 sec
+result: <html> <head> <title> <h1>
+expect: html head title h1
+judge : OK (-)
+
+No.14
+expr : //node()[1]
+time : 0.000000 sec
+result: <html> <head> <title> title <h1> foo
+expect: html head title text("title"):gecko:opera:applewebkit:netfront h1 text("foo")
+judge : OK (-)
+
+No.15
+expr : /descendant::*[1]
+time : 0.000000 sec
+result: <html>
+expect: html
+judge : OK (-)
+
+No.16
+expr : /descendant::node()[1]
+time : 0.000000 sec
+result: <html>
+expect: html
+judge : OK (-)
+
+No.17
+expr : /descendant-or-self::*[1]
+time : 0.000000 sec
+result: <html>
+expect: html
+judge : OK (-)
+
+No.18
+expr : /descendant-or-self::node()[1]
+time : 0.000000 sec
+result: <[document]>
+expect: document()
+judge : OK (-)
+
+No.19
+expr : //*//*[1]
+time : 0.015000 sec
+result: <head> <title> <h1>
+expect: head title h1
+judge : OK (-)
+
+No.20
+expr : //node()//node()[1]
+time : 0.000000 sec
+result: <head> <title> title <h1> foo
+expect: head title text("title"):gecko:opera:applewebkit:netfront h1 text("foo")
+judge : OK (-)
+
+No.21
+expr : //*/descendant::*[1]
+time : 0.000000 sec
+result: <head> <title> <h1>
+expect: head title h1
+judge : OK (-)
+
+No.22
+expr : //node()/descendant::node()[1]
+time : 0.000000 sec
+result: <head> <title> title <h1> foo
+expect: head title text("title"):gecko:opera:applewebkit:netfront h1 text("foo")
+judge : OK (-)
+
+No.23
+expr : //*/descendant-or-self::*[1]
+time : 0.000000 sec
+result: <html> <head> <title> <body> <h1>
+expect: html head title body h1
+judge : OK (-)
+
+No.24
+expr : //node()/descendant-or-self::node()[1]
+time : 0.000000 sec
+result: <html> <head> <title> title <body> <h1> foo
+expect: html head title text("title"):gecko:opera:applewebkit:netfront body h1 text("foo")
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0007.txt b/BSXPath_ver001e/testbsxresult/r0007.txt
new file mode 100644
index 0000000..6a9ac03
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0007.txt
@@ -0,0 +1,116 @@
+[0007]
+Ancestor Test
+
+No.1
+expr : id("t")/ancestor::*
+time : 0.000000 sec
+result: <html> <body>
+expect: html body
+judge : OK (-)
+
+No.2
+expr : id("t")/ancestor::node()
+time : 0.016000 sec
+result: <[document]> <html> <body>
+expect: document() html body
+judge : OK (-)
+
+No.3
+expr : id("t")/ancestor-or-self::*
+time : 0.000000 sec
+result: <html> <body> <h1 id=t>
+expect: html body h1
+judge : OK (-)
+
+No.4
+expr : id("t")/ancestor-or-self::node()
+time : 0.000000 sec
+result: <[document]> <html> <body> <h1 id=t>
+expect: document() html body h1
+judge : OK (-)
+
+No.5
+expr : id("t")/ancestor-or-self::node()/ancestor::*
+time : 0.000000 sec
+result: <html> <body>
+expect: html body
+judge : OK (-)
+
+No.6
+expr : id("t")/ancestor-or-self::node()/ancestor::node()
+time : 0.000000 sec
+result: <[document]> <html> <body>
+expect: document() html body
+judge : OK (-)
+
+No.7
+expr : id("t")/ancestor-or-self::node()/ancestor-or-self::*
+time : 0.000000 sec
+result: <html> <body> <h1 id=t>
+expect: html body h1
+judge : OK (-)
+
+No.8
+expr : id("t")/ancestor-or-self::node()/ancestor-or-self::node()
+time : 0.015000 sec
+result: <[document]> <html> <body> <h1 id=t>
+expect: document() html body h1
+judge : OK (-)
+
+No.9
+expr : id("t")/ancestor::*[1]
+time : 0.000000 sec
+result: <body>
+expect: body
+judge : OK (-)
+
+No.10
+expr : id("t")/ancestor::node()[1]
+time : 0.000000 sec
+result: <body>
+expect: body
+judge : OK (-)
+
+No.11
+expr : id("t")/ancestor-or-self::*[1]
+time : 0.000000 sec
+result: <h1 id=t>
+expect: h1
+judge : OK (-)
+
+No.12
+expr : id("t")/ancestor-or-self::node()[1]
+time : 0.000000 sec
+result: <h1 id=t>
+expect: h1
+judge : OK (-)
+
+No.13
+expr : id("t")/ancestor-or-self::node()/ancestor::*[1]
+time : 0.000000 sec
+result: <html> <body>
+expect: html body
+judge : OK (-)
+
+No.14
+expr : id("t")/ancestor-or-self::node()/ancestor::node()[1]
+time : 0.000000 sec
+result: <[document]> <html> <body>
+expect: document() html body
+judge : OK (-)
+
+No.15
+expr : id("t")/ancestor-or-self::node()/ancestor-or-self::*[1]
+time : 0.000000 sec
+result: <html> <body> <h1 id=t>
+expect: html body h1
+judge : OK (-)
+
+No.16
+expr : id("t")/ancestor-or-self::node()/ancestor-or-self::node()[1]
+time : 0.000000 sec
+result: <[document]> <html> <body> <h1 id=t>
+expect: document() html body h1
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0008.txt b/BSXPath_ver001e/testbsxresult/r0008.txt
new file mode 100644
index 0000000..2f54cf9
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0008.txt
@@ -0,0 +1,116 @@
+[0008]
+Sibling Test
+
+No.1
+expr : id('first')/following-sibling::*
+time : 0.000000 sec
+result: <span class=2> <span class=3> <span id=last class=4>
+expect: span.2 span.3 span.4
+judge : OK (-)
+
+No.2
+expr : id('first')/following-sibling::node()
+time : 0.000000 sec
+result: foo <span class=2> bar <span class=3> baz <span id=last class=4>
+expect: text("foo") span.2 text("bar") span.3 text("baz") span.4
+judge : OK (-)
+
+No.3
+expr : id('first')/following-sibling::*/following-sibling::*
+time : 0.000000 sec
+result: <span class=3> <span id=last class=4>
+expect: span.3 span.4
+judge : OK (-)
+
+No.4
+expr : id('first')/following-sibling::node()/following-sibling::node()
+time : 0.000000 sec
+result: <span class=2> bar <span class=3> baz <span id=last class=4>
+expect: span.2 text("bar") span.3 text("baz") span.4
+judge : OK (-)
+
+No.5
+expr : id('first')/following-sibling::*[1]
+time : 0.015000 sec
+result: <span class=2>
+expect: span.2
+judge : OK (-)
+
+No.6
+expr : id('first')/following-sibling::node()[1]
+time : 0.000000 sec
+result: foo
+expect: text("foo")
+judge : OK (-)
+
+No.7
+expr : id('first')/following-sibling::*/following-sibling::*[1]
+time : 0.000000 sec
+result: <span class=3> <span id=last class=4>
+expect: span.3 span.4
+judge : OK (-)
+
+No.8
+expr : id('first')/following-sibling::node()/following-sibling::node()[1]
+time : 0.000000 sec
+result: <span class=2> bar <span class=3> baz <span id=last class=4>
+expect: span.2 text("bar") span.3 text("baz") span.4
+judge : OK (-)
+
+No.9
+expr : id('last')/preceding-sibling::*
+time : 0.015000 sec
+result: <span id=first class=1> <span class=2> <span class=3>
+expect: span.1 span.2 span.3
+judge : OK (-)
+
+No.10
+expr : id('last')/preceding-sibling::node()
+time : 0.000000 sec
+result: <span id=first class=1> foo <span class=2> bar <span class=3> baz
+expect: span.1 text("foo") span.2 text("bar") span.3 text("baz")
+judge : OK (-)
+
+No.11
+expr : id('last')/preceding-sibling::*/preceding-sibling::*
+time : 0.000000 sec
+result: <span id=first class=1> <span class=2>
+expect: span.1 span.2
+judge : OK (-)
+
+No.12
+expr : id('last')/preceding-sibling::node()/preceding-sibling::node()
+time : 0.000000 sec
+result: <span id=first class=1> foo <span class=2> bar <span class=3>
+expect: span.1 text("foo") span.2 text("bar") span.3
+judge : OK (-)
+
+No.13
+expr : id('last')/preceding-sibling::*[1]
+time : 0.000000 sec
+result: <span class=3>
+expect: span.3
+judge : OK (-)
+
+No.14
+expr : id('last')/preceding-sibling::node()[1]
+time : 0.000000 sec
+result: baz
+expect: text("baz")
+judge : OK (-)
+
+No.15
+expr : id('last')/preceding-sibling::*/preceding-sibling::*[1]
+time : 0.000000 sec
+result: <span id=first class=1> <span class=2>
+expect: span.1 span.2
+judge : OK (-)
+
+No.16
+expr : id('last')/preceding-sibling::node()/preceding-sibling::node()[1]
+time : 0.015000 sec
+result: <span id=first class=1> foo <span class=2> bar <span class=3>
+expect: span.1 text("foo") span.2 text("bar") span.3
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0009.txt b/BSXPath_ver001e/testbsxresult/r0009.txt
new file mode 100644
index 0000000..c72e4f7
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0009.txt
@@ -0,0 +1,102 @@
+[0009]
+Element had length property (ex <select>) Test
+
+No.1
+expr : id("target")
+time : 0.000000 sec
+result: <select id=target>
+expect: select#target
+judge : OK (-)
+
+No.2
+expr : //*[@id="target"]
+time : 0.015000 sec
+result: <select id=target>
+expect: select#target
+judge : OK (-)
+
+No.3
+expr : //select[@id="target"]
+time : 0.000000 sec
+result: <select id=target>
+expect: select#target
+judge : OK (-)
+
+No.4
+expr : //node()[@id="target"]
+time : 0.000000 sec
+result: <select id=target>
+expect: select#target
+judge : OK (-)
+
+No.5
+expr : //body/*[@id="target"]
+time : 0.000000 sec
+result: <select id=target>
+expect: select#target
+judge : OK (-)
+
+No.6
+expr : //body/select[@id="target"]
+time : 0.000000 sec
+result: <select id=target>
+expect: select#target
+judge : OK (-)
+
+No.7
+expr : //body/node()[@id="target"]
+time : 0.016000 sec
+result: <select id=target>
+expect: select#target
+judge : OK (-)
+
+No.8
+expr : id("target2")
+time : 0.000000 sec
+result:
+expect: (none)
+judge : OK (-)
+
+No.9
+expr : //*[@name="target2"]
+time : 0.000000 sec
+result: <select id=a> <select id=b>
+expect: select#a select#b
+judge : OK (-)
+
+No.10
+expr : //select[@name="target2"]
+time : 0.000000 sec
+result: <select id=a> <select id=b>
+expect: select#a select#b
+judge : OK (-)
+
+No.11
+expr : //node()[@name="target2"]
+time : 0.000000 sec
+result: <select id=a> <select id=b>
+expect: select#a select#b
+judge : OK (-)
+
+No.12
+expr : //body/div/*[@name="target2"]
+time : 0.000000 sec
+result: <select id=a> <select id=b>
+expect: select#a select#b
+judge : OK (-)
+
+No.13
+expr : //body/div/select[@name="target2"]
+time : 0.000000 sec
+result: <select id=a> <select id=b>
+expect: select#a select#b
+judge : OK (-)
+
+No.14
+expr : //body/div/node()[@name="target2"]
+time : 0.016000 sec
+result: <select id=a> <select id=b>
+expect: select#a select#b
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0010.txt b/BSXPath_ver001e/testbsxresult/r0010.txt
new file mode 100644
index 0000000..2588c56
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0010.txt
@@ -0,0 +1,32 @@
+[0010]
+IE id problem
+
+No.1
+expr : /html/body/div
+time : 0.000000 sec
+result: <div> <div id=tags> <div id=getElementsByTagName> <div id=getElementById> <div id=children> <div id=nodeType> <div id=length>
+expect: div div#tags div#getElementsByTagName div#getElementById div#children div#nodeType div#length
+judge : OK (-)
+
+No.2
+expr : //body//div
+time : 0.000000 sec
+result: <div> <div id=aaa> <div id=tags> <div id=getElementsByTagName> <div id=getElementById> <div id=children> <div id=nodeType> <div id=length>
+expect: div div#aaa div#tags div#getElementsByTagName div#getElementById div#children div#nodeType div#length
+judge : OK (-)
+
+No.3
+expr : //div[@id="aaa"]
+time : 0.016000 sec
+result: <div id=aaa>
+expect: div#aaa
+judge : OK (-)
+
+No.4
+expr : id("aaa")
+time : 0.000000 sec
+result: <div id=aaa>
+expect: div#aaa
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0011.txt b/BSXPath_ver001e/testbsxresult/r0011.txt
new file mode 100644
index 0000000..bf30aa7
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0011.txt
@@ -0,0 +1,46 @@
+[0011]
+Complex href
+
+No.1
+expr : //a[@href="javascript:doFoo('a', 'b')"]
+time : 0.016000 sec
+result: <a id=id0-0>
+expect: a#id0-0
+judge : OK (-)
+
+No.2
+expr : //a[@href="javascript:doFoo('a',%20'b')"]
+time : 0.000000 sec
+result: <a id=id0-1>
+expect: a#id0-1
+judge : OK (-)
+
+No.3
+expr : //a[@href="javascript:doFoo('%61',%20'b')"]
+time : 0.000000 sec
+result: <a id=id0-2>
+expect: a#id0-2
+judge : OK (-)
+
+No.4
+expr : //a[@href="http://example.com/a b"]
+time : 0.000000 sec
+result: <a id=id1-0>
+expect: a#id1-0
+judge : OK (-)
+
+No.5
+expr : //a[@href="http://example.com/a%20b"]
+time : 0.000000 sec
+result: <a id=id1-1>
+expect: a#id1-1
+judge : OK (-)
+
+No.6
+expr : //a[@href="http://example.com/%61%20b"]
+time : 0.000000 sec
+result: <a id=id1-2>
+expect: a#id1-2
+judge : OK (-)
+
+
diff --git a/BSXPath_ver001e/testbsxresult/r0012.txt b/BSXPath_ver001e/testbsxresult/r0012.txt
new file mode 100644
index 0000000..6a1abd5
--- /dev/null
+++ b/BSXPath_ver001e/testbsxresult/r0012.txt
@@ -0,0 +1,46 @@
+[0012]
+Misc
+
+No.1
+expr : //div[2]
+time : 0.016000 sec
+result: <div id=id2> <div id=id4-2>
+expect: div#id2 div#id4-2
+judge : OK (-)
+
+No.2
+expr : /descendant::div[2]
+time : 0.000000 sec
+result: <div id=id2>
+expect: div#id2
+judge : OK (-)
+
+No.3
+expr : (//div)[2]
+time : 0.000000 sec
+result: <div id=id2>
+expect: div#id2
+judge : OK (-)
+
+No.4
+expr : //tr[2]
+time : 0.015000 sec
+result: <tr id=id6> <tr id=id9>
+expect: tr#id6 tr#id9
+judge : OK (-)
+
+No.5
+expr : /descendant::tr[2]
+time : 0.015000 sec
+result: <tr id=id6>
+expect: tr#id6
+judge : OK (-)
+
+No.6
+expr : (//tr)[2]
+time : 0.000000 sec
+result: <tr id=id6>
+expect: tr#id6
+judge : OK (-)
+
+