xmlparser/MANIFEST0000644000076400007640000000215711532726446014467 0ustar yoshidamyoshidamMANIFEST xmlparser.c README.ja lib/xmltreebuilder.rb lib/xmltree.rb lib/xmltreevisitor.rb lib/xmldigest.rb lib/wget.rb lib/sax.rb lib/saxdriver.rb extconf.rb README encoding.h Encodings/euc-jp.enc Encodings/shift_jis.enc Encodings/README.ja lib/xml/dom/core.rb lib/xml/dom/builder.rb lib/xml/dom/visitor.rb lib/xml/dom/digest.rb lib/xml/sax.rb lib/xml/saxdriver.rb lib/xml/parser.rb lib/xml/dom2/document.rb lib/xml/dom2/node.rb lib/xml/dom2/namednodemap.rb lib/xml/dom2/documentfragment.rb lib/xml/dom2/cdatasection.rb lib/xml/dom2/documenttype.rb lib/xml/dom2/element.rb lib/xml/dom2/attr.rb lib/xml/dom2/comment.rb lib/xml/dom2/characterdata.rb lib/xml/dom2/notation.rb lib/xml/dom2/entity.rb lib/xml/dom2/entityreference.rb lib/xml/dom2/text.rb lib/xml/dom2/processinginstruction.rb lib/xml/dom2/domexception.rb lib/xml/dom2/domimplementation.rb lib/xml/dom2/nodelist.rb lib/xml/dom2/dombuilder.rb lib/xml/dom2/domentityresolver.rb lib/xml/dom2/core.rb lib/xml/dom2/dominputsource.rb lib/xml/dom2/dombuilderfilter.rb lib/xml/dom2/domentityresolverimpl.rb lib/xml/parserns.rb lib/xml/xpath.ry lib/xml/xpath.rb lib/xml/dom2/xpath.rb xmlparser/xmlparser.c0000644000076400007640000017323211532726202015510 0ustar yoshidamyoshidam/* * Expat (XML Parser Toolkit) wrapper for Ruby * Dec 15, 2009 yoshidam version 0.7.0 support Ruby 1.9.1 * Feb 16, 2004 yoshidam version 0.6.8 taint output string * Feb 16, 2004 yoshidam version 0.6.7 fix buffer overflow * Mar 11, 2003 yoshidam version 0.6.6 fix skippedEntity handler * Sep 20, 2002 yoshidam version 0.6.5 fix reset method * Apr 4, 2002 yoshidam version 0.6.3 change event code values * Oct 10, 2000 yoshidam version 0.6.1 support expat-1.2 * Oct 6, 2000 yoshidam version 0.6.0 support expat-1.95.0 * Jun 28, 1999 yoshidam version 0.5.18 define initialize for Ruby 1.5 * Jun 28, 1999 yoshidam version 0.5.15 support start/endDoctypeDecl * Jun 28, 1999 yoshidam version 0.5.14 support setParamEntityParsing * Apr 28, 1999 yoshidam version 0.5.11 support notStandalone * Mar 29, 1998 yoshidam version 0.5.9 optimize for Ruby 1.3 * Mar 8, 1998 yoshidam version 0.5.7 support start/endNamespaceDecl * Jan 14, 1998 yoshidam version 0.5.4 support start/endCdataSection * Jan 10, 1998 yoshidam version 0.5.3 support encoding map * Nov 24, 1998 yoshidam version 0.5.0 support TEST version of expat * Nov 5, 1998 yoshidam version 0.4.18 mIDs are initialized in Init_xmlparser * Oct 28, 1998 yoshidam version 0.4.17 mIDs are stored into static vars * Oct 13, 1998 yoshidam version 0.4.12 debug and speed up myEncodingConv * Oct 7, 1998 yoshidam version 0.4.11 hold internal object into ivar * Sep 18, 1998 yoshidam version 0.4.6 * Sep 8, 1998 yoshidam version 0.4.4 * Sep 3, 1998 yoshidam version 0.4.3 * Sep 1, 1998 yoshidam version 0.4.2 * Aug 28, 1998 yoshidam version 0.4.1 * Aug 22, 1998 yoshidam version 0.4.0 * Jul 6, 1998 yoshidam version 0.2 * Jun 30, 1998 yoshidam version 0.1 * * XML_ENC_PATH: path of encoding map for Perl * HAVE_XML_USEFOREIGNDTD: expat 1.95.5 * HAVE_XML_GETFEATURELIST: expat 1.95.5 * HAVE_XML_SETSKIPPEDENTITYHANDLER: expat 1.95.4 * HAVE_XML_PARSERRESET: expat 1.95.3 * HAVE_EXPAT_H: expat 1.95.0 * HAVE_XML_SETDOCTYPEDECLHANDLER: expat 19990728 * XML_DTD: expat 19990626 * NEW_EXPAT: expat 1.1 */ #include "ruby.h" #ifdef HAVE_RUBY_IO_H # include "ruby/io.h" #else # include "rubyio.h" #endif #include #include #ifdef HAVE_EXPAT_H # include "expat.h" #else # include "xmlparse.h" #endif #ifdef XML_ENC_PATH # include # include # include "encoding.h" # ifndef PATH_MAX # define PATH_MAX 256 # endif #endif #ifndef RSTRING_PTR # define RSTRING_PTR(s) (RSTRING(s)->ptr) # define RSTRING_LEN(s) (RSTRING(s)->len) #endif #ifdef HAVE_RUBY_ENCODING_H static rb_encoding* enc_xml; #endif static VALUE eXMLParserError; static VALUE cXMLParser; static VALUE cXMLEncoding; static ID id_map; static ID id_startElementHandler; static ID id_endElementHandler; static ID id_characterDataHandler; static ID id_processingInstructionHandler; static ID id_defaultHandler; static ID id_defaultExpandHandler; static ID id_unparsedEntityDeclHandler; static ID id_notationDeclHandler; static ID id_externalEntityRefHandler; static ID id_unknownEncoding; static ID id_convert; #ifdef NEW_EXPAT static ID id_commentHandler; static ID id_startCdataSectionHandler; static ID id_endCdataSectionHandler; static ID id_startNamespaceDeclHandler; static ID id_endNamespaceDeclHandler; static ID id_notStandaloneHandler; #endif #ifdef HAVE_XML_SETDOCTYPEDECLHANDLER static ID id_startDoctypeDeclHandler; static ID id_endDoctypeDeclHandler; #endif #ifdef HAVE_EXPAT_H static ID id_elementDeclHandler; static ID id_attlistDeclHandler; static ID id_xmlDeclHandler; static ID id_entityDeclHandler; #endif #if 0 static ID id_externalParsedEntityDeclHandler; static ID id_internalParsedEntityDeclHandler; #endif #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER static ID id_skippedEntityHandler; #endif #define GET_PARSER(obj, parser) \ Data_Get_Struct(obj, XMLParser, parser) typedef struct _XMLParser { XML_Parser parser; int iterator; int defaultCurrent; #ifdef NEW_EXPAT const XML_Char** lastAttrs; #endif int tainted; VALUE parent; char* context; const XML_Char *detectedEncoding; } XMLParser; static VALUE symDEFAULT; static VALUE symSTART_ELEM; static VALUE symEND_ELEM; static VALUE symCDATA; static VALUE symPI; static VALUE symUNPARSED_ENTITY_DECL; static VALUE symNOTATION_DECL; static VALUE symEXTERNAL_ENTITY_REF; #ifdef NEW_EXPAT static VALUE symCOMMENT; static VALUE symSTART_CDATA; static VALUE symEND_CDATA; static VALUE symSTART_NAMESPACE_DECL; static VALUE symEND_NAMESPACE_DECL; #endif #ifdef HAVE_XML_SETDOCTYPEDECLHANDLER static VALUE symSTART_DOCTYPE_DECL; static VALUE symEND_DOCTYPE_DECL; #endif #ifdef HAVE_EXPAT_H static VALUE symELEMENT_DECL; static VALUE symATTLIST_DECL; static VALUE symXML_DECL; static VALUE symENTITY_DECL; #endif #if 0 static VALUE symEXTERNAL_PARSED_ENTITY_DECL; static VALUE symINTERNAL_PARSED_ENTITY_DECL; #endif #if 0 static VALUE symUNKNOWN_ENCODING; #endif #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER static VALUE symSKIPPED_ENTITY; #endif /* destructor */ static void XMLParser_free(XMLParser* parser) { /* fprintf(stderr, "Delete XMLParser: %p->%p\n", parser, parser->parser);*/ if (parser->parser) { XML_ParserFree(parser->parser); parser->parser = NULL; } free(parser); } static void XMLParser_mark(XMLParser* parser) { /* fprintf(stderr, "Mark XMLParser: %p->%p\n", parser, parser->parser);*/ if (!NIL_P(parser->parent)) { XMLParser* parent; GET_PARSER(parser->parent, parent); rb_gc_mark(parser->parent); } } static void taintParser(XMLParser* parser) { parser->tainted |= 1; if (!NIL_P(parser->parent) && !parser->context) { XMLParser* parent; GET_PARSER(parser->parent, parent); taintParser(parent); } } inline static VALUE taintObject(XMLParser* parser, VALUE obj) { if (parser->tainted) OBJ_TAINT(obj); return obj; } #define TO_(o) (taintObject(parser, o)) inline static VALUE freezeObject(VALUE obj) { OBJ_FREEZE(obj); return obj; } #define FO_(o) (freezeObject(o)) #ifdef HAVE_RUBY_ENCODING_H # define ENC_(o) (rb_enc_associate(o, enc_xml)) #else # define ENC_(o) (o) #endif /* Event handlers for iterator */ static void iterStartElementHandler(void *recv, const XML_Char *name, const XML_Char **atts) { XMLParser* parser; VALUE attrhash; GET_PARSER(recv, parser); #ifdef NEW_EXPAT parser->lastAttrs = atts; #endif attrhash = rb_hash_new(); while (*atts) { const char* key = *atts++; const char* val = *atts++; rb_hash_aset(attrhash, FO_(TO_(ENC_(rb_str_new2((char*)key)))), TO_(ENC_(rb_str_new2((char*)val)))); } rb_yield(rb_ary_new3(4, symSTART_ELEM, TO_(ENC_(rb_str_new2((char*)name))), attrhash, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterEndElementHandler(void *recv, const XML_Char *name) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symEND_ELEM, TO_(ENC_(rb_str_new2((char*)name))), Qnil, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterCharacterDataHandler(void *recv, const XML_Char *s, int len) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symCDATA, Qnil, TO_(ENC_(rb_str_new((char*)s, len))), recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterProcessingInstructionHandler(void *recv, const XML_Char *target, const XML_Char *data) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symPI, TO_(ENC_(rb_str_new2((char*)target))), TO_(ENC_(rb_str_new2((char*)data))), recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterDefaultHandler(void *recv, const XML_Char *s, int len) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symDEFAULT, Qnil, TO_(ENC_(rb_str_new((char*)s, len))), recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; /* XML_DefaultCurrent shoould not call in defaultHandler */ /* XML_DefaultCurrent(parser->parser); */ } } void iterUnparsedEntityDeclHandler(void *recv, const XML_Char *entityName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) { XMLParser* parser; VALUE valary; GET_PARSER(recv, parser); valary = rb_ary_new3(4, (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), TO_(ENC_(rb_str_new2((char*)systemId))), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil), TO_(ENC_(rb_str_new2((char*)notationName)))); rb_yield(rb_ary_new3(4, symUNPARSED_ENTITY_DECL, TO_(ENC_(rb_str_new2((char*)entityName))), valary, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } void iterNotationDeclHandler(void *recv, const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XMLParser* parser; VALUE valary; GET_PARSER(recv, parser); valary = rb_ary_new3(3, (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), (systemId ? TO_(ENC_(rb_str_new2((char*)systemId))) : Qnil), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil)); rb_yield(rb_ary_new3(4, symNOTATION_DECL, TO_(ENC_(rb_str_new2((char*)notationName))), valary, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } int iterExternalEntityRefHandler(XML_Parser xmlparser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XMLParser* parser; VALUE recv; VALUE valary; VALUE ret; recv = (VALUE)XML_GetUserData(xmlparser); GET_PARSER(recv, parser); valary = rb_ary_new3(3, (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), (systemId ? TO_(ENC_(rb_str_new2((char*)systemId))) : Qnil), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil)); ret = rb_yield(rb_ary_new3(4, symEXTERNAL_ENTITY_REF, (context ? TO_(ENC_(rb_str_new2((char*)context))) : Qnil), valary, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } /* The error status in this iterator block should be returned by the exception. */ return 1; } #ifdef NEW_EXPAT static void iterCommentHandler(void *recv, const XML_Char *s) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symCOMMENT, Qnil, TO_(ENC_(rb_str_new2((char*)s))), recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterStartCdataSectionHandler(void *recv) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symSTART_CDATA, Qnil, Qnil, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterEndCdataSectionHandler(void *recv) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symEND_CDATA, Qnil, Qnil, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterStartNamespaceDeclHandler(void *recv, const XML_Char *prefix, const XML_Char *uri) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symSTART_NAMESPACE_DECL, (prefix ? TO_(ENC_(rb_str_new2((char*)prefix))) : Qnil), (uri ? TO_(ENC_(rb_str_new2((char*)uri))) : Qnil), recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterEndNamespaceDeclHandler(void *recv, const XML_Char *prefix) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symEND_NAMESPACE_DECL, (prefix ? TO_(ENC_(rb_str_new2((char*)prefix))) : Qnil), Qnil, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } #endif #ifdef HAVE_XML_SETPARAMENTITYPARSING static void #ifdef HAVE_EXPAT_H iterStartDoctypeDeclHandler(void *recv, const XML_Char *doctypeName, const XML_Char *sysid, const XML_Char *pubid, int has_internal_subset) #else iterStartDoctypeDeclHandler(void *recv, const XML_Char *doctypeName) #endif { XMLParser* parser; VALUE valary = Qnil; GET_PARSER(recv, parser); #ifdef HAVE_EXPAT_H valary = rb_ary_new3(3, (sysid ? TO_(ENC_(rb_str_new2((char*)sysid))) : Qnil), (pubid ? TO_(ENC_(rb_str_new2((char*)pubid))) : Qnil), (has_internal_subset ? Qtrue : Qfalse)); #endif rb_yield(rb_ary_new3(4, symSTART_DOCTYPE_DECL, TO_(ENC_(rb_str_new2((char*)doctypeName))), valary, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterEndDoctypeDeclHandler(void *recv) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symEND_DOCTYPE_DECL, Qnil, Qnil, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } #endif #ifdef HAVE_EXPAT_H static VALUE makeContentArray(XMLParser* parser, XML_Content* model) { static const char* content_type_name[] = { NULL, "EMPTY", "ANY", "MIXED", "NAME", "CHOICE", "SEQ" }; static const char* content_quant_name[] = { "", "?", "*", "+" }; unsigned int i; VALUE children = Qnil; const char* type_name = content_type_name[model->type]; const char* quant_name = content_quant_name[model->quant]; VALUE ret = rb_ary_new3(3, TO_(ENC_(rb_str_new2((char*)type_name))), TO_(ENC_(rb_str_new2((char*)quant_name))), (model->name ? TO_(ENC_(rb_str_new2((char*)model->name))) : Qnil)); if (model->numchildren > 0) { children = rb_ary_new(); for (i = 0; i < model->numchildren; i++) { VALUE child = makeContentArray(parser, model->children + i); rb_ary_push(children, child); } } rb_ary_push(ret, children); return ret; } static void iterElementDeclHandler(void *recv, const XML_Char *name, XML_Content *model) { XMLParser* parser; VALUE content; GET_PARSER(recv, parser); content = makeContentArray(parser, model); rb_yield(rb_ary_new3(4, symELEMENT_DECL, TO_(ENC_(rb_str_new2(name))), content, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterAttlistDeclHandler (void *recv, const XML_Char *elname, const XML_Char *attname, const XML_Char *att_type, const XML_Char *dflt, int isrequired) { XMLParser* parser; VALUE valary; GET_PARSER(recv, parser); valary = rb_ary_new3(4, TO_(ENC_(rb_str_new2((char*)attname))), TO_(ENC_(rb_str_new2((char*)att_type))), (dflt ? TO_(ENC_(rb_str_new2((char*)dflt))) : Qnil), (isrequired ? Qtrue : Qfalse)); rb_yield(rb_ary_new3(4, symATTLIST_DECL, TO_(ENC_(rb_str_new2(elname))), valary, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterXmlDeclHandler (void *recv, const XML_Char *version, const XML_Char *encoding, int standalone) { XMLParser* parser; VALUE valary; GET_PARSER(recv, parser); valary = rb_ary_new3(3, (version ? TO_(ENC_(rb_str_new2(version))) : Qnil), (encoding ? TO_(ENC_(rb_str_new2((char*)encoding))) : Qnil), INT2FIX(standalone)); rb_yield(rb_ary_new3(4, symXML_DECL, Qnil, valary, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterEntityDeclHandler (void *recv, const XML_Char *entityName, int is_parameter_entity, const XML_Char *value, int value_length, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) { XMLParser* parser; VALUE valary; GET_PARSER(recv, parser); valary = rb_ary_new3(6, (is_parameter_entity ? Qtrue : Qfalse), TO_(ENC_(rb_str_new((char*)value, value_length))), (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), (systemId ? TO_(ENC_(rb_str_new2((char*)systemId))) : Qnil), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil), (notationName ? TO_(ENC_(rb_str_new2((char*)notationName))) : Qnil)); rb_yield(rb_ary_new3(4, symENTITY_DECL, TO_(ENC_(rb_str_new2(entityName))), valary, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } #endif #if 0 static void iterExternalParsedEntityDeclHandler(void *recv, const XML_Char *entityName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XMLParser* parser; VALUE valary; GET_PARSER(recv, parser); valary = rb_ary_new3(3, (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), TO_(ENC_(rb_str_new2((char*)systemId))), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil)); rb_yield(rb_ary_new3(4, symEXTERNAL_PARSED_ENTITY_DECL, TO_(ENC_(rb_str_new2((char*)entityName))), valary, recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } static void iterInternalParsedEntityDeclHandler(void *recv, const XML_Char *entityName, const XML_Char *replacementText, int replacementTextLength) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symINTERNAL_PARSED_ENTITY_DECL, TO_(ENC_(rb_str_new2((char*)entityName))), TO_(ENC_(rb_str_new((char*)replacementText, replacementTextLength))), recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } #endif #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER static void iterSkippedEntityHandler(void *recv, const XML_Char *entityName, int is_parameter_entity) { XMLParser* parser; GET_PARSER(recv, parser); rb_yield(rb_ary_new3(4, symSKIPPED_ENTITY, TO_(ENC_(rb_str_new2((char*)entityName))), INT2FIX(is_parameter_entity), recv)); if (parser->defaultCurrent) { parser->defaultCurrent = 0; XML_DefaultCurrent(parser->parser); } } #endif /* Event handlers for instance method */ static void myStartElementHandler(void *recv, const XML_Char *name, const XML_Char **atts) { XMLParser* parser; VALUE attrhash; GET_PARSER(recv, parser); #ifdef NEW_EXPAT parser->lastAttrs = atts; #endif attrhash = rb_hash_new(); while (*atts) { const char* key = *atts++; const char* val = *atts++; rb_hash_aset(attrhash, FO_(TO_(ENC_(rb_str_new2((char*)key)))), TO_(ENC_(rb_str_new2((char*)val)))); } rb_funcall((VALUE)recv, id_startElementHandler, 2, TO_(ENC_(rb_str_new2((char*)name))), attrhash); } static void myEndElementHandler(void *recv, const XML_Char *name) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_endElementHandler, 1, TO_(ENC_(rb_str_new2((char*)name)))); } static void myCharacterDataHandler(void *recv, const XML_Char *s, int len) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_characterDataHandler, 1, TO_(ENC_(rb_str_new((char*)s, len)))); } static void myProcessingInstructionHandler(void *recv, const XML_Char *target, const XML_Char *data) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_processingInstructionHandler, 2, TO_(ENC_(rb_str_new2((char*)target))), TO_(ENC_(rb_str_new2((char*)data)))); } static void myDefaultHandler(void *recv, const XML_Char *s, int len) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_defaultHandler, 1, TO_(ENC_(rb_str_new((char*)s, len)))); } #ifdef NEW_EXPAT static void myDefaultExpandHandler(void *recv, const XML_Char *s, int len) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_defaultExpandHandler, 1, TO_(ENC_(rb_str_new((char*)s, len)))); } #endif void myUnparsedEntityDeclHandler(void *recv, const XML_Char *entityName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_unparsedEntityDeclHandler, 5, TO_(ENC_(rb_str_new2((char*)entityName))), (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), TO_(ENC_(rb_str_new2((char*)systemId))), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil), TO_(ENC_(rb_str_new2((char*)notationName)))); } void myNotationDeclHandler(void *recv, const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_notationDeclHandler, 4, TO_(ENC_(rb_str_new2((char*)notationName))), (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), (systemId ? TO_(ENC_(rb_str_new2((char*)systemId))) : Qnil), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil)); } int myExternalEntityRefHandler(XML_Parser xmlparser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XMLParser* parser; VALUE recv; VALUE ret; recv = (VALUE)XML_GetUserData(xmlparser); GET_PARSER(recv, parser); ret = rb_funcall(recv, id_externalEntityRefHandler, 4, (context ? TO_(ENC_(rb_str_new2((char*)context))): Qnil), (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), (systemId ? TO_(ENC_(rb_str_new2((char*)systemId))) : Qnil), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil)); /* The error status in this handler should be returned by the exception. */ return Qnil; } #ifdef NEW_EXPAT static void myCommentHandler(void *recv, const XML_Char *s) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_commentHandler, 1, TO_(ENC_(rb_str_new2((char*)s)))); } static void myStartCdataSectionHandler(void *recv) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_startCdataSectionHandler, 0); } static void myEndCdataSectionHandler(void *recv) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_endCdataSectionHandler, 0); } static void myStartNamespaceDeclHandler(void *recv, const XML_Char *prefix, const XML_Char *uri) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_startNamespaceDeclHandler, 2, (prefix ? TO_(ENC_(rb_str_new2((char*)prefix))) : Qnil), (uri ? TO_(ENC_(rb_str_new2((char*)uri))) : Qnil)); } static void myEndNamespaceDeclHandler(void *recv, const XML_Char *prefix) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_endNamespaceDeclHandler, 1, (prefix ? TO_(ENC_(rb_str_new2((char*)prefix))) : Qnil)); } static int myNotStandaloneHandler(void *recv) { XMLParser* parser; VALUE v; GET_PARSER(recv, parser); v = rb_funcall((VALUE)recv, id_notStandaloneHandler, 0); Check_Type(v, T_FIXNUM); return FIX2INT(v); } #endif #ifdef HAVE_XML_SETPARAMENTITYPARSING static void #ifdef HAVE_EXPAT_H myStartDoctypeDeclHandler(void *recv, const XML_Char *doctypeName, const XML_Char *sysid, const XML_Char *pubid, int has_internal_subset) #else myStartDoctypeDeclHandler(void *recv, const XML_Char *doctypeName) #endif { XMLParser* parser; GET_PARSER(recv, parser); #ifdef HAVE_EXPAT_H rb_funcall((VALUE)recv, id_startDoctypeDeclHandler, 4, TO_(ENC_(rb_str_new2((char*)doctypeName))), (sysid ? TO_(ENC_(rb_str_new2((char*)sysid))) : Qnil), (pubid ? TO_(ENC_(rb_str_new2((char*)pubid))) : Qnil), (has_internal_subset ? Qtrue : Qfalse)); #else rb_funcall((VALUE)recv, id_startDoctypeDeclHandler, 4, TO_(ENC_(rb_str_new2((char*)doctypeName))), Qnil, Qnil, Qfalse); #endif } static void myEndDoctypeDeclHandler(void *recv) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_endDoctypeDeclHandler, 0); } #endif #ifdef HAVE_EXPAT_H static void myElementDeclHandler(void *recv, const XML_Char *name, XML_Content *model) { XMLParser* parser; VALUE content; GET_PARSER(recv, parser); content = makeContentArray(parser, model); rb_funcall((VALUE)recv, id_elementDeclHandler, 2, TO_(ENC_(rb_str_new2(name))), content); } static void myAttlistDeclHandler (void *recv, const XML_Char *elname, const XML_Char *attname, const XML_Char *att_type, const XML_Char *dflt, int isrequired) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_attlistDeclHandler, 5, TO_(ENC_(rb_str_new2(elname))), TO_(ENC_(rb_str_new2((char*)attname))), TO_(ENC_(rb_str_new2((char*)att_type))), (dflt ? TO_(ENC_(rb_str_new2((char*)dflt))) : Qnil), (isrequired ? Qtrue : Qfalse)); } static void myXmlDeclHandler (void *recv, const XML_Char *version, const XML_Char *encoding, int standalone) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_xmlDeclHandler, 3, (version ? TO_(ENC_(rb_str_new2(version))) : Qnil), (encoding ? TO_(ENC_(rb_str_new2((char*)encoding))) : Qnil), INT2FIX(standalone)); } static void myEntityDeclHandler (void *recv, const XML_Char *entityName, int is_parameter_entity, const XML_Char *value, int value_length, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_entityDeclHandler, 7, TO_(ENC_(rb_str_new2(entityName))), (is_parameter_entity ? Qtrue : Qfalse), TO_(ENC_(rb_str_new((char*)value, value_length))), (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), (systemId ? TO_(ENC_(rb_str_new2((char*)systemId))) : Qnil), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil), (notationName ? TO_(ENC_(rb_str_new2((char*)notationName))) : Qnil)); } #endif #if 0 static void myExternalParsedEntityDeclHandler(void *recv, const XML_Char *entityName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_externalParsedEntityDeclHandler, 4, TO_(ENC_(rb_str_new2((char*)entityName))), (base ? TO_(ENC_(rb_str_new2((char*)base))) : Qnil), TO_(ENC_(rb_str_new2((char*)systemId))), (publicId ? TO_(ENC_(rb_str_new2((char*)publicId))) : Qnil)); } static void myInternalParsedEntityDeclHandler(void *recv, const XML_Char *entityName, const XML_Char *replacementText, int replacementTextLength) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_internalParsedEntityDeclHandler, 2, TO_(ENC_(rb_str_new2((char*)entityName))), TO_(ENC_(rb_str_new((char*)replacementText, replacementTextLength)))); } #endif static VALUE XMLEncoding_map(VALUE obj, VALUE i) { return i; } static VALUE XMLEncoding_convert(VALUE obj, VALUE str) { return INT2FIX('?'); } static int myEncodingConv(void *data, const char *s) { VALUE v; int len; int slen = RSTRING_PTR(rb_ivar_get((VALUE)data, id_map))[*(unsigned char*)s]; v = rb_funcall((VALUE)data, id_convert, 1, ENC_(rb_str_new((char*)s, -slen))); switch (TYPE(v)) { case T_FIXNUM: return FIX2INT(v); case T_STRING: len = RSTRING_LEN(v); if (len == 1) { return (unsigned char)*RSTRING_PTR(v); } else if (len >= 2) { return (unsigned char)*RSTRING_PTR(v) | (unsigned char)*(RSTRING_PTR(v) + 1) << 8; } } return 0; } #if 0 static int iterUnknownEncodingHandler(void *recv, const XML_Char *name, XML_Encoding *info) { XMLParser* parser; VALUE ret; if (!rb_method_boundp(CLASS_OF((VALUE)recv), id_unknownEncoding, 0)) return 0; GET_PARSER(recv, parser); ret = rb_yield(rb_ary_new3(4, symUNKNOWN_ENCODING, TO_(ENC_(rb_str_new2((char*)name))), Qnil, recv)); if (TYPE(ret) == T_OBJECT && rb_obj_is_kind_of(ret, cXMLEncoding)) { int i; ID mid = rb_intern("map"); VALUE cmap = rb_str_new(NULL, 256); rb_ivar_set(ret, id_map, cmap); for (i = 0; i < 256; i++) { VALUE m = rb_funcall(ret, mid, 1, INT2FIX(i)); RSTRING_PTR(cmap)[i] = info->map[i] = FIX2INT(m); } /* protect object form GC */ rb_ivar_set(recv, rb_intern("_encoding"), ret); info->data = (void*)ret; info->convert = myEncodingConv; return 1; } return 0; } #endif #ifdef XML_ENC_PATH /* * Encoding map functions come from XML::Parser Version 2.19 * * Copyright 1998 Larry Wall and Clark Cooper * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the same terms as Perl itself. */ static Encinfo* getEncinfo(char* data, int size) { Encmap_Header* header = (Encmap_Header*)data; unsigned short prefixes_size; unsigned short bytemap_size; Encinfo* ret; int i; PrefixMap* prefixes; unsigned short *bytemap; if (size < sizeof(Encmap_Header) || ntohl(header->magic) != ENCMAP_MAGIC) return NULL; prefixes_size = ntohs(header->pfsize); bytemap_size = ntohs(header->bmsize); if (size != (sizeof(Encmap_Header) + prefixes_size * sizeof(PrefixMap) + bytemap_size * sizeof(unsigned short))) return NULL; if ((ret = (Encinfo*)malloc(sizeof(Encinfo))) == NULL) { return NULL; } ret->prefixes_size = prefixes_size; ret->bytemap_size = bytemap_size; for (i = 0; i < 256; i++) ret->firstmap[i] = ntohl(header->map[i]); prefixes = (PrefixMap*)(data + sizeof(Encmap_Header)); bytemap = (unsigned short*)(data + sizeof(Encmap_Header) + sizeof(PrefixMap)*prefixes_size); if ((ret->prefixes = (PrefixMap*)malloc(sizeof(PrefixMap)*prefixes_size)) == NULL) { free(ret); return NULL; } if ((ret->bytemap = (unsigned short*)malloc(sizeof(unsigned short)*bytemap_size)) == NULL) { free(ret->prefixes); free(ret); return NULL; } for (i = 0; i < prefixes_size; i++, prefixes++) { ret->prefixes[i].min = prefixes->min; ret->prefixes[i].len = prefixes->len; ret->prefixes[i].bmap_start = ntohs(prefixes->bmap_start); memcpy(ret->prefixes[i].ispfx, prefixes->ispfx, sizeof(prefixes->ispfx) + sizeof(prefixes->ischar)); } for (i = 0; i < bytemap_size; i++) ret->bytemap[i] = ntohs(bytemap[i]); return ret; } static int convertEncoding(Encinfo* enc, const char* seq) { PrefixMap* curpfx; int count; int index = 0; for (count = 0; count < 4; count++) { unsigned char byte = (unsigned char)seq[count]; unsigned char bndx; unsigned char bmsk; int offset; curpfx = &enc->prefixes[index]; offset = ((int)byte) - curpfx->min; if (offset < 0) break; if (offset >= curpfx->len && curpfx->len != 0) break; bndx = byte >> 3; bmsk = 1 << (byte & 0x7); if (curpfx->ispfx[bndx] & bmsk) { index = enc->bytemap[curpfx->bmap_start + offset]; } else if (curpfx->ischar[bndx] & bmsk) { return enc->bytemap[curpfx->bmap_start + offset]; } else break; } return -1; } static void releaseEncoding(Encinfo* enc) { if (enc) { if (enc->prefixes) free(enc->prefixes); if (enc->bytemap) free(enc->bytemap); free(enc); } } static Encinfo* findEncoding(const char* encname) { FILE* fp; Encinfo* enc; struct stat st; int size; int len; char file[PATH_MAX] = "\0"; const char* p; char* buf; #ifdef DOSISH const char sepchar = '\\'; #else const char sepchar = '/'; #endif const char* const encext = ".enc"; rb_secure(2); /* make map file path */ if (XML_ENC_PATH != NULL) { strncpy(file, XML_ENC_PATH, PATH_MAX - 1); file[PATH_MAX - 1] = '\0'; } len = strlen(file); if (len > 0 && len < PATH_MAX - 1 && file[len - 1] != sepchar) file[len++] = sepchar; for (p = encname; *p && len < PATH_MAX - 1; p++, len++) { file[len] = tolower(*p); } file[len] = '\0'; strncat(file, encext, PATH_MAX - len -1); if ((fp = fopen(file, "rb")) == NULL) { return NULL; } /* get file length */ fstat(fileno(fp), &st); size = st.st_size; if ((buf = (char*)malloc(size)) == NULL) { fclose(fp); return NULL; } fread(buf, 1, size, fp); fclose(fp); enc = getEncinfo(buf, size); free(buf); return enc; } #endif static int myUnknownEncodingHandler(void *recv, const XML_Char *name, XML_Encoding *info) { XMLParser* parser; VALUE ret; GET_PARSER(recv, parser); parser->detectedEncoding = name; if (!rb_method_boundp(CLASS_OF((VALUE)recv), id_unknownEncoding, 0)) #ifndef XML_ENC_PATH return 0; #else { Encinfo* enc; if ((enc = findEncoding(name)) != NULL) { memcpy(info->map, enc->firstmap, sizeof(int)*256); info->data = enc; info->convert = (int(*)(void*,const char*))convertEncoding; info->release = (void(*)(void*))releaseEncoding; return 1; } else return 0; } #endif ret = rb_funcall((VALUE)recv, id_unknownEncoding, 1, TO_(ENC_(rb_str_new2((char*)name)))); if (TYPE(ret) == T_OBJECT && rb_obj_is_kind_of(ret, cXMLEncoding)) { int i; ID mid = rb_intern("map"); VALUE cmap = rb_str_new(NULL, 256); rb_ivar_set(ret, id_map, cmap); if (OBJ_TAINTED(ret)) taintParser(parser); TO_(cmap); for (i = 0; i < 256; i++) { VALUE m = rb_funcall(ret, mid, 1, INT2FIX(i)); RSTRING_PTR(cmap)[i] = info->map[i] = FIX2INT(m); } /* protect object form GC */ rb_ivar_set((VALUE)recv, rb_intern("_encoding"), ret); info->data = (void*)ret; info->convert = myEncodingConv; return 1; } return 0; } #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER static void mySkippedEntityHandler(void *recv, const XML_Char *entityName, int is_parameter_entity) { XMLParser* parser; GET_PARSER(recv, parser); rb_funcall((VALUE)recv, id_skippedEntityHandler, 2, TO_(ENC_(rb_str_new2((char*)entityName))), INT2FIX(is_parameter_entity)); } #endif /* constructor */ static VALUE XMLParser_new(int argc, VALUE* argv, VALUE klass) { XMLParser* parser; VALUE obj; VALUE arg1; VALUE arg2; VALUE arg3; int count; char* encoding = NULL; #ifdef NEW_EXPAT char* nssep = NULL; #endif char* context = NULL; XMLParser* rootparser = NULL; VALUE parent = Qnil; count = rb_scan_args(argc, argv, "03", &arg1, &arg2, &arg3); if (count == 1) { /* new(encoding) */ if (TYPE(arg1) != T_NIL) { Check_Type(arg1, T_STRING); /* encoding */ encoding = RSTRING_PTR(arg1); } } else if (count == 2) { /* new(encoding, nschar) */ /* new(parser, context) */ #ifdef NEW_EXPAT if (TYPE(arg1) != T_DATA) { if (TYPE(arg1) != T_NIL) { Check_Type(arg1, T_STRING); /* encoding */ encoding = RSTRING_PTR(arg1); } Check_Type(arg2, T_STRING); /* nschar */ nssep = RSTRING_PTR(arg2); } else { #endif Check_Type(arg1, T_DATA); /* parser */ GET_PARSER(arg1, rootparser); if (!NIL_P(arg2)) { Check_Type(arg2, T_STRING); /* context */ context = RSTRING_PTR(arg2); } parent = arg1; #ifdef NEW_EXPAT } #endif } else if (count == 3) { /* new(parser, context, encoding) */ Check_Type(arg1, T_DATA); /* parser */ GET_PARSER(arg1, rootparser); if (!NIL_P(arg2)) { Check_Type(arg2, T_STRING); /* context */ context = RSTRING_PTR(arg2); } Check_Type(arg3, T_STRING); /* encoding */ encoding = RSTRING_PTR(arg3); parent = arg1; } /* create object */ obj = Data_Make_Struct(klass, XMLParser, XMLParser_mark, XMLParser_free, parser); /* create parser */ if (rootparser == NULL) { #ifdef NEW_EXPAT if (nssep == NULL) parser->parser = XML_ParserCreate(encoding); else parser->parser = XML_ParserCreateNS(encoding, nssep[0]); #else parser->parser = XML_ParserCreate(encoding); #endif parser->tainted = 0; parser->context = NULL; } else { parser->parser = XML_ExternalEntityParserCreate(rootparser->parser, context, encoding); /* clear all inhrited handlers, because handlers should be set in "parse" method */ XML_SetElementHandler(parser->parser, NULL, NULL); XML_SetCharacterDataHandler(parser->parser, NULL); XML_SetProcessingInstructionHandler(parser->parser, NULL); XML_SetDefaultHandler(parser->parser, NULL); XML_SetUnparsedEntityDeclHandler(parser->parser, NULL); XML_SetNotationDeclHandler(parser->parser, NULL); XML_SetExternalEntityRefHandler(parser->parser, NULL); #ifdef NEW_EXPAT XML_SetCommentHandler(parser->parser, NULL); XML_SetCdataSectionHandler(parser->parser, NULL, NULL); XML_SetNamespaceDeclHandler(parser->parser, NULL, NULL); XML_SetNotStandaloneHandler(parser->parser, NULL); #endif #ifdef HAVE_XML_SETDOCTYPEDECLHANDLER XML_SetDoctypeDeclHandler(parser->parser, NULL, NULL); #endif #ifdef HAVE_EXPAT_H XML_SetElementDeclHandler(parser->parser, NULL); XML_SetAttlistDeclHandler(parser->parser, NULL); XML_SetXmlDeclHandler(parser->parser, NULL); XML_SetEntityDeclHandler(parser->parser, NULL); #endif #if 0 XML_SetExternalParsedEntityDeclHandler(parser->parser, NULL); XML_SetInternalParsedEntityDeclHandler(parser->parser, NULL); #endif #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER XML_SetSkippedEntityHandler(parser->parser, NULL); #endif if (rootparser->tainted) parser->tainted |= 1; parser->context = context; } if (!parser->parser) rb_raise(eXMLParserError, "cannot create parser"); /* setting up internal data */ XML_SetUserData(parser->parser, (void*)obj); parser->iterator = 0; parser->defaultCurrent = 0; #ifdef NEW_EXPAT parser->lastAttrs = NULL; #endif parser->parent = parent; parser->detectedEncoding = NULL; rb_obj_call_init(obj, argc, argv); return obj; } static VALUE XMLParser_initialize(VALUE obj) { return Qnil; } #ifdef HAVE_XML_PARSERRESET static VALUE XMLParser_reset(int argc, VALUE* argv, VALUE obj) { XMLParser* parser; VALUE vencoding = Qnil; char* encoding = NULL; int count; count = rb_scan_args(argc, argv, "01", &vencoding); GET_PARSER(obj, parser); if (count > 0 && TYPE(vencoding) != T_NIL) { Check_Type(vencoding, T_STRING); encoding = RSTRING_PTR(vencoding); } XML_ParserReset(parser->parser, encoding); /* setting up internal data */ XML_SetUserData(parser->parser, (void*)obj); parser->iterator = 0; parser->defaultCurrent = 0; #ifdef NEW_EXPAT parser->lastAttrs = NULL; #endif parser->tainted = 0; parser->detectedEncoding = NULL; return obj; } #endif static void setup_evnet_handlers(XMLParser* parser, VALUE obj) { XML_StartElementHandler start = NULL; XML_EndElementHandler end = NULL; #ifdef NEW_EXPAT XML_StartCdataSectionHandler startC = NULL; XML_EndCdataSectionHandler endC = NULL; XML_StartNamespaceDeclHandler startNS = NULL; XML_EndNamespaceDeclHandler endNS = NULL; #endif #ifdef HAVE_XML_SETDOCTYPEDECLHANDLER XML_StartDoctypeDeclHandler startDoctype = NULL; XML_EndDoctypeDeclHandler endDoctype = NULL; #endif /* Call as iterator */ if (parser->iterator) { XML_SetElementHandler(parser->parser, iterStartElementHandler, iterEndElementHandler); XML_SetCharacterDataHandler(parser->parser, iterCharacterDataHandler); XML_SetProcessingInstructionHandler(parser->parser, iterProcessingInstructionHandler); /* check dummy default handler */ #ifdef NEW_EXPAT if (rb_method_boundp(CLASS_OF(obj), id_defaultExpandHandler, 0)) XML_SetDefaultHandlerExpand(parser->parser, iterDefaultHandler); else #endif if (rb_method_boundp(CLASS_OF(obj), id_defaultHandler, 0)) XML_SetDefaultHandler(parser->parser, iterDefaultHandler); if (rb_method_boundp(CLASS_OF(obj), id_unparsedEntityDeclHandler, 0)) XML_SetUnparsedEntityDeclHandler(parser->parser, iterUnparsedEntityDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_notationDeclHandler, 0)) XML_SetNotationDeclHandler(parser->parser, iterNotationDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_externalEntityRefHandler, 0)) XML_SetExternalEntityRefHandler(parser->parser, iterExternalEntityRefHandler); #ifdef NEW_EXPAT if (rb_method_boundp(CLASS_OF(obj), id_commentHandler, 0)) XML_SetCommentHandler(parser->parser, iterCommentHandler); if (rb_method_boundp(CLASS_OF(obj), id_startCdataSectionHandler, 0)) startC = iterStartCdataSectionHandler; if (rb_method_boundp(CLASS_OF(obj), id_endCdataSectionHandler, 0)) endC = iterEndCdataSectionHandler; if (startC || endC) XML_SetCdataSectionHandler(parser->parser, startC, endC); if (rb_method_boundp(CLASS_OF(obj), id_startNamespaceDeclHandler, 0)) startNS = iterStartNamespaceDeclHandler; if (rb_method_boundp(CLASS_OF(obj), id_endNamespaceDeclHandler, 0)) endNS = iterEndNamespaceDeclHandler; if (startNS || endNS) XML_SetNamespaceDeclHandler(parser->parser, startNS, endNS); if (rb_method_boundp(CLASS_OF(obj), id_notStandaloneHandler, 0)) XML_SetNotStandaloneHandler(parser->parser, myNotStandaloneHandler); #endif #ifdef HAVE_XML_SETDOCTYPEDECLHANDLER if (rb_method_boundp(CLASS_OF(obj), id_startDoctypeDeclHandler, 0)) startDoctype = iterStartDoctypeDeclHandler; if (rb_method_boundp(CLASS_OF(obj), id_endDoctypeDeclHandler, 0)) endDoctype = iterEndDoctypeDeclHandler; if (startDoctype || endDoctype) XML_SetDoctypeDeclHandler(parser->parser, startDoctype, endDoctype); #endif #ifdef HAVE_EXPAT_H if (rb_method_boundp(CLASS_OF(obj), id_elementDeclHandler, 0)) XML_SetElementDeclHandler(parser->parser, iterElementDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_attlistDeclHandler, 0)) XML_SetAttlistDeclHandler(parser->parser, iterAttlistDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_xmlDeclHandler, 0)) XML_SetXmlDeclHandler(parser->parser, iterXmlDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_entityDeclHandler, 0)) XML_SetEntityDeclHandler(parser->parser, iterEntityDeclHandler); #endif #if 0 if (rb_method_boundp(CLASS_OF(obj), id_externalParsedEntityDeclHandler, 0)) XML_SetExternalParsedEntityDeclHandler(parser->parser, iterExternalParsedEntityDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_internalParsedEntityDeclHandler, 0)) XML_SetInternalParsedEntityDeclHandler(parser->parser, iterInternalParsedEntityDeclHandler); #endif /* Call non-iterator version of UnknownEncoding handler, because the porcedure block often returns the unexpected value. */ XML_SetUnknownEncodingHandler(parser->parser, myUnknownEncodingHandler, (void*)obj); #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER if (rb_method_boundp(CLASS_OF(obj), id_skippedEntityHandler, 0)) XML_SetSkippedEntityHandler(parser->parser, iterSkippedEntityHandler); #endif } /* Call as not iterator */ else { if (rb_method_boundp(CLASS_OF(obj), id_startElementHandler, 0)) start = myStartElementHandler; if (rb_method_boundp(CLASS_OF(obj), id_endElementHandler, 0)) end = myEndElementHandler; if (start || end) XML_SetElementHandler(parser->parser, start, end); if (rb_method_boundp(CLASS_OF(obj), id_characterDataHandler, 0)) XML_SetCharacterDataHandler(parser->parser, myCharacterDataHandler); if (rb_method_boundp(CLASS_OF(obj), id_processingInstructionHandler, 0)) XML_SetProcessingInstructionHandler(parser->parser, myProcessingInstructionHandler); #ifdef NEW_EXPAT if (rb_method_boundp(CLASS_OF(obj), id_defaultExpandHandler, 0)) XML_SetDefaultHandlerExpand(parser->parser, myDefaultExpandHandler); else #endif if (rb_method_boundp(CLASS_OF(obj), id_defaultHandler, 0)) { XML_SetDefaultHandler(parser->parser, myDefaultHandler); } if (rb_method_boundp(CLASS_OF(obj), id_unparsedEntityDeclHandler, 0)) XML_SetUnparsedEntityDeclHandler(parser->parser, myUnparsedEntityDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_notationDeclHandler, 0)) XML_SetNotationDeclHandler(parser->parser, myNotationDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_externalEntityRefHandler, 0)) XML_SetExternalEntityRefHandler(parser->parser, myExternalEntityRefHandler); #ifdef NEW_EXPAT if (rb_method_boundp(CLASS_OF(obj), id_commentHandler, 0)) XML_SetCommentHandler(parser->parser, myCommentHandler); if (rb_method_boundp(CLASS_OF(obj), id_startCdataSectionHandler, 0)) startC = myStartCdataSectionHandler; if (rb_method_boundp(CLASS_OF(obj), id_endCdataSectionHandler, 0)) endC = myEndCdataSectionHandler; if (startC || endC) XML_SetCdataSectionHandler(parser->parser, startC, endC); if (rb_method_boundp(CLASS_OF(obj), id_startNamespaceDeclHandler, 0)) startNS = myStartNamespaceDeclHandler; if (rb_method_boundp(CLASS_OF(obj), id_endNamespaceDeclHandler, 0)) endNS = myEndNamespaceDeclHandler; if (startNS || endNS) XML_SetNamespaceDeclHandler(parser->parser, startNS, endNS); if (rb_method_boundp(CLASS_OF(obj), id_notStandaloneHandler, 0)) XML_SetNotStandaloneHandler(parser->parser, myNotStandaloneHandler); #endif #ifdef HAVE_XML_SETDOCTYPEDECLHANDLER if (rb_method_boundp(CLASS_OF(obj), id_startDoctypeDeclHandler, 0)) startDoctype = myStartDoctypeDeclHandler; if (rb_method_boundp(CLASS_OF(obj), id_endDoctypeDeclHandler, 0)) endDoctype = myEndDoctypeDeclHandler; if (startDoctype || endDoctype) XML_SetDoctypeDeclHandler(parser->parser, startDoctype, endDoctype); #endif #ifdef HAVE_EXPAT_H if (rb_method_boundp(CLASS_OF(obj), id_elementDeclHandler, 0)) XML_SetElementDeclHandler(parser->parser, myElementDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_attlistDeclHandler, 0)) XML_SetAttlistDeclHandler(parser->parser, myAttlistDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_xmlDeclHandler, 0)) XML_SetXmlDeclHandler(parser->parser, myXmlDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_entityDeclHandler, 0)) XML_SetEntityDeclHandler(parser->parser, myEntityDeclHandler); #endif #if 0 if (rb_method_boundp(CLASS_OF(obj), id_externalParsedEntityDeclHandler, 0)) XML_SetExternalParsedEntityDeclHandler(parser->parser, myExternalParsedEntityDeclHandler); if (rb_method_boundp(CLASS_OF(obj), id_internalParsedEntityDeclHandler, 0)) XML_SetInternalParsedEntityDeclHandler(parser->parser, myInternalParsedEntityDeclHandler); #endif XML_SetUnknownEncodingHandler(parser->parser, myUnknownEncodingHandler, (void*)obj); #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER if (rb_method_boundp(CLASS_OF(obj), id_skippedEntityHandler, 0)) XML_SetSkippedEntityHandler(parser->parser, mySkippedEntityHandler); #endif } } /* parse method */ static VALUE XMLParser_parse(int argc, VALUE* argv, VALUE obj) { XMLParser* parser; int ret; VALUE str; VALUE isFinal; int final = 1; int count; int fromStream = 0; ID mid = rb_intern("gets"); ID linebuf = rb_intern("_linebuf"); count = rb_scan_args(argc, argv, "02", &str, &isFinal); /* If "str" has public "gets" method, it will be considered *stream* */ if (!rb_obj_is_kind_of(str, rb_cString) && rb_method_boundp(CLASS_OF(str), mid, 1)) { fromStream = 1; } else if (!NIL_P(str)) { Check_Type(str, T_STRING); } if (count >= 2) { if (isFinal == Qtrue) final = 1; else if (isFinal == Qfalse) final = 0; else rb_raise(rb_eTypeError, "not valid value"); } GET_PARSER(obj, parser); parser->iterator = rb_block_given_p(); /* Setup event handlers */ setup_evnet_handlers(parser, obj); /* Parse from stream (probably slightly slow) */ if (fromStream) { VALUE buf; if (OBJ_TAINTED(str)) taintParser(parser); do { buf = rb_funcall(str, mid, 0); if (!NIL_P(buf)) { Check_Type(buf, T_STRING); if (OBJ_TAINTED(buf)) taintParser(parser); rb_ivar_set(obj, linebuf, buf); /* protect buf from GC (reasonable?)*/ ret = XML_Parse(parser->parser, RSTRING_PTR(buf), RSTRING_LEN(buf), 0); } else { ret = XML_Parse(parser->parser, NULL, 0, 1); } if (!ret) { int err = XML_GetErrorCode(parser->parser); const char* errStr = XML_ErrorString(err); rb_raise(eXMLParserError, (char*)errStr); } } while (!NIL_P(buf)); return Qnil; } /* Parse string */ if (!NIL_P(str)) { #if defined(HAVE_RUBY_ENCODING_H) && defined(HAVE_XML_PARSERRESET) int err; #endif if (OBJ_TAINTED(str)) taintParser(parser); ret = XML_Parse(parser->parser, RSTRING_PTR(str), RSTRING_LEN(str), final); #if defined(HAVE_RUBY_ENCODING_H) && defined(HAVE_XML_PARSERRESET) /* Ruby 1.9.1 Encoding conversion */ err = XML_GetErrorCode(parser->parser); if (final && err == XML_ERROR_UNKNOWN_ENCODING) { rb_encoding* enc; volatile VALUE encobj; volatile VALUE ustr; enc = rb_enc_find(parser->detectedEncoding); if ((int)ENC_TO_ENCINDEX(enc) != rb_ascii8bit_encindex()) { rb_enc_associate(str, enc); encobj = rb_enc_from_encoding(enc_xml); /* rb_str_encode may raises an exception */ ustr = rb_str_encode(str, encobj, 0, Qnil); if (!NIL_P(ustr)) { XML_ParserReset(parser->parser, "utf-8"); XML_SetUserData(parser->parser, (void*)obj); parser->defaultCurrent = 0; #ifdef NEW_EXPAT parser->lastAttrs = NULL; #endif parser->detectedEncoding = NULL; setup_evnet_handlers(parser, obj); ret = XML_Parse(parser->parser, RSTRING_PTR(ustr), RSTRING_LEN(ustr), final); } } } #endif } else ret = XML_Parse(parser->parser, NULL, 0, final); if (!ret) { int err = XML_GetErrorCode(parser->parser); const char* errStr = XML_ErrorString(err); rb_raise(eXMLParserError, (char*)errStr); } return Qnil; } /* done method */ static VALUE XMLParser_done(VALUE obj) { XMLParser* parser; GET_PARSER(obj, parser); if (parser->parser) { XML_ParserFree(parser->parser); parser->parser = NULL; } return Qnil; } /* defaultCurrent method */ static VALUE XMLParser_defaultCurrent(VALUE obj) { XMLParser* parser; GET_PARSER(obj, parser); if (!(parser->iterator)) { XML_DefaultCurrent(parser->parser); } else { parser->defaultCurrent = 1; } return Qnil; } /* line method */ static VALUE XMLParser_getCurrentLineNumber(VALUE obj) { XMLParser* parser; int line; GET_PARSER(obj, parser); line = XML_GetCurrentLineNumber(parser->parser); return INT2FIX(line); } /* column method */ static VALUE XMLParser_getCurrentColumnNumber(VALUE obj) { XMLParser* parser; int column; GET_PARSER(obj, parser); column = XML_GetCurrentColumnNumber(parser->parser); return INT2FIX(column); } /* byte index method */ static VALUE XMLParser_getCurrentByteIndex(VALUE obj) { XMLParser* parser; long pos; GET_PARSER(obj, parser); pos = XML_GetCurrentByteIndex(parser->parser); return INT2FIX(pos); } /* set URI base */ static VALUE XMLParser_setBase(VALUE obj, VALUE base) { XMLParser* parser; int ret; Check_Type(base, T_STRING); GET_PARSER(obj, parser); if (OBJ_TAINTED(base)) taintParser(parser); ret = XML_SetBase(parser->parser, RSTRING_PTR(base)); return INT2FIX(ret); } /* get URI base */ static VALUE XMLParser_getBase(VALUE obj) { XMLParser* parser; const XML_Char* ret; GET_PARSER(obj, parser); ret = XML_GetBase(parser->parser); if (!ret) return Qnil; return TO_(ENC_(rb_str_new2((char*)ret))); } #ifdef NEW_EXPAT #if 0 static VALUE XMLParser_getSpecifiedAttributes(VALUE obj) { XMLParser* parser; int count; const XML_Char** atts; VALUE attrhash; GET_PARSER(obj, parser); atts = parser->lastAttrs; if (!atts) return Qnil; count = XML_GetSpecifiedAttributeCount(parser->parser)/2; attrhash = rb_hash_new(); while (*atts) { const char* key = *atts++; atts++; rb_hash_aset(attrhash, FO_(TO_(ENC_(rb_str_new2((char*)key)))), (count-- > 0) ? Qtrue: Qfalse); } return attrhash; } #else static VALUE XMLParser_getSpecifiedAttributes(VALUE obj) { XMLParser* parser; int i, count; const XML_Char** atts; VALUE attrarray; GET_PARSER(obj, parser); atts = parser->lastAttrs; if (!atts) return Qnil; count = XML_GetSpecifiedAttributeCount(parser->parser)/2; attrarray = rb_ary_new2(count); for (i = 0; i < count; i++, atts+=2) { const char* key = *atts; rb_ary_push(attrarray, TO_(ENC_(rb_str_new2((char*)key)))); } return attrarray; } #endif static VALUE XMLParser_getCurrentByteCount(VALUE obj) { XMLParser* parser; GET_PARSER(obj, parser); return INT2FIX(XML_GetCurrentByteCount(parser->parser)); } #endif #ifdef XML_DTD static VALUE XMLParser_setParamEntityParsing(VALUE obj, VALUE parsing) { XMLParser* parser; int ret; Check_Type(parsing, T_FIXNUM); GET_PARSER(obj, parser); ret = XML_SetParamEntityParsing(parser->parser, FIX2INT(parsing)); return INT2FIX(ret); } #endif static VALUE XMLParser_s_expatVersion(VALUE obj) { #if defined(HAVE_EXPAT_H) return ENC_(rb_str_new2(XML_ExpatVersion())); #elif defined(EXPAT_1_2) return ENC_(rb_str_new2("1.2")); #elif defined(NEW_EXPAT) return ENC_(rb_str_new2("1.1")); #else return ENC_(rb_str_new2("1.0")); #endif } #ifdef HAVE_EXPAT_H static VALUE XMLParser_setReturnNSTriplet(VALUE obj, VALUE do_nst) { XMLParser* parser; int nst; GET_PARSER(obj, parser); switch (TYPE(do_nst)) { case T_TRUE: nst = 1; break; case T_FALSE: nst = 0; break; case T_FIXNUM: nst = FIX2INT(do_nst); break; default: rb_raise(rb_eTypeError, "not valid value"); } XML_SetReturnNSTriplet(parser->parser, nst); return Qnil; } static VALUE XMLParser_getInputContext(VALUE obj) { XMLParser* parser; const char* buffer; int offset; int size; VALUE ret = Qnil; GET_PARSER(obj, parser); buffer = XML_GetInputContext(parser->parser, &offset, &size); if (buffer && size > 0) { ret = rb_ary_new3(2, TO_(ENC_(rb_str_new(buffer, size))), INT2FIX(offset)); } return ret; } static VALUE XMLParser_getIdAttrribute(VALUE obj) { XMLParser* parser; int idattr; const XML_Char** atts; GET_PARSER(obj, parser); atts = parser->lastAttrs; if (!atts) return Qnil; idattr = XML_GetIdAttributeIndex(parser->parser); if (idattr < 0) return Qnil; return TO_(ENC_(rb_str_new2((char*)atts[idattr]))); } #endif #ifdef HAVE_XML_USEFOREIGNDTD static VALUE XMLParser_useForeignDTD(VALUE obj, VALUE useDTD) { XMLParser* parser; int dtd; int ret; GET_PARSER(obj, parser); switch (TYPE(useDTD)) { case T_TRUE: dtd = 1; break; case T_FALSE: dtd = 0; break; case T_FIXNUM: dtd = FIX2INT(useDTD); break; default: rb_raise(rb_eTypeError, "not valid value"); } ret = XML_UseForeignDTD(parser->parser, dtd); return INT2FIX(ret); } #endif #ifdef HAVE_XML_GETFEATURELIST static VALUE XMLParser_s_getFeatureList(VALUE obj) { const XML_Feature* list; VALUE ret = rb_hash_new(); list = XML_GetFeatureList(); while (list && list->feature) { rb_hash_aset(ret, FO_(ENC_(rb_str_new2(list->name))), INT2NUM(list->value)); list++; } return ret; } #endif void Init_xmlparser() { VALUE mXML; #ifdef HAVE_RUBY_ENCODING_H enc_xml = rb_utf8_encoding(); #endif eXMLParserError = rb_define_class("XMLParserError", rb_eStandardError); cXMLParser = rb_define_class("XMLParser", rb_cObject); cXMLEncoding = rb_define_class("XMLEncoding", rb_cObject); /* Class name aliases */ if (rb_const_defined(rb_cObject, rb_intern("XML")) == Qtrue) mXML = rb_const_get(rb_cObject, rb_intern("XML")); else mXML = rb_define_module("XML"); rb_define_const(mXML, "ParserError", eXMLParserError); rb_define_const(cXMLParser, "Error", eXMLParserError); rb_define_const(mXML, "Parser", cXMLParser); rb_define_const(mXML, "Encoding", cXMLEncoding); rb_define_singleton_method(cXMLParser, "new", XMLParser_new, -1); rb_define_singleton_method(cXMLParser, "expatVersion", XMLParser_s_expatVersion, 0); rb_define_method(cXMLParser, "initialize", XMLParser_initialize, -1); rb_define_method(cXMLParser, "parse", XMLParser_parse, -1); rb_define_method(cXMLParser, "done", XMLParser_done, 0); rb_define_method(cXMLParser, "defaultCurrent", XMLParser_defaultCurrent, 0); rb_define_method(cXMLParser, "line", XMLParser_getCurrentLineNumber, 0); rb_define_method(cXMLParser, "column", XMLParser_getCurrentColumnNumber, 0); rb_define_method(cXMLParser, "byteIndex", XMLParser_getCurrentByteIndex, 0); rb_define_method(cXMLParser, "setBase", XMLParser_setBase, 1); rb_define_method(cXMLParser, "getBase", XMLParser_getBase, 0); #ifdef NEW_EXPAT rb_define_method(cXMLParser, "getSpecifiedAttributes", XMLParser_getSpecifiedAttributes, 0); rb_define_method(cXMLParser, "byteCount", XMLParser_getCurrentByteCount, 0); #endif #ifdef XML_DTD rb_define_method(cXMLParser, "setParamEntityParsing", XMLParser_setParamEntityParsing, 1); #endif #ifdef HAVE_EXPAT_H rb_define_method(cXMLParser, "setReturnNSTriplet", XMLParser_setReturnNSTriplet, 1); rb_define_method(cXMLParser, "getInputContext", XMLParser_getInputContext, 0); rb_define_method(cXMLParser, "getIdAttribute", XMLParser_getIdAttrribute, 0); #endif #ifdef HAVE_XML_PARSERRESET rb_define_method(cXMLParser, "reset", XMLParser_reset, -1); #endif rb_define_method(cXMLEncoding, "map", XMLEncoding_map, 1); rb_define_method(cXMLEncoding, "convert", XMLEncoding_convert, 1); #ifdef HAVE_XML_USEFOREIGNDTD rb_define_method(cXMLParser, "useForeignDTD", XMLParser_useForeignDTD, 1); #endif #ifdef HAVE_XML_GETFEATURELIST rb_define_singleton_method(cXMLParser, "getFeatureList", XMLParser_s_getFeatureList, 0); #endif #define DEFINE_EVENT_CODE(klass, name) \ rb_define_const(klass, #name, sym##name = ID2SYM(rb_intern(#name))) DEFINE_EVENT_CODE(cXMLParser, START_ELEM); DEFINE_EVENT_CODE(cXMLParser, END_ELEM); DEFINE_EVENT_CODE(cXMLParser, CDATA); DEFINE_EVENT_CODE(cXMLParser, PI); DEFINE_EVENT_CODE(cXMLParser, DEFAULT); DEFINE_EVENT_CODE(cXMLParser, UNPARSED_ENTITY_DECL); DEFINE_EVENT_CODE(cXMLParser, NOTATION_DECL); DEFINE_EVENT_CODE(cXMLParser, EXTERNAL_ENTITY_REF); #ifdef NEW_EXPAT DEFINE_EVENT_CODE(cXMLParser, COMMENT); DEFINE_EVENT_CODE(cXMLParser, START_CDATA); DEFINE_EVENT_CODE(cXMLParser, END_CDATA); DEFINE_EVENT_CODE(cXMLParser, START_NAMESPACE_DECL); DEFINE_EVENT_CODE(cXMLParser, END_NAMESPACE_DECL); #endif #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER DEFINE_EVENT_CODE(cXMLParser, SKIPPED_ENTITY); #endif #ifdef XML_DTD rb_define_const(cXMLParser, "PARAM_ENTITY_PARSING_NEVER", XML_PARAM_ENTITY_PARSING_NEVER); rb_define_const(cXMLParser, "PARAM_ENTITY_PARSING_UNLESS_STANDALONE", XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE); rb_define_const(cXMLParser, "PARAM_ENTITY_PARSING_ALWAYS", XML_PARAM_ENTITY_PARSING_ALWAYS); #endif #ifdef HAVE_XML_SETDOCTYPEDECLHANDLER DEFINE_EVENT_CODE(cXMLParser, START_DOCTYPE_DECL); DEFINE_EVENT_CODE(cXMLParser, END_DOCTYPE_DECL); #endif #ifdef HAVE_EXPAT_H DEFINE_EVENT_CODE(cXMLParser, ELEMENT_DECL); DEFINE_EVENT_CODE(cXMLParser, ATTLIST_DECL); DEFINE_EVENT_CODE(cXMLParser, XML_DECL); DEFINE_EVENT_CODE(cXMLParser, ENTITY_DECL); #endif #if 0 DEFINE_EVENT_CODE(cXMLParser, EXTERNAL_PARSED_ENTITY_DECL); DEFINE_EVENT_CODE(cXMLParser, INTERNAL_PARSED_ENTITY_DECL); #endif #if 0 DEFINE_EVENT_CODE(cXMLParser, UNKNOWN_ENCODING); #endif id_map = rb_intern("_map"); id_startElementHandler = rb_intern("startElement"); id_endElementHandler = rb_intern("endElement"); id_characterDataHandler = rb_intern("character"); id_processingInstructionHandler = rb_intern("processingInstruction"); id_defaultHandler = rb_intern("default"); id_unparsedEntityDeclHandler = rb_intern("unparsedEntityDecl"); id_notationDeclHandler = rb_intern("notationDecl"); id_externalEntityRefHandler = rb_intern("externalEntityRef"); #ifdef NEW_EXPAT id_defaultExpandHandler = rb_intern("defaultExpand"); id_commentHandler = rb_intern("comment"); id_startCdataSectionHandler = rb_intern("startCdata"); id_endCdataSectionHandler = rb_intern("endCdata"); id_startNamespaceDeclHandler = rb_intern("startNamespaceDecl"); id_endNamespaceDeclHandler = rb_intern("endNamespaceDecl"); id_notStandaloneHandler = rb_intern("notStandalone"); #endif #ifdef HAVE_XML_SETDOCTYPEDECLHANDLER id_startDoctypeDeclHandler = rb_intern("startDoctypeDecl"); id_endDoctypeDeclHandler = rb_intern("endDoctypeDecl"); #endif id_unknownEncoding = rb_intern("unknownEncoding"); id_convert = rb_intern("convert"); #ifdef HAVE_EXPAT_H id_elementDeclHandler = rb_intern("elementDecl"); id_attlistDeclHandler = rb_intern("attlistDecl"); id_xmlDeclHandler = rb_intern("xmlDecl"); id_entityDeclHandler = rb_intern("entityDecl"); #endif #if 0 id_externalParsedEntityDeclHandler = rb_intern("externalParsedEntityDecl"); id_internalParsedEntityDeclHandler = rb_intern("internalParsedEntityDecl"); #endif #ifdef HAVE_XML_SETSKIPPEDENTITYHANDLER id_skippedEntityHandler = rb_intern("skippedEntity"); #endif } xmlparser/README.ja0000644000076400007640000007147211532727536014616 0ustar yoshidamyoshidam Expat (XML Parser Toolkit) ÍѳÈÄ¥¥â¥¸¥å¡¼¥ë version 0.7.2 µÈÅÄÀµ¿Í - ³µÍ× Ëܥ⥸¥å¡¼¥ë¤Ï¡¤Ruby¤«¤é James Clark »á¤Î XML Parser Toolkit "expat" (http://www.jclark.com/xml/expat.html) ¤Ø¥¢¥¯¥»¥¹¤¹ ¤ë¤¿¤á¤Î³ÈÄ¥¥â¥¸¥å¡¼¥ë¤Ç¤¹¡£ ¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤ë expat ¤Î¥Ð¡¼¥¸¥ç¥ó¤Ï¡¤1.95.0 °Ê¹ß (http://sourceforge.net/projects/expat/) ¤Ç¤¹¡£ - ¥¤¥ó¥¹¥È¡¼¥ë Ruby-1.6 °Ê¹ß¤Ç¤·¤«Æ°ºî³Îǧ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£Ruby-1.6.7 °Ê¹ß¤Î »ÈÍѤò¤ª¤¹¤¹¤á¤·¤Þ¤¹¡£¤Þ¤¿¡¤expat-1.95.x ¤Î¥½¡¼¥¹¤¬É¬ÍפǤ¹¡£ ¤Þ¤º expat ¤ò¥³¥ó¥Ñ¥¤¥ë¤·¤Æ¤¯¤À¤µ¤¤¡£ expat-1.95.x ¤ò»È¤¦¾ì ¹ç¤Ï¡¤configure; make; make install ¤Ç¥¤¥ó¥¹¥È¡¼¥ë¤Ç¤­¤Þ¤¹¡£ ¼¡¤Ë xmlparser ¥â¥¸¥å¡¼¥ë¤ò¥³¥ó¥Ñ¥¤¥ë¤·¤Þ¤¹¡£expat ¤Î¥Ø¥Ã¥À ¥Õ¥¡¥¤¥ë¤ä¥é¥¤¥Ö¥é¥ê¤Î°ÌÃÖ¤ò extconf.rb ¤Î¥ª¥×¥·¥ç¥ó¤Ç»ØÄꤹ ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ --with-expat-dir=/path/to/expat ¤¢¤ë¤¤¤Ï --with-expat-lib=/path/to/expat/lib --with-expat-include=/path/to/expat/include Perl ÍÑ XML::Parser ¤Î ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¥Þ¥Ã¥×¤òÍøÍѤ¹¤ë¾ì¹ç ¤Ï --with-perl-enc-map ¥ª¥×¥·¥ç¥ó¤Ç¥Ç¥£¥ì¥¯¥È¥ê¤ò»ØÄꤷ¤Æ²¼ ¤µ¤¤¡£Encodings ¥Ç¥£¥ì¥¯¥È¥ê¤ÎÃæ¤Ë EUC-JP ¤ÈShift_JIS ¤Î¥Þ¥Ã ¥×¤¬Æþ¤Ã¤Æ¤¤¤Þ¤¹¡£É¬Íפʤé¤ÐŬÅö¤Ê¥Ç¥£¥ì¥¯¥È¥ê(¤¿¤È¤¨¤Ð /usr/local/share/XML/Parser/Encoding ¤Ê¤É)¤Ë¥³¥Ô¡¼¤·¤Æ¤¯ ¤À¤µ¤¤¡£ ¸å¤ÏÄ̾ï¤Î¥â¥¸¥å¡¼¥ë¥¤¥ó¥¹¥È¡¼¥ë¤ò¹Ô¤Ã¤Æ¤¯¤À¤µ¤¤¡£ ruby extconf.rb --with-expat-dir=/usr/local --with-perl-enc-map=/usr/local/share/XML/Parser/Encodings make make site-install - »È¤¤Êý ruby ¤Î make »þ¤ËÀÅŪ¤Ë¥ê¥ó¥¯¤·¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ï¡¤ require "xml/parser" ¤È¤·¤Æ¤«¤é»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤¡£ ¥Ñ¡¼¥¹·ë²Ì¤òÆÀ¤ëÊýË¡¤È¤·¤Æ¡¤¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤òÄêµÁ¤¹¤ëÊýË¡¤È ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦ÊýË¡¤¬¤¢¤ê¤Þ¤¹¡£ ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤òÄêµÁ¤¹¤ëÊýË¡¤Ï SAX (Simple API for XML) ¤Ë »÷¤Æ¤¤¤Þ¤¹¡£ ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤ò»È¤¦¾ì¹ç¡¤´ðËÜŪ¤Ë XMLParser ¥¯¥é¥¹¤ò·Ñ¾µ ¤·¡¤¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¥á¥½¥Ã¥É¤òÄêµÁ¤·¤Æ»È¤Ã¤Æ¤¯¤À¤µ¤¤¡£ private ¥á¥½¥Ã¥É¤Ë¤·¤Æ¤ª¤¯¤Û¤¦¤¬°ÂÁ´¤Ç¤·¤ç¤¦¡£ XMLParser ¥¯¥é¥¹¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤ËÆÃ°Û¥á¥½¥Ã¥É¤òÄêµÁ¤·¤Æ¤â¹½¤¤ ¤Þ¤»¤ó¡£¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ïʸˡ¥Á¥§¥Ã¥¯ ¤·¤«¤·¤Þ¤»¤ó¡£ ¥á¥½¥Ã¥É̾ | ¥¤¥Ù¥ó¥È -------------------------+------------------- startElement | ¥¨¥ì¥á¥ó¥È³«»Ï¥¿¥° endElement | ¥¨¥ì¥á¥ó¥È½ªÎ»¥¿¥° character | ʸ»ú¥Ç¡¼¥¿ processingInstruction | PI unparsedEntityDecl | ²òÀÏÂоݳ°¼ÂÂÎÀë¸À(OBSOLETE) notationDecl | µ­Ë¡Àë¸À externalEntityRef | ³°Éô¼ÂÂλ²¾È comment | ¥³¥á¥ó¥È startCdata | CDATA ¥»¥¯¥·¥ç¥ó³«»Ï endCdata | CDATA ¥»¥¯¥·¥ç¥ó½ªÎ» startNamespaceDecl | Namespace Àë¸À³«»Ï endNamespaceDecl | Namespace Àë¸À½ªÎ» startDoctypeDecl | ʸ½ñ·¿Àë¸À³«»Ï endDoctypeDecl | ʸ½ñ·¿Àë¸À½ªÎ» notStandalone | standalone ¤Ç¤Ï¤Ê¤¤ default | ¤½¤Î¾ defaultExpand | default ¤ÈƱ¤¸ (*1) unknownEncoding | ̤ÃΤΥ¨¥ó¥³¡¼¥Ç¥£¥ó¥° elementDecl | element declaration attlistDecl | attlist declaration xmlDecl | XML declaration entityDecl | entity declaration *1 default ¤È¤ÏÆâÉô¼ÂÂλ²¾È¤òŸ³«¤¹¤ë¤³¤È¤À¤±¤¬°ã¤¤¤Þ¤¹¡£ defaultExpand ¤òÄêµÁ¤¹¤ë¤È default ¤ò̵»ë¤·¤Þ¤¹¡£ ¥È¥Ã¥×¥ì¥Ù¥ë¤Ç´Ø¿ô¤òÄêµÁ¤¹¤ë¾ì¹ç¤Ï´Ø¿ô̾¤ËÃí°Õ¤·¤Æ²¼¤µ¤¤¡£¤¿ ¤Þ¤¿¤Þ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤ÈƱ¤¸Ì¾Á°¤Ë¤·¤Æ¤·¤Þ¤¦¤Èͽ´ü¤·¤Ê¤¤·ë²Ì ¤¬¾·¤¯¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£¥È¥Ã¥×¥ì¥Ù¥ë¤Ç´Ø¿ô¤òÄêµÁ¤¹¤ë¤È Object ¤Î¥á¥½¥Ã¥É¤È¸«¤Ê¤µ¤ì¤Þ¤¹¡£XMLParser ¤â Object ¤ÎÇÉÀ¸¥¯¥é¥¹¤Ê ¤Î¤Ç¡¤¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤ÈƱ¤¸Ì¾Á°¤Î´Ø¿ô¤¬¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤È¤· ¤Æ¸Æ¤Ó½Ð¤µ¤ì¤Æ¤·¤Þ¤¦¤Î¤Ç¤¹¡£µÕ¤Ë¡¤Á´¤Æ¤Î XMLParser ¥ª¥Ö¥¸¥§ ¥¯¥È¤ÇƱ¤¸¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤ò»È¤¦¤Î¤Ç¤¢¤ì¤Ð¡¤¥È¥Ã¥×¥ì¥Ù¥ë¤Î´Ø ¿ô¤È¤·¤ÆÄêµÁ¤·¤Æ¤â¹½¤¤¤Þ¤»¤ó¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦ÊýË¡¤Ï¤è¤ê Ruby ¤é¤·¤¤(¤È»×¤ï¤ì¤ë)¤ä¤ê¤« ¤¿¤Ç¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¤Ï¤¿¤È¤¨¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤òÄêµÁ¤·¤Æ¤¤ ¤Æ¤â̵»ë¤µ¤ì¤Þ¤¹¡£¥¤¥Æ¥ì¡¼¥¿¤Ï ¥¤¥Ù¥ó¥È¥¿¥¤¥×¡¤Ì¾¾Î¡¤ ¥Ç¡¼¥¿ ¤È¤¤¤¦ 3 ¤Ä¤ÎÊÑ¿ô¤ò¥¤¥Æ¥ì¡¼¥¿¥Ö¥í¥Ã¥¯¤ËÅϤ·¤Þ¤¹¡£ ¥¤¥Ù¥ó¥È¥¿¥¤¥× | ̾¾Î | ¥Ç¡¼¥¿ ----------------------------------+-----------------+--------------- START_ELEM | ¥¨¥ì¥á¥ó¥È̾ | °À­¤Î¥Ï¥Ã¥·¥å END_ELEM | ¥¨¥ì¥á¥ó¥È̾ | nil CDATA | nil | ʸ»úÎó PI | PI ̾ | ʸ»úÎó UNPARSED_ENTITY_DECL(OBSOLETE) | ¼ÂÂÎ̾ | ÇÛÎó (*1) NOTATION_DECL | µ­Ë¡Ì¾ | ÇÛÎó (*2) EXTERNAL_ENTITY_REF | ¼ÂÂÎ̾ (*5) | ÇÛÎó (*2) COMMENT | nil | ʸ»úÎó START_CDATA | nil | nil END_CDATA | nil | nil START_NAMESPACE_DECL | prefix | URI END_NAMESPACE_DECL | prefix | nil START_DOCTYPE_DECL | ʸ½ñ·¿Ì¾ | nil END_DOCTYPE_DECL | nil | nil DEFAULT | nil | ʸ»úÎó ELEMENT_DECL | element name | array (*8) ATTLIST_DECL | element name | array (*9) XML_DECL | nil | array (*10) ENTITY_DECL | entity name | array (*11) *1 [URL¥Ù¡¼¥¹¡¤¥·¥¹¥Æ¥à¼±Ê̻ҡ¤¸ø³«¼±Ê̻ҡ¤µ­Ë¡Ì¾] URL¥Ù¡¼¥¹¡¤µ­Ë¡Ì¾ ¤Ï nil ¤Ë¤Ê¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£ *2 [URL¥Ù¡¼¥¹¡¤¥·¥¹¥Æ¥à¼±Ê̻ҡ¤¸ø³«¼±ÊÌ»Ò] URL¥Ù¡¼¥¹¡¤¥·¥¹¥Æ¥à¼±Ê̻ҡ¤¸ø³«¼±ÊÌ»Ò ¤Ï nil ¤Ë¤Ê¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£ *5 ³°Éô¥Ñ¥é¥á¡¼¥¿¼ÂÂΤξì¹ç¤Ï nil ¤Ë¤Ê¤ê¤Þ¤¹¡£ *8 [type, quant, name, [...]] *9 [attname, atttype, default, isrequired] *10 [version, encoding, standalone] *11 [isPE, value, URL base, system ID, public ID, notation name] UNPARSED_ENTITY_DECL¡¤NOTATION_DECL¡¤EXTERNAL_ENTITY_REF¡¤ COMMENT¡¤START_CDATA¡¤END_CDATA¡¤START_NAMESPACE_DECL¡¤ END_NAMESPACE_DECL¡¤DEFAULT¡¤ELEMENT_DECL¡¤ATTLIST_DECL¡¤ XML_DECL¡¤ENTITY_DECL ¤¬È¯À¸¤¹¤ë¤Î¤Ï¤½¤ì¤¾¤ì¡¤¥À¥ß¡¼¤Î unparsedEntityDecl¡¤notationDecl¡¤externalEntityRef¡¤comment¡¤ startCdata¡¤endCdata¡¤startNamespaceDecl¡¤endNamespaceDecl¡¤ default (¤Þ¤¿¤Ï defaultExpand)¡¤elementDecl¡¤attlistDecl¡¤ xmlDecl¡¤entityDecl ¥á¥½¥Ã¥É¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ë¤È¤­¤À¤±¤Ç¤¹¡£ ÆþÎÏʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤Ï UTF-8, UTF-16 ¤ËÂбþ¤·¤Æ¤¤¤Þ¤¹¡£ ½ÐÎÏ¤Ï UTF-8 ¤Ç¤¹¡£¤½¤ì°Ê³°¤Îʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤ò»È¤¤¤¿¤¤ ¾ì¹ç¤Ïʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤òÊÑ´¹¤·¡¤ ¹Ô¤Î encoding="..." ¤ò½ñ¤­´¹¤¨¤Æ¤¯¤À¤µ¤¤¡£ ¥³¥ó¥Ñ¥¤¥ë»þ¤Ë XML_ENC_PATH ¤¬Å¬ÀÚ¤ËÀßÄꤵ¤ì¤Æ¤¤¤¿¾ì¹ç¡¤Perl ÍÑ XML::Parser ¤Î¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¥Þ¥Ã¥×¤òÍøÍѤǤ­¤Þ¤¹¡£¤³¤Î ¥Ñ¥Ã¥±¡¼¥¸¤Ë¤Ï¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¥Þ¥Ã¥×¤Ï´Þ¤Þ¤ì¤Æ¤¤¤Ê¤¤¤Î¤Ç¡¤ CPAN ¤«¤é XML::Parser ¤¢¤ë¤¤¤Ï XML::Encoding ¥â¥¸¥å¡¼¥ë¤òÆþ ¼ê¤·¡¤.enc ¥Õ¥¡¥¤¥ë¤òŬÅö¤Ê¥Ç¥£¥ì¥¯¥È¥ê¤Ë¥¤¥ó¥¹¥È¡¼¥ë¤·¤Æ²¼ ¤µ¤¤¡£ XMLParser ¥¯¥é¥¹: ¥¯¥é¥¹¥á¥½¥Ã¥É new(encoding = nil, nssep = nil) XML ¥Ñ¡¼¥µ¥ª¥Ö¥¸¥§¥¯¥È¤òºîÀ®¤·¤Þ¤¹¡£ºîÀ®¤Ë¼ºÇÔ¤¹¤ë¤È XMLParserError Îã³°¤¬È¯À¸¤·¤Þ¤¹¡£ encoding ¤È¤·¤ÆÊ¸»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤ò³°Éô¤«¤é»ØÄꤹ¤ë ¤³¤È¤â½ÐÍè¤Þ¤¹¡£Expat ¤¬Âбþ¤·¤Æ¤¤¤ë¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°Ì¾ (ISO-8859-1, UTF-8, US-ASCII, UTF-16)¤¬»È¤¨¤Þ¤¹¡£ Expat-ja ¤Î¾ì¹ç¤Ï EUC-JP ¤È Shift_JIS ¤â»È¤¨¤ë¤Ï¤º¤Ç¤¹¡£ nssep ¤ò»ØÄꤹ¤ë¤È̾Á°¶õ´Ö³ÈÄ¥¤¬Í­¸ú¤Ë¤Ê¤ê¤Þ¤¹¡£¥¨¥ì¥á ¥ó¥È¤ä°À­¤Î̾Á°¤Ë¥×¥ì¥Õ¥£¥Ã¥¯¥¹¤ò»ØÄꤹ¤ë¤È¡¤¥¨¥ì¥á¥ó ¥È̾¤ä°À­Ì¾¤¬ URI ¤È¥í¡¼¥«¥ë¥Ñ¡¼¥È¤òÏ¢·ë¤·¤¿Ì¾Á°¤Ë¤Ê ¤ê¤Þ¤¹¡£nssep ¤Ç»ØÄꤵ¤ì¤¿Ê¸»úÎó¤ÎºÇ½é¤Îʸ»ú¤¬¥»¥Ñ¥ì¡¼ ¥¿¤Ë¤Ê¤ê¤Þ¤¹¡£ Î㤨¤Ð ¤ò nssep = '!' ¤Ç¥Ñ¡¼¥¹¤¹¤ë¤È¡¤¥¨¥ì¥á¥ó¥È̾¤Ï http://www.yoshidam.net/ns/hoge!test ¤Ë¤Ê¤ê¤Þ¤¹¡£ ¥Ñ¡¼¥¹¤Î½ª¤ï¤Ã¤¿¥Ñ¡¼¥µ¥ª¥Ö¥¸¥§¥¯¥È¤ÎºÆÍøÍѤϤǤ­¤Ê¤¤¤Î ¤Ç¡¤¥Ñ¡¼¥¹Ëè¤Ë¥Ñ¡¼¥µ¥ª¥Ö¥¸¥§¥¯¥È¤òºîÀ®¤·¤Æ¤¯¤À¤µ¤¤¡£ new(parser, context, encoding = nil) ³°Éô¼ÂÂΥѡ¼¥¹ÍѤÎXML ¥Ñ¡¼¥µ¥ª¥Ö¥¸¥§¥¯¥È¤òºîÀ®¤·¤Þ¤¹¡£ ºîÀ®¤Ë¼ºÇÔ¤¹¤ë¤ÈXMLParserError Îã³°¤¬È¯À¸¤·¤Þ¤¹¡£ externalEntityRef ¥¤¥Ù¥ó¥È¤¬È¯À¸°Ê¹ß¤Ë¸Æ¤Ó½Ð¤»¤Þ¤¹¡£ parser ¤È¤·¤Æ XML ¥Ñ¡¼¥µ¥ª¥Ö¥¸¥§¥¯¥È¤ò»ØÄꤷ¤Æ²¼¤µ¤¤¡£ context ¤È¤·¤Æ externalEntityRef ¥¤¥Ù¥ó¥È¤Î¥Ñ¡¼¥¹¥³¥ó ¥Æ¥¯¥¹¥È¤¬»ØÄê¤Ç¤­¤Þ¤¹¡£ encoding ¤È¤·¤ÆÊ¸»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤ò³°Éô¤«¤é»ØÄꤹ¤ë ¤³¤È¤â¤Ç¤­¤Þ¤¹¡£ reset ¥á¥½¥Ã¥É¤ò¸Æ¤Ó½Ð¤¹¤³¤È¤ÇºÆÍøÍѤ¬²Äǽ¤Ç¤¹¡£ expatVersion() expat ¤Î¥Ð¡¼¥¸¥ç¥ó¤òÆÀ¤Þ¤¹¡£ getFeatureList Get a hash list of expat API's features. This method is for expat-1.95.5 or later. ¥á¥½¥Ã¥É parse(str = nil, isFinal = true) str ¤ò¥Ñ¡¼¥¹¤·¤Þ¤¹¡£¥Ñ¡¼¥¹·ë²Ì¤È¤·¤Æ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤¬ ¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£¥¤¥Æ¥ì¡¼¥¿¥Ö¥í¥Ã¥¯¤ò»ØÄꤷ¤¿¾ì¹ç¤Ï¡¤¥¤ ¥Ù¥ó¥È¥Ï¥ó¥É¥é¤Ï¸Æ¤Ó½Ð¤µ¤ì¤Þ¤»¤ó¡£ isFinal ¤Ï XML ¤ÎÅÓÃæ¤Þ¤Ç¥Ñ¡¼¥¹¤¹¤ë¾ì¹ç¤Ï false, ºÇ¸å ¤Þ¤Ç¤Î¾ì¹ç¤Ï true ¤ò»ØÄꤷ¤Æ²¼¤µ¤¤¡£¾Êά»þ¤Ï true ¤Ç¤¹¡£ °ú¿ô̵¤·¤Ç¸Æ¤Ó½Ð¤¹¤³¤È¤Ç¡¤¥Ñ¡¼¥¹¤Î½ªÎ»¤ò»Ø¼¨¤¹¤ë¤³¤È¤â ¤Ç¤­¤Þ¤¹¡£ str ¤È¤·¤Æ¥¹¥È¥ê¡¼¥à¤òÅϤ¹¤³¤È¤â¤Ç¤­¤Þ¤¹¡£String ¤ÎÇÉ À¸¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤Ï¤Ê¤¯¡¤public ¤Ê gets ¥á¥½¥Ã¥É¤ò»ý¤Ã ¤Æ¤¤¤ë¥ª¥Ö¥¸¥§¥¯¥È¤¬¥¹¥È¥ê¡¼¥à¤È¤ß¤Ê¤µ¤ì¤Þ¤¹¡£ ¤³¤Î¾ì¹ç¡¤isFinal ¤Î»ØÄê¤Ï̵»ë¤µ¤ì¡¤gets ¤¬ nil ¤òÊÖ¤¹¤Þ¤Ç¥Ñ¡¼¥¹¤·¤Þ¤¹¡£ ¥Ñ¡¼¥¹¥¨¥é¡¼¤ò¸¡½Ð¤¹¤ë¤È XMLParserError Îã³°¤¬È¯À¸¤·¤Þ¤¹¡£ done ¥Ñ¡¼¥¹¤ò½ªÎ»¤·¡¤¥Ñ¡¼¥µ¤Î»ÈÍѤ·¤¿¥á¥â¥ê¤ò²òÊü¤·¤Þ¤¹¡£ÄÌ ¾ï¤Ï GC ¤ËǤ¤»¤Æ¤·¤Þ¤Ã¤Æ¤âÌäÂꤢ¤ê¤Þ¤»¤ó¤¬¡¤³°Éô¥Ñ¥é¥á¡¼ ¥¿¼ÂÂΤò¥Ñ¡¼¥¹¤·¤¿¸å¤Ïɬ¤º externalEntityRef ¥¤¥Ù¥ó¥È Æâ¤Ç²òÊü¤·¤Æ¤¯¤À¤µ¤¤¡£ defaultCurrent ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥éÆâ¤Ç¸Æ¤Ó½Ð¤·¤Þ¤¹¡£default ¥¤¥Ù¥ó¥È¤òȯ À¸¤µ¤»¡¤¥Ñ¡¼¥¹Á°¤ÎÀ¸¤Î¥Ç¡¼¥¿¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥éÆâ¤Ç¤¹¤°¤µ¤Þ default ¥¤¥Ù¥ó¥È¤¬È¯À¸¤· ¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¥Ö¥í¥Ã¥¯Æâ¤Ç»È¤Ã¤¿¾ì¹ç¡¤¼¡¤Î¥¤¥Æ¥ì¡¼¥¿¥Ö¥í¥Ã ¥¯¸Æ¤Ó½Ð¤·¤¬ DEFAULT ¤Ë¤Ê¤ê¤Þ¤¹¡£default ¥Ï¥ó¥É¥é¡¼¤Ï ¸Æ¤Ó½Ð¤µ¤ì¤Ê¤¤¤³¤È¤ËÃí°Õ¤·¤Æ²¼¤µ¤¤¡£ setBase URL ¥Ù¡¼¥¹¤òÀßÄꤷ¤Þ¤¹¡£ÀßÄꤷ¤¿Ãͤϡ¤ unparsedEntityDecl ¥á¥½¥Ã¥É¤Ê¤É¤Î°ú¿ô¤È¤·¤ÆÅϤµ¤ì¤Þ¤¹¡£ line column byteIndex ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥éÆâ¤Ç¸Æ¤Ó½Ð¤·¤Þ¤¹¡£¸½ºß¤Î¥Ñ¡¼¥¹°ÌÃÖ¤òÊÖ ¤·¤Þ¤¹¡£ ¤Þ¤¿¡¤parse ¥á¥½¥Ã¥É¤¬ XMLParserError Îã³°¤ÇȯÀ¸¤·¤¿»þ ¤Ë¸Æ¤Ó½Ð¤¹¤È¥¨¥é¡¼°ÌÃÖ¤òÊÖ¤·¤Þ¤¹¡£ byteCount ¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥éÆâ¤Ç¸Æ¤Ó½Ð¤·¤Þ¤¹¡£¸½ºß¤Î¥¤¥Ù¥ó¥ÈÂоݤΠŤµ¤òÊÖ¤·¤Þ¤¹¡£ÆâÉô¼ÂÂÎ¤Ç¤Ï 0 ¤òÊÖ¤·¤Þ¤¹¡£ getSpecifiedAttributes °À­¤¬»ØÄꤵ¤ì¤¿Ãͤ«¡¤¥Ç¥Õ¥©¥ë¥ÈÃͤ«¤òÃΤ뤳¤È¤¬¤Ç¤­¤Þ ¤¹¡£ °À­Ì¾¤ò¥­¡¼¡¤»ØÄꤵ¤ì¤¿¤«¤É¤¦¤« (true/false) ¤ò ÃͤȤ¹¤ë¥Ï¥Ã¥·¥å¤òÊÖ¤·¤Þ¤¹¡£ startElement ¥¤¥Ù¥ó¥ÈÆâ¤Ç ¸Æ¤Ó½Ð¤·¤Æ¤¯¤À¤µ¤¤¡£ setParamEntityParsing(parsing) ³°Éô¥Ñ¥é¥á¡¼¥¿¼ÂÂÎ(³°Éô DTD ¥µ¥Ö¥»¥Ã¥È¤â´Þ¤à) ¤ò¥Ñ¡¼¥¹ ¤¹¤ë¤«¤É¤¦¤«¤ò»ØÄꤷ¤Þ¤¹¡£ parsing ¤Ë¤Ï PARAM_ENTITY_PARSING_NEVER (0) PARAM_ENTITY_PARSING_UNLESS_STANDALONE (1) PARAM_ENTITY_PARSING_ALWAYS (2) ¤Î¤¤¤º¤ì¤«¤ò»ØÄꤷ¤Æ¤¯¤À¤µ¤¤¡£ ³°Éô¥Ñ¥é¥á¡¼¥¿¥¨¥ó¥Æ¥£¥Æ¥£¤ò¥Ñ¡¼¥¹¤¹¤ë¾ì¹ç¡¤ externalEntityRef ¥¤¥Ù¥ó¥È¤¬¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£context ¤Ï nil ¤Ë¤Ê¤ê¤Þ¤¹¡£ setReturnNSTriplet(do_nst) ̾Á°¶õ´Ö¤¬Í­¸ú¤Ê¤È¤­¤Ë¡¤URI + ¥í¡¼¥«¥ë̾ + ¥×¥ì¥Õ¥£¥Ã ¥¯¥¹¤ò»È¤¦¤«¤É¤¦¤«»Ø¼¨¤·¤Þ¤¹¡£false ¤Î»þ¤ÏURI + ¥í¡¼¥« ¥ë̾¤Ç¤¹¡£ expat-1.95.3 °Ê¹ß¤Ç¤Ï¡¤Í×ÁÇ̾¤ËÂФ·¤Æ¤âÍ­¸ú¤Ç¤¹¡£ getInputContext ÆþÎϥХåե¡¤È¸½ºß¥Ñ¡¼¥¹°ÌÃÖ¤òÆÀ¤Þ¤¹¡£ getIdAttribute ID °À­¤Î̾Á°¤òÆÀ¤Þ¤¹¡£ startElement ¥¤¥Ù¥ó¥ÈÆâ¤Ç¸Æ¤Ó½Ð¤·¤Æ¤¯¤À¤µ¤¤¡£ reset(encoding) ¥Ñ¡¼¥µ¥ª¥Ö¥¸¥§¥¯¥È¤òºÆÍøÍѤ¹¤ë¤¿¤á¤Ë¥ê¥»¥Ã¥È¤·¤Þ¤¹¡£ encoding ¤È¤·¤ÆÊ¸»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤ò³°Éô¤«¤é»ØÄꤹ¤ë ¤³¤È¤â¤Ç¤­¤Þ¤¹¡£ This method is for the expat-1.95.3 or later. useForeignDTD(useDTD) Specifies to parse an external DTD subset without the DOCTYPE declaration. In externalEntityRef, sysID and pubID will be NULL. This method is for the expat-1.95.5 or later. See setParamEntityParsing also. ¥á¥½¥Ã¥É (¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é) startElement(name, attrs) ¥¨¥ì¥á¥ó¥È³«»Ï¥¿¥°¤ò¸«ÉÕ¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£name ¤Ï ¥¨¥ì¥á¥ó¥È̾¡¤attrs ¤Ï°À­Ì¾¤ò¥­¡¼¡¤Â°À­ÃͤòÃͤȤ¹¤ë¥Ï¥Ã ¥·¥å¤Ç¤¹¡£ endElement(name) ¥¨¥ì¥á¥ó¥È½ªÎ»¥¿¥°¤ò¸«ÉÕ¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£name ¤Ï ¥¨¥ì¥á¥ó¥È̾¤Ç¤¹¡£ character(data) ¥Æ¥­¥¹¥È¡¤CDATA ¥»¥¯¥·¥ç¥ó¤ò¸«ÉÕ¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ default ¥Ï¥ó¥É¥é¤¬Ì¤ÄêµÁ¤Î¤È¤­¤ÏÆâÉô¼ÂÂΤÏŸ³«¤µ¤ì¤Þ¤¹¡£ processingInstruction(target, data) PI ¤ò¸«ÉÕ¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ unparsedEntityDecl(entityName, base, systemId, publicId, notationName) ** OBSOLETE ** ²òÀÏÂоݳ°¼ÂÂÎÀë¸À¤ò¸«ÉÕ¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ entityName¡¤base¡¤systemId¡¤publicId¡¤notationName ¤Ï ¤½¤ì¤¾¤ì¼ÂÂÎ̾¡¤URL ¥Ù¡¼¥¹¡¤¥·¥¹¥Æ¥à¼±Ê̻ҡ¤¸ø³«¼±Ê̻ҡ¤ µ­Ë¡Ì¾¤Ç¤¹¡£URL ¥Ù¡¼¥¹¡¤µ­Ë¡Ì¾ ¤Ï nil ¤Ë¤Ê¤ë¤³¤È¤¬¤¢¤ê ¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤unparsedEntityDecl ¤¬ÄêµÁ¤µ ¤ì¤Æ¤¤¤ë¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤ UNPARSED_ENTITY_DECL ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ notationDecl(notationName, base, systemId, publicId) µ­Ë¡Àë¸À¤ò¸«ÉÕ¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ notationName¡¤base¡¤systemId¡¤publicId ¤Ï¤½¤ì¤¾¤ìµ­Ë¡ ̾¡¤URL ¥Ù¡¼¥¹¡¤¥·¥¹¥Æ¥à¼±Ê̻ҡ¤¸ø³«¼±Ê̻ҤǤ¹¡£URL ¥Ù¡¼ ¥¹¡¤¥·¥¹¥Æ¥à¼±Ê̻ҡ¤¸ø³«¼±ÊÌ»Ò ¤Ï nil ¤Ë¤Ê¤ë¤³¤È¤¬¤¢¤ê ¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤notationDecl ¤¬ÄêµÁ¤µ¤ì¤Æ¤¤ ¤ë¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤NOTATION_DECL ¥¤¥Ù¥ó¥È¤Î ȯÀ¸¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ externalEntityRef(context, base, systemId, publicId) ³°Éô¼ÂÂλ²¾È¤ò¸«ÉÕ¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ context¡¤base¡¤systemId¡¤publicId ¤Ï¤½¤ì¤¾¤ì¥Ñ¡¼¥¹¥³¥ó ¥Æ¥¯¥¹¥È¡¤URL ¥Ù¡¼¥¹¡¤¥·¥¹¥Æ¥à¼±Ê̻ҡ¤¸ø³«¼±Ê̻ҤǤ¹¡£ URL ¥Ù¡¼¥¹¡¤¸ø³«¼±ÊÌ»Ò ¤Ï nil ¤Ë¤Ê¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£ ¥Ñ¡¼¥¹¥³¥ó¥Æ¥¯¥¹¥È¤Ï³°Éô¼ÂÂΥѡ¼¥¹ÍѤΥѡ¼¥µ¤òÀ¸À®¤¹¤ë ¤È¤­¤Î context °ú¿ô¤È¤·¤ÆÍøÍѲÄǽ¤Ç¤¹¡£ ¤³¤Î¥¤¥Ù¥ó¥È¤Ç³°Éô¼ÂÂΤò¥Ñ¡¼¥¹¤·¤Ê¤±¤ì¤Ð¡¤³°Éô¼ÂÂΤϥѡ¼ ¥¹¤µ¤ì¤ë¤³¤È¤Ï¤¢¤ê¤Þ¤»¤ó¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤externalEntityRef ¤¬ÄêµÁ¤µ¤ì ¤Æ¤¤¤ë¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤ ETERNAL_ENTITY_DEF ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ Îã def externalEntityRef(context, base, systemId, publicId) extp = self.type.new(self, context) file = if base.nil?; systemId; else base + "/" + systemId; end extp.parse(open(file)) extp.done end ¥Æ¥¹¥ÈÈÇ expat ¤Ç¤Ï³°Éô¥Ñ¥é¥á¡¼¥¿¼ÂÂλ²¾È (¤ª¤è¤Ó³°Éô DTD ¥µ¥Ö¥»¥Ã¥È) ¤ò¸«ÉÕ¤±¤¿¾ì¹ç¤Ë¤â¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£¤³¤Î¾ì¹ç ¤Ï context ¤Ï nil ¤Ë¤Ê¤ê¤Þ¤¹¡£³°Éô¥Ñ¥é¥á¡¼¥¿¼ÂÂΤò¥Ñ¡¼ ¥¹¤¹¤ë¾ì¹ç¤Ïɬ¤º¤³¤Î¥Ï¥ó¥É¥éÆâ¤Ç¥Ñ¡¼¥¹¤·¡¤¥Ñ¡¼¥¹¤¬½ªÎ» ¤·¤¿¤é done ¤ò¸Æ¤Ó½Ð¤·¤Æ¤¯¤À¤µ¤¤¡£ setParamEntityParsing ¤â»²¾È¤·¤Æ¤¯¤À¤µ¤¤¡£ comment(data) ¥³¥á¥ó¥È¤ò¸«ÉÕ¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤comment ¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ë¤«¤É ¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤COMMENT ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë±Æ¶Á ¤òÍ¿¤¨¤Þ¤¹¡£ startCdata() CDATA ¥»¥¯¥·¥ç¥ó¤Î³«»Ï»þ¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£CDATA ¥»¥¯¥·¥ç ¥ó¤ÎÆâÍÆ¤Ïcharacter ¥¤¥Ù¥ó¥È¤ÇÊó¹ð¤µ¤ì¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤startCdata ¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ë ¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤START_CDATA ¥¤¥Ù¥ó¥È¤ÎȯÀ¸ ¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ endCdata() CDATA ¥»¥¯¥·¥ç¥ó¤Î½ªÎ»»þ¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤endCdata ¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ë¤« ¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤END_CDATA ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë±Æ ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ startNamespaceDecl(prefix, uri) Namespace Àë¸À¤µ¤ì¤¿¥¨¥ì¥á¥ó¥È¤Î³«»ÏÁ°¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ prefix ¤Ï xmlns °À­¤¬»ØÄꤵ¤ì¤¿¾ì¹ç¤Ï nil ¤Ë¤Ê¤ê¡¤uri ¤Ï¶õ URI ¤¬»ØÄꤵ¤ì¤¿¾ì¹ç¤Ë nil ¤Ë¤Ê¤ê¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤startNamespaceDecl ¤¬ÄêµÁ¤µ¤ì¤Æ ¤¤¤ë¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤ START_NAMESPACE_DECL ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ endNamespaceDecl(prefix) Namespace Àë¸À¤µ¤ì¤¿¥¨¥ì¥á¥ó¥È¤Î½ªÎ»¸å¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ prefix ¤Ï xmlns °À­¤¬»ØÄꤵ¤ì¤¿¾ì¹ç¤Ï nil ¤Ë¤Ê¤ê¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤endNamespaceDecl ¤¬ÄêµÁ¤µ¤ì¤Æ ¤¤¤ë¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤ END_NAMESPACE_DECL ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ startDoctypeDecl(doctypeName, sysid, pubid, has_internal_subset) DOCTYPE Àë¸À¤Îʸ½ñ·¿Ì¾¤ò¸«¤Ä¤±¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ doctypeName ¤Ïʸ½ñ·¿Ì¾¤Ç¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤startDoctypeDecl ¤¬ÄêµÁ¤µ¤ì¤Æ ¤¤¤ë¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤ START_DOCTYPE_DECL ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ endDoctypeDecl() DOCTYPE Àë¸À¤Î½ªÎ»»þ¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤endDoctypeDecl ¤¬ÄêµÁ¤µ¤ì¤Æ ¤¤¤ë¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤ END_DOCTYPE_DECL ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ default(data) ¾¤Î¥¤¥Ù¥ó¥È¤¬¸Æ¤Ó½Ð¤µ¤ì¤Ê¤«¤Ã¤¿¾ì¹ç¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ ¤³¤Î¥á¥½¥Ã¥É¤òÄêµÁ¤¹¤ë¤ÈÆâÉô¼ÂÂΤΟ³«¤¬Í޻ߤµ¤ì¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤default ¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤ë¤«¤É ¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤DEFAULT ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¡¤ÆâÉô¼Â ÂΤΟ³«¤Ë±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ defaultExpand(data) ¾¤Î¥¤¥Ù¥ó¥È¤¬¸Æ¤Ó½Ð¤µ¤ì¤Ê¤«¤Ã¤¿¾ì¹ç¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¡¤defaultExpand ¤¬ÄêµÁ¤µ¤ì¤Æ¤¤ ¤ë¤«¤É¤¦¤«¤À¤±¤¬¥Á¥§¥Ã¥¯¤µ¤ì¡¤DEFAULT ¥¤¥Ù¥ó¥È¤ÎȯÀ¸¤Ë ±Æ¶Á¤òÍ¿¤¨¤Þ¤¹¡£ defaultExpand ¤Ï default ¥á¥½¥Ã¥É¤ËÍ¥À褷¤Þ¤¹¡£ unknownEncoding(name) ¥Ñ¡¼¥¹³«»Ï»þ¤«¡¤XML Àë¸À¤Î¥Ñ¡¼¥¹»þ¤Ë̤ÃΤΥ¨¥ó¥³¡¼¥Ç¥£ ¥ó¥°¤ò¸¡½Ð¤·¤¿¾ì¹ç¤Ë°ìÅÙ¤À¤±¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ XMLEncoding ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤·¤Æ²¼¤µ¤¤¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¤Ë¤â¤³¤Î¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤¬¸Æ¤Ó ½Ð¤µ¤ì¡¤¥¤¥Æ¥ì¡¼¥¿¥Ö¥í¥Ã¥¯¤Ï¸Æ¤Ó½Ð¤µ¤ì¤Þ¤»¤ó¡£ ¾ÜºÙ¤Ï¼¡Àá¤ò»²¾È¤·¤Æ²¼¤µ¤¤¡£ notStandalone() standalone="yes" ¤Ç¤Ê¤¤»þ¡¤³°Éô DTD ¥µ¥Ö¥»¥Ã¥È¤ä¥Ñ¥é¥á¡¼ ¥¿¼ÂÂΤò»²¾È¤¹¤ë¤È¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ ¥¨¥é¡¼¤òȯÀ¸¤µ¤»¤¿¤¤¾ì¹ç¤Ï 0¡¤½èÍý¤ò³¹Ô¤µ¤»¤¿¤¤¾ì¹ç¤Ï 1 ¤òÊÖ¤·¤Æ¤¯¤À¤µ¤¤¡£ ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ»È¤¦¾ì¹ç¤Ë¤â¤³¤Î¥¤¥Ù¥ó¥È¥Ï¥ó¥É¥é¤¬¸Æ¤Ó ½Ð¤µ¤ì¡¤¥¤¥Æ¥ì¡¼¥¿¥Ö¥í¥Ã¥¯¤Ï¸Æ¤Ó½Ð¤µ¤ì¤Þ¤»¤ó¡£ expat ¤Ï³°Éô DTD ¥µ¥Ö¥»¥Ã¥È¤ä¥Ñ¥é¥á¡¼¥¿¼ÂÂΤò²ò·è¤Ç¤­ ¤Ê¤¤¤Î¤Ç¡¤¤³¤Î¥¤¥Ù¥ó¥È¤¬È¯À¸¤·¤¿¾ì¹ç¤Ï¾¤Î XML ¥×¥í¥»¥Ã ¥µ¤ò¸Æ¤Ó½Ð¤¹¤Ê¤ê¡¤½èÍý¤òÃæÃǤ¹¤ë¤Ê¤ê¤¹¤Ù¤­¤«¤â¤·¤ì¤Þ¤» ¤ó¡£ elementDecl(name, model) Í×ÁÇÀë¸À»þ¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ name ¤ÏÍ×ÁÇ̾¡¤model ¤Ï ÆâÍÆ¥â¥Ç¥ë¤ò¤¢¤é¤ï¤¹ [type, quant, name, [children_model, ...]] ¤Î¤è¤¦¤ÊÇÛÎó¤Ç¤¹¡£type ¤Ï "EMPTY"¡¤"ANY"¡¤"MIXED"¡¤ "CHOICE"¡¤"SEQ" ¤Î¤¤¤º¤ì¤«¡¤quant¤Ï ""¡¤"?"¡¤"*"¡¤"+" ¤Î¤¤¤º¤ì¤«¤Ç¤¹¡£name ¤Ï nil ¤«Í×ÁÇ̾¡¤children_model ¤Ï»Ò¥â¥Ç¥ë¤Ç¤¹¡£ If you use iterator, this method is not called, but to define this affects to cause ELEMENT_DECL event. attlistDecl(elname, attname, att_type, dflt, isrequired) °À­Àë¸À»þ¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£elname ¤ÏÍ×ÁÇ̾¡¤attname ¤Ï°À­Ì¾¡¤att_type ¤Ï°À­¤Î·¿¡¤dflt ¤Ï¾ÊάÃÍ¡¤ isrequired ¤Ï #REQUIRED ¤«¤É¤¦¤«¤ò¤¢¤é¤ï¤·¤Þ¤¹¡£ If you use iterator, this method is not called, but to define this affects to cause ATTLIST_DECL event. xmlDecl(version, encoding, standalone) ʸ½ñÀèÆ¬¤Î XML Àë¸À¤ª¤è¤Ó²òÀϲÄǽ¼ÂÂΤΥƥ­¥¹¥ÈÀë¸À»þ ¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£¥Æ¥­¥¹¥ÈÀë¸À¤Ç¤Ï version ¤¬ nil ¤Ë¡¤ XML Àë¸À¤Ç¤Ï encoding ¤¬ nil ¤Ë¤Ê¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡£ standalone ¤Ï -1¡¤0¡¤1 ¤ÎÃͤò¤È¤ê¤Þ¤¹¡£ If you use iterator, this method is not called, but to define this affects to cause XML_DECL event. entityDecl(entityName, isparameter_entity, value, base, systemId, publicId, notationName) ¼ÂÂÎÀë¸À»þ¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ If you use iterator, this method is not called, but to define this affects to cause ENTITY_DECL event. skippedEntity(entityName, is_parameter_entity) This method is for expat-1.95.4 or later. If you use iterator, this method is not called, but to define this affects to cause SKIPPED_ENTITY event. ̤ÃΤÎʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤Ë¤Ä¤¤¤Æ unknownEncoding ¥á¥½¥Ã¥É¤òÄêµÁ¤¹¤ë¤È¡¤¥Ñ¡¼¥¹³«»Ï»þ¤«¡¤XML Àë ¸À¤Î¥Ñ¡¼¥¹»þ¤Ë̤ÃΤΥ¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤ò¸¡½Ð¤·¤¿¾ì¹ç¤Ë°ìÅÙ¤À¤± ¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£¤³¤Î¥¤¥Ù¥ó¥È¤ò½èÍý¤¹¤ë¤³¤È¤Ç¡¤expat ¤ÎÂбþ¤· ¤Æ¤¤¤Ê¤¤Ê¸»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°(¾õÂÖÁ«°Ü¤Î¤Ê¤¤Â¿¥Ð¥¤¥È¥¨¥ó¥³¡¼ ¥Ç¥£¥ó¥°¤Î¤ß)¤ËÂбþ¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ unknownEncoding ¥á¥½¥Ã¥É¤òÄêµÁ¤¹¤ë¤È Perl ¤Î¥¨¥ó¥³¡¼¥Ç¥£¥ó¥° ¥Þ¥Ã¥×¤Ï»ÈÍѤµ¤ì¤Ê¤¯¤Ê¤ê¤Þ¤¹¡£ ¾¤Î¥¤¥Ù¥ó¥È¤È°ã¤Ã¤Æ¡¤¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ¸Æ¤Ó½Ð¤·¤¿¾ì¹ç¤â¥¤¥Ù¥ó ¥È¥Ï¥ó¥É¥é¤¬¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ °ú¿ô¤È¤·¤Æ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°Ì¾¤¬ÅϤµ¤ì¤Þ¤¹¡£ÌáÃͤȤ·¤Æ¤½¤Î¥¨¥ó ¥³¡¼¥Ç¥£¥ó¥°¤ËÂбþ¤·¤¿ XMLEncoding ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤·¤Æ²¼¤µ ¤¤¡£XMLEncoding ¥ª¥Ö¥¸¥§¥¯¥È°Ê³°¤òÊÖ¤¹¤È unknownEncoding ¥á¥½¥Ã ¥É¤¬Ì¤ÄêµÁ¤Î¾ì¹ç¤ÈƱÍͤÎÎã³°¤òȯÀ¸¤·¤Þ¤¹¡£ ¤³¤Îµ¡¹½¤Ë¤è¤ëʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°ÊÑ´¹¤Ï¤«¤Ê¤êÃÙ¤¤¤Ç¤¹¡£ XMLEncoding ¥¯¥é¥¹ ʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°ÊÑ´¹¤Î¤¿¤á¤Î¥¯¥é¥¹¤Ç¤¹¡£ÄêµÁºÑ¤ß¥á¥½¥Ã ¥É¤Ï Latin-1 ÁêÅö¤ÎÊÑ´¹¤ò¹Ô¤Ê¤¤¤Þ¤¹¡£¤½¤Î¤Þ¤Þ»È¤¦¤³¤È¤Ï̵ °ÕÌ£¤Ê¤Î¤Ç¡¤Å¬ÀÚ¤ÊÊÑ´¹¤ò¹Ô¤Ê¤¦¤è¤¦¥á¥½¥Ã¥É¤òÄêµÁ¤·¤Ê¤ª¤·¤Æ »È¤Ã¤Æ²¼¤µ¤¤¡£ ¥á¥½¥Ã¥É map(code) ¤½¤Î¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤Î¥Ð¥¤¥ÈÎó¾ðÊó¤òÄêµÁ¤¹¤ë¤¿¤á¤ËÆâÉô Ū¤Ë¸Æ¤Ó½Ð¤µ¤ì¤Þ¤¹¡£ code ¤Ï¥Ð¥¤¥ÈÎó¤ÎºÇ½é¤Î¥Ð¥¤¥È¤Î¥³¡¼¥É¥Ý¥¤¥ó¥È¤Ç¡¤00h ¤«¤é FFh ¤Þ¤Ç¤ÎÀ°¿ô¤¬ÅϤµ¤ì¤Þ¤¹¡£ ÌáÃͤȤ·¤Æ°Ê²¼¤Î¤¤¤º¤ì¤«¤ÎÃͤòÀ°¿ô¤ÇÊÖ¤·¤Æ²¼¤µ¤¤¡£ 0 °Ê¾å : Unicode ¤Î¥³¡¼¥É¥Ý¥¤¥ó¥È -1 : ÉÔÀµ¤Ê¥Ð¥¤¥ÈÎó -n : n ¥Ð¥¤¥È¤Î¿¥Ð¥¤¥ÈÎó (2<=n<=4) Î㤨¤Ð¡¤ÆüËܸì EUC (JIS X 0201 ¥«¥Ê¤È JIS X 0212 Êä½õ ´Á»ú̵¤·)¤Î¾ì¹ç¤Ï°Ê²¼¤Î¤è¤¦¤Ê map ¥á¥½¥Ã¥É¤òÄêµÁ¤·¤Æ²¼ ¤µ¤¤¡£ def map(i) return i if i < 128 return -1 if i < 160 or i == 255 return -2 end ISO-2022-JP ¤Î¤è¤¦¤Ê¾õÂÖÁ«°Ü¤ò¹Ô¤Ê¤¦¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°¤Ë ¤ÏÂбþ¤Ç¤­¤Þ¤»¤ó¡£ convert(s) ʸ»ú¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°ÊÑ´¹¤Î¤¿¤áÆâÉôŪ¤Ë°ìʸ»úËè¤Ë¸Æ¤Ó½Ð ¤µ¤ì¤Þ¤¹¡£ s ¤Ï map ¤ÇÄêµÁ¤µ¤ì¤¿Ä¹¤µ¤Î¿¥Ð¥¤¥ÈÎó¤Ç¤¹¡£ÌáÃͤȤ·¤Æ¡¤ Unicode ¤Î¥³¡¼¥É¥Ý¥¤¥ó¥È(65535 °Ê²¼¤ÎÀ°¿ô) ¤«¡¤ASCII ʸ»ú¤«¡¤ ¥ê¥È¥ë¥¨¥ó¥Ç¥£¥¢¥ó¤Î UCS2 ʸ»úÎó¤òÊÖ¤·¤Æ²¼¤µ¤¤¡£ ¼ÂÁõÎã class EUCHandler XPointer support is contributed by Masaki Fukushima - ÍúÎò Feb 28, 2011 version 0.7.2 digest.rb ¤òºÆ¼ýÏ¿ Dec 28, 2009 version 0.7.1 Ruby 1.9.1 ¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°ÊÑ´¹Âбþ Dec 15, 2009 version 0.7.0 Ruby 1.9.1 Âбþ Apr 5, 2004 version 0.6.8 fixes overflow, and taints output. Mar 11, 2003 version 0.6.6 ³°Éô¼ÂÂΥѡ¼¥µÀ¸À®»þ¤ÎskippedEntity¥Ï¥ó¥É¥é¤Î ½é´ü²½Ëº¤ì¤ò½¤Àµ Sep 20, 2002 version 0.6.5 fixes reset adds skippedEntity event for expat-1.95.4 adds XML::Parser.getFeatureList and XML::Parser#useForeignDTD for expat-1.95.5 Jun 18, 2002 version 0.6.4 expat-1.95.3 ÍÑ¤Ë XML::Parser#reset Äɲà Mar 23, 2002 version 0.6.2 lib ¤Î¥ì¥¤¥¢¥¦¥ÈÊѹ¹ XML::Parser::Error ¤Î¿Æ¥¯¥é¥¹Êѹ¹ DOM Level 2 ¤Î¼Â¸³ÅªÂбþ ̾Á°¶õ´Ö¤Î¼Â¸³ÅªÂбþ (XML::ParserNS) Oct 15, 2000 version 0.6.1 expat-1.95.0¡¤expat-1.2 Âбþ Aug 5, 2000 version 0.5.19 ¹â¶¶À¬µÁ¤µ¤ó¤¬ xmltree.rb Åù¤ò RD ²½¤·¤Æ¤¯¤À¤µ¤¤¤Þ¤·¤¿¡£ May 30, 2000 version 0.5.18 ruby 1.5 ¤Çư¤«¤Ê¤¯¤Ê¤Ã¤Æ¤¤¤¿¤Î¤Ç½¤Àµ Jan 4, 2000 version 0.5.17 NodeList#+ ¤ÎÌäÂ꽤Àµ (Masatoshi SEKI ¤µ¤ó¤¢¤ê¤¬¤È¤¦¤´¤¶¤¤¤Þ¤¹) Oct 14, 1999 version 0.5.16 ¤¤¤¯¤Ä¤«¤Î¥µ¥ó¥×¥ë¥×¥í¥°¥é¥à¤òÊѹ¹ Aug 18, 1999 version 0.5.15 expat-19990728 ¤Î start/endDoctypeDecl ¤Ë Âбþ SAX ¥É¥é¥¤¥Ð¤Î¥Ð¥°½¤Àµ Jun 29, 1999 version 0.5.14 expat-19990626 ¤Î³°Éô¥Ñ¥é¥á¡¼¥¿¼ÂÂÎ (¤ª¤è¤Ó³°Éô DTD ¥µ¥Ö¥»¥Ã¥È)¤ÎÆÉ¤ß¹þ¤ß¤ËÂбþ Ruby-1.2 ¥µ¥Ý¡¼¥È¤òÃæ»ß¡£ Jun 10, 1999 version 0.5.13 ¼Â¸³Åª SAX ¥É¥é¥¤¥Ð¤òÄɲà expat-1.1 Âбþ May 13, 1999 version 0.5.12 extconf.rb ¤Î¥Ð¥°½¤Àµ (Æ£Ëܾ°Ë®¤µ¤ó¤¢¤ê ¤¬¤È¤¦¤´¤¶¤¤¤Þ¤¹) Apr 28, 1999 version 0.5.11 expat-19990425 ¤ËÂбþ¤·¡¤ NotStandalone ¥¤¥Ù¥ó¥È¡¤getSpecifiedAttributes, byteCount ¥á¥½¥Ã¥ÉÄɲà Apr 20, 1999 version 0.5.10 xss4j ¤ò»²¹Í¤Ë¤·¤Æ xmldigest.rb ¤òÊѹ¹ Mar 29, 1999 version 0.5.9 Ruby 1.3 ÍѤ˥ª¥Ö¥¸¥§¥¯¥È¤Î¹½Â¤¤òÊѹ¹ Mar 23, 1999 version 0.5.8 XPointer ¤Î¥­¡¼¥ï¡¼¥É¤Î¾Êά¤ò²Äǽ¤Ë¤·¤¿ XML::DOM::Builder ¤Ç³°Éô¥Ñ¡¼¥¹¼ÂÂΤνèÍý¤òÄɲà Mar 8, 1999 version 0.5.7 expat-19990307 ¤Î start/endNamespaceDecl ¥¤¥Ù¥ó¥È¤ËÂбþ Jan 25, 1999 version 0.5.6 ¥¯¥é¥¹Ì¾¤ÎÊÌ̾¤ò C ¥â¥¸¥å¡¼¥ëÆâ¤Ë°Üư Cygwin ¤Çưºî¤µ¤»¤ë¤¿¤á¤ÎÊѹ¹ Jan 14, 1999 version 0.5.5 expat-19981231 ¤Î start/endCdataSection ¥¤¥Ù¥ó¥È¤ËÂбþ xmltreebuilder ¤ò¥Æ¥¹¥ÈÈÇ expat ¤ËÂбþ¤µ¤»¤¿ (comment, CDATA) Node#trim ¤ò CDATA ¥»¥¯¥·¥ç¥ó¤â trim ¤¹¤ë¤è¤¦¤Ë²þ¤ Jan 13, 1999 version 0.5.4 xmltree, xmltreebuilder ²þ¤ (¥Ð¥°¤¬Æþ¤Ã¤¿¤«¤â) Jan 10, 1999 version 0.5.3 Perl ÍÑ encoding map Âбþ Jan 1, 1999 version 0.5.2 expat-19981231 Âбþ Dec 1, 1998 version 0.5.1 ÌäÂêÅÀ½¤Àµ(Ê¡ÅèÀµµ¡¤µ¤ó¤¢¤ê¤¬¤È¤¦¤´¤¶¤¤¤Þ¤¹) Nov 24, 1998 version 0.5.0 ¥Æ¥¹¥ÈÈÇ expat Âбþ Nov 5, 1998 version 0.4.18 ¥Ð¥°½¤Àµ(Ê¡ÅèÀµµ¡¤µ¤ó¤¢¤ê¤¬¤È¤¦¤´¤¶¤¤¤Þ¤¹) ¥¯¥é¥¹Ì¾¤ËÊÌ̾ÄêµÁ XMLParserError -> XML::Parser::Error ¥á¥½¥Ã¥É ID ¤Î½é´ü²½°ÌÃÖÊѹ¹ xmltreebuilder ¤Ç Ruby ¤Î¥Ð¥°?²óÈò Oct 28, 1998 version 0.4.17 ¥á¥½¥Ã¥É ID ¤òÀÅŪÊÑ¿ô¤Ë°Ü¤·¤¿ Oct 28, 1998 version 0.4.16 XPointer »ÈÍÑ»þ¤Î ID °À­¤ò³°Éô¤«¤é»ØÄê²Äǽ¤Ë¤·¤¿ Node#trim ¤ò xml:space Âбþ¤Ë¤·¤¿ Oct 23, 1998 version 0.4.15 ¥Ð¥°½¤Àµ¡¤¥¯¥é¥¹Ì¾¤ËÊÌ̾ÄêµÁ XMLParser -> XML::Parser XML::SimpleTree -> XML::DOM XML::SimpleTreeBuilder -> XML::DOM::Builder Oct 20, 1998 version 0.4.14 Ê¡ÅèÀµµ¡¤µ¤ó¤Ë¤è¤ë XPointer ¥µ¥Ý¡¼¥È¤òÄɲà Oct 18, 1998 version 0.4.13 SimpleTree ¤Î¥Ð¥°½¤Àµ¡¤Visitor Äɲà Oct 13, 1998 version 0.4.12 ¥Ð¥°½¤Àµ¡¤¥¨¥ó¥³¡¼¥Ç¥£¥ó¥°ÊÑ´¹Éô¤Î¹â®²½ Oct 7, 1998 version 0.4.11 ¥Ñ¡¼¥µÆâÉô¤Î¥ª¥Ö¥¸¥§¥¯¥È´ÉÍý¤ÎÊѹ¹ Oct 4, 1998 version 0.4.9 ºÙ¤«¤¤¥Ð¥°½¤Àµ¡¤DOM ´«¹ðÂбþ¤Ê¤É Sep 22, 1998 version 0.4.8 ¥¹¥È¥ê¡¼¥à¤Î»ÅÍͤò¾¯¤·Êѹ¹ Sep 21, 1998 version 0.4.7 SimpleTree, SimpleTreeBuilder ¤Ë Comment ¤Ê¤ÉÄɲà Sep 18, 1998 version 0.4.6 UnknownEncoding ¥¤¥Ù¥ó¥È¤ËÂбþ Sep 17, 1998 version 0.4.5 SimpleTree ¤Ë¥á¥½¥Ã¥ÉÄɲà Sep 8, 1998 version 0.4.4 ¥Ñ¡¼¥µ¥ª¥Ö¥¸¥§¥¯¥È¤¬ T_DATA ¤«¤é T_OBJECT ¤ËÊѹ¹ Sep 3, 1998 version 0.4.3 isFinal ¥Õ¥é¥°¤òÄɲᤥ¹¥È¥ê¡¼¥àÂбþ Sep 2, 1998 version 0.4.2 ³°Éô¼ÂÂÎ¥¤¥Ù¥ó¥È¡¤³°Éô¼ÂÂΥѡ¼¥µÄɲà Aug 14, 1998 version 0.3.3 expat 1.0 Âбþ Aug 12, 1998 version 0.3.2 SimpleTree ¤Ë XPointer ¤â¤É¤­¤òÄɲà (root, child ,id ¤Î¤ß¥µ¥Ý¡¼¥È) Aug 4, 1998 version 0.3.1 ¥é¥¤¥Ö¥é¥êÄɲá¤expat_ja ưºî³Îǧ Jul 17, 1998 version 0.3 ¥¤¥Æ¥ì¡¼¥¿¥Ö¥í¥Ã¥¯Æâ¤Î defaultCurrent ¤ËÂбþ Jul 3, 1998 version 0.2 ¥¤¥Æ¥ì¡¼¥¿¤ËÂбþ Jul 1, 1998 version 0.1 ¥ê¥ê¡¼¥¹ xmlparser/lib/xmltreebuilder.rb0000644000076400007640000000003207633545642017452 0ustar yoshidamyoshidamrequire 'xml/dom/builder' xmlparser/lib/xmltree.rb0000644000076400007640000000002707633545642016107 0ustar yoshidamyoshidamrequire 'xml/dom/core' xmlparser/lib/xmltreevisitor.rb0000644000076400007640000000003207633545642017523 0ustar yoshidamyoshidamrequire 'xml/dom/visitor' xmlparser/lib/xmldigest.rb0000644000076400007640000000003107633545642016422 0ustar yoshidamyoshidamrequire 'xml/dom/digest' xmlparser/lib/wget.rb0000644000076400007640000000230207633552733015372 0ustar yoshidamyoshidam## -*- Ruby -*- ## URLopen ## 1999 by yoshidam ## ## TODO: This module should be writen by Ruby instead of wget/lynx. module WGET PARAM = { 'wget' => nil, 'opts' => nil, 'http_proxy' => nil, 'ftp_proxy' => nil } def open(url, *rest) raise TypeError.new("wrong argument type #{url.inspect}" + " (expected String)") if url.class != String if url =~ /^\/|^\./ || (url !~ /^http:|^ftp:/ && FileTest.exist?(url)) File::open(url, *rest) else ENV['http_proxy'] = PARAM['http_proxy'] if PARAM['http_proxy'] ENV['ftp_proxy'] = PARAM['ftp_proxy'] if PARAM['ftp_proxy'] IO::popen(PARAM['wget'] + ' ' + PARAM['opts'] + ' ' + url) end end module_function :open end [ '/usr/local/bin/wget', '/usr/bin/wget', '/usr/local/bin/lynx', '/usr/bin/lynx', '/usr/local/bin/lwp-request', '/usr/bin/lwp-request' ].each do |p| if FileTest.executable?(p) WGET::PARAM['wget'] = p case p when /wget$/ WGET::PARAM['opts'] = '-q -O -' when /lynx$/ WGET::PARAM['opts'] = '-source' when /lwp-request$/ WGET::PARAM['opts'] = '-m GET' end break end end raise "wget not found" if !WGET::PARAM['wget'] xmlparser/lib/sax.rb0000644000076400007640000000002207633545642015215 0ustar yoshidamyoshidamrequire 'xml/sax' xmlparser/lib/saxdriver.rb0000644000076400007640000000003007633545642016430 0ustar yoshidamyoshidamrequire 'xml/saxdriver' xmlparser/extconf.rb0000644000076400007640000000360510205406004015305 0ustar yoshidamyoshidam# # ruby extconf.rb # --with-perl-enc-map[=/path/to/enc-map] # --with-expat-dir=/path/to/expat # --with-expat-lib=/path/to/expat/lib # --with-expat-include=/path/to/expat/include # require 'mkmf' cwd=`pwd`.chomp! perl= ENV['PERL'] || 'perl' ## Encoding maps may be stored in $perl_archlib/XML/Parser/Encodins/ #perl_archlib = '/usr/lib/perl5/site_perl/5.005/i586-linux' #perl_archlib = '/usr/local/lib' perl_archlib = `#{perl} -e 'use Config; print $Config{"archlib"}'` xml_enc_path = with_config("perl-enc-map") if xml_enc_path == true xml_enc_path = perl_archlib + "/XML/Parser/Encodings" end ##$CFLAGS="-I#{cwd}/expat/xmlparse -I#{cwd}/expat/xmltok" + ## ' -DXML_ENC_PATH=getenv\(\"XML_ENC_PATH\"\)' + ## " -DNEW_EXPAT" #$CFLAGS = "-I#{cwd}/expat/xmlparse -I#{cwd}/expat/xmltok" #$LDFLAGS = "-L#{cwd}/expat/xmlparse -Wl,-rpath,/usr/local/lib" #$LDFLAGS = "-L#{cwd}/expat/xmlparse" dir_config("expat") #dir_config("xmltok") #dir_config("xmlparse") if xml_enc_path $CFLAGS += " -DXML_ENC_PATH=\\\"#{xml_enc_path}\\\"" end #if have_header("xmlparse.h") || have_header("expat.h") if have_header("expat.h") || have_header("xmlparse.h") if have_library("expat", "XML_ParserCreate") || have_library("xmltok", "XML_ParserCreate") if have_func("XML_SetNotStandaloneHandler") $CFLAGS += " -DNEW_EXPAT" end if have_func("XML_SetParamEntityParsing") $CFLAGS += " -DXML_DTD" end # if have_func("XML_SetExternalParsedEntityDeclHandler") # $CFLAGS += " -DEXPAT_1_2" # end have_func("XML_SetDoctypeDeclHandler") have_func("XML_ParserReset") have_func("XML_SetSkippedEntityHandler") have_func("XML_GetFeatureList") have_func("XML_UseForeignDTD") have_func("XML_GetIdAttributeIndex") have_library("socket", "ntohl") have_library("wsock32") if RUBY_PLATFORM =~ /mswin32|mingw/ create_makefile("xmlparser") end end xmlparser/README0000644000076400007640000005652511532727512014221 0ustar yoshidamyoshidam Expat (XML Parser Toolkit) Module for Ruby version 0.7.2 Yoshida Masato - Introduction This is a module to access to James Clark's XML Parser Toolkit "expat" (http://www.jclark.com/xml/expat.html) from Ruby. Supported versions of expat are 1.95.0 or later (http://sourceforge.net/projects/expat/). - Installation This can work with ruby-1.6. I recommend you to use ruby-1.6.7 or later. And you need the source code of expat-1.95.x. First, compile expat. With expat-1.95.x, configure; make; make install. Then, compile xmlparser. You can specify the location of expat's header file or library file. --with-expat-dir=/path/to/expat or --with-expat-lib=/path/to/expat/lib --with-expat-include=/path/to/expat/inclide If you want to use encoding maps of XML::Parser of Perl, set the proper directory with --with-perl-enc-map option. For example: ruby extconf.rb --with-expat-dir=/usr/local --with-perl-enc-map=/usr/local/share/XML/Parser/Encodings make make site-install - Usage If you do not link this module with Ruby statically, require "xml/parser" before using. There is two styles to get parsing result. One is to define instance methods as event handlers, another is to use iterator. To define event handlers is like SAX (Simple API for XML). If you use event handlers, inherit XMLParser class and define instance methods as event handlers. Or you may use the instance of XMLParser class (or derived) with singleton instance methods as event handlers. When no event handlers are defined, this parser does non-validating syntax checking only. method name | event -------------------------+--------------------------- startElement | element start tag endElement | element end tag character | character data processingInstruction | processing instruction unparsedEntityDecl | unparsed entity declaration(OBSOLETE) notationDecl | notation declaration externalEntityRef | external entity reference comment | comment startCdata | CDATA section start endCdata | CDATA section end startNamespaceDecl | Namespace declaration start endNamespaceDecl | Namespace declaration end startDoctypeDecl | DOCTYPE declaration start endDoctypeDecl | DOCTYPE declaration end notStandalone | document is not standalone default | other data defaultExpand | same as default (*1) unknownEncoding | unknown character encoding elementDecl | element declaration attlistDecl | attlist declaration xmlDecl | XML declaration entityDecl | entity declaration *1 inhibits expansion of internal entities. defaultExpand have higher priority than default. To use iterator is probably a ruby-ish manner. If you use iterator, this parser ignores event handlers even if they are defined. The iterator evaluates the iterator block with three variables, event type, name, and data. event type | name | data ----------------------------------+-----------------+------------------- START_ELEM | element name | hash of attributes END_ELEM | element name | nil CDATA | nil | string PI | PI name | string UNPARSED_ENTITY_DECL(OBSOLETE) | entity name | array (*1) NOTATION_DECL | notation name | array (*2) EXTERNAL_ENTITY_REF | entity names(*5)| array (*2) COMMENT | nil | string START_CDATA | nil | nil END_CDATA | nil | nil START_NAMESPACE_DECL | prefix | URI END_NAMESPACE_DECL | prefix | nil START_DOCTYPE_DECL | doctype name | nil END_DOCTYPE_DECL | nil | nil DEFAULT (*4) | nil | string ELEMENT_DECL | element name | array (*8) ATTLIST_DECL | element name | array (*9) XML_DECL | nil | array (*10) ENTITY_DECL | entity name | array (*11) *1 [URL base, system ID, public ID, notation name] URL base and notation name may be nil. *2 [URL base, system ID, public ID] URL base, system ID and public ID may be nil. *4 defaultExpand enables this event *5 It may be nil *8 [type, quant, name, [...]] *9 [attname, atttype, default, isrequired] *10 [version, encoding, standalone] *11 [isPE, value, system ID, public ID, notation name] UNPARSED_ENTITY_DECL, NOTATION_DECL, EXTERNAL_ENTITY_REF, COMMENT, START_CDATA, END_CDATA, START_NAMESPACE_DECL, END_NAMESPACE_DECL, DEFAULT, ELEMENT_DECL, ATTLIST_DECL, XML_DECL and ENTITY_DECL events are generated only if each dummy methods, "unparsedEntityDecl", "notationDecl", "externalEntityRef", "comment", "startCdata", "endCdata", "startNamespaceDecl", "endNamespaceDecl", "default" (or "defaultExpand"), "elementDecl", "attlistDecl", "xmlDecl" and "entityDecl" are defined. Supported input character encodings are UTF-8 and UTF-16. Output character encoding is UTF-8. If XML_ENC_PATH is set on compiling, you can use the encoding maps of XML::Parser of Perl. This package not include them, you must get XML::Parser or XML::Encoding from CPAN, and install .enc files into the proper directory. XMLParser class: Class method new(encoding = nil, nssep = nil) Create a XML parser object. A failure of the creation raises a XMLParserError exception. The "encoding" parameter can specify the character encoding. Expat can recognize ISO-8859-1, UTF-8, US-ASCII and UTF-16, and expat_ja can also EUC-JP and Shift_JIS. The "nssep" parameter enables namespace extension. The namespace-prefixed element and attribute names are concatenated with the namespace's URI and a separator (the first byte of nssep). For example, with nssep = '!', is parsed into http://www.yoshidam.net/ns/hoge!test The object that finish parsing cannot be reused, so you must create a new one for every parsing. new(parser, context, encoding = nil) Create a XML parser object that can parse an external general entity. A failure of the creation raises a XMLParserError exception. This can be called at any point after the first call to an externalEntityRef event. The "context" parameter can be passed from the parse context of externalEntityRef event. The "encoding" parameter can specify the character encoding. Call "reset" to be reused. expatVersion() Get expat version. getFeatureList Get a hash list of expat API's features. This method is for expat-1.95.5 or later. Method parse(str, isFinal = true) Parse a string. This method can be an iterator. Parsing results can be processed by event handlers or an iterator block. "IsFinal" parameter must true on last call of this method. Default is true. No parameter call of this method indicates the end of parsing. "Str" can be a stream object. It must be an object with "gets" method. In this case, "isFinal" is ignored, the parsing is repeated until the stream returns nil. A failure to parse raises a XMLParserError exception. done Free the parser. Usually you can trust the GC, but after parsing the external parameser entity, you must free the parser in the externalEntityRef event. defaultCurrent Raise a "default" event within any event handlers or an iterator block. You can get the corresponding markup. If within a event handler, it raise a default event immediately. But within an iterator block, the next yielding will be a DEFAULT event. setBase Set URL base. The setting value can get the parameter 'base' of the external entity methods, such as unparsedEntityDecl. line column byteIndex Get current parsing location. When a "parse" method raises XML::Parser::Error, these method return the position of the error detected. byteCount Get the number of bytes in the current event. When the event is is in an internal entity, this method returns 0. getSpecifiedAttributes Check the attributes whether specified or defaulted. Return value is a hash, the keys are the attribute's name, the values are specified or not (boolean). This method should be used in startElement event handler. setParamEntityParsing(parsing) Controls parsing of parameter entities (including the external DTD subset ). "Parsing" parameter is PARAM_ENTITY_PARSING_NEVER (0) or PARAM_ENTITY_PARSING_UNLESS_STANDALONE (1) or PARAM_ENTITY_PARSING_ALWAYS (2). References to external parameter entities will invoke the externalEntityRef event. The context will be nil. setReturnNSTriplet(do_nst) Sets namespace triplet flag. It will work well for element names with Expat-1.95.3 or later getInputContext Returns the parser's input buffer and current parse posion. getIdAttribute Gets the ID attribute name. This method should be used in startElement event handler. reset(encoding) Resets the parser object to be reused. The "encoding" parameter can specify the character encoding. This method is for the expat-1.95.3 or later. useForeignDTD(useDTD) Specifies to parse an external DTD subset without the DOCTYPE declaration. In externalEntityRef, sysID and pubID will be NULL. This method is for the expat-1.95.5 or later. See setParamEntityParsing also. Method (event handler) startElement(name, attrs) This method is called when element start tags are detected. "Name" is the element name, attrs is a hash of attributes, the keys are the attribute's name, the values are attribute's values. endElement(name) This method is called when element end tags are detected. "Name" is the element name. character(data) This method is called when texts or CDATA sections are detected. Internal entities are expanded as long as "default" handler is not defined. processingInstruction(target, data) This method is called when processing instructions are detected. unparsedEntityDecl(entityName, base, systemId, publicId, notationName) ** OBSOLETE ** This methods is called when parsed entity declarations are detected. "EntityName", "base", "systemId", "publicId" and "notationName" are the entity name, the URL base, the system identifier, the public identifier and the notation name. The URL base and the notation name can be nil. If you use iterator, this method is not called, but to define this affects to cause UNPARSED_ENTITY_DECL event. notationDecl(notationName, base, systemId, publicId) This methods is called when notation declarations are detected. "NotationName", "base", "systemId", and "publicId" are the notation name, the URL base, the system identifier and the public identifier. The URL base, the system identifier and the public identifier can be nil. If you use iterator, this method is not called, but to define this affects to cause NOTATION_DECL event. externalEntityRef(context, base, systemId, publicId) This methods is called when external entity references are detected. "context", "base", "systemId", and "publicId" are the parsing context, the URL base, the system identifier and the public identifier. The URL base and the public identifier can be nil. The context can use the 'context' parameter of the constructor of the external entity parser. If you do not parse the external entities by this event, the external entities are never parsed. If you use iterator, this method is not called, but to define this affects to cause EXTERNAL_ENTITY_REF event. On expat-19990626 or later, it is called when external parameter entity refs (including external DTD subset) are detected. In this case, "context" will be nil. The parser for the external parameter entitiy must be created, "parse" and "done" in this event. See setParamEntityParsing also. comment(data) This methods is called when comments are detected. If you use iterator, this method is not called, but to define this affects to cause COMMENT event. startCdata() This methods is called when CDATA sections start. The contents of the CDATA sections are reported by character event. If you use iterator, this method is not called, but to define this affects to cause START_CDATA event. endCdata() This methods is called when CDATA sections end. If you use iterator, this method is not called, but to define this affects to cause END_CDATA event. startNamespaceDecl(prefix, uri) This methods is called before the element that has namespace declaration. Prefix and uri can be nil. If you use iterator, this method is not called, but to define this affects to cause START_NAMESPACE_DECL event. endNamespaceDecl(prefix) This methods is called after the element that has namespace declaration. Prefix can be nil. If you use iterator, this method is not called, but to define this affects to cause END_NAMESPACE_DECL event. startDoctypeDecl(doctypeName, sysid, pubid, has_internal_subset) This methods is called when the name of the DOCTYPE is encountered. If you use iterator, this method is not called, but to define this affects to cause START_DOCTYPE_DECL event. endDoctypeDecl() This methods is called when the closing > is encountered, but after processing any external subset. If you use iterator, this method is not called, but to define this affects to cause END_DOCTYPE_DECL event. default(data) This method is called when there is no applicable event handler. If this method is defined, expansion of internal entities are inhibited. If you use iterator, this method is not called, but to define this affects to cause DEFAULT event and to inhibit expansion of internal entities. defaultExpand(data) This method is called when there is no applicable event handler. If you use iterator, this method is not called, but to define this affects to cause DEFAULT event. This method have higher priority than default method. unknownEncoding(name) This method is called when unknown encoding is detected. XMLEncoding object (or nil to reject) must be returned. Even if parse method is used as the iterator, this method is called. notStandalone() This methods is called if the document is not standalone (it has an external subset or a reference to a parameter entity, but does not have standalone="yes"). If you may return 0 to raise an error, or return 1 to continue the parsing. Even if parse method is used as the iterator, this method is called. elementDecl(name, model) If you use iterator, this method is not called, but to define this affects to cause ELEMENT_DECL event. attlistDecl(elname, attname, att_type, dflt, isrequired) If you use iterator, this method is not called, but to define this affects to cause ATTLIST_DECL event. xmlDecl(version, encoding, standalone) If you use iterator, this method is not called, but to define this affects to cause XML_DECL event. entityDecl(entityName, isparameter_entity, vale, base, systemId, publicId, notationName) If you use iterator, this method is not called, but to define this affects to cause ENTITY_DECL event. skippedEntity(entityName, is_parameter_entity) This method is for expat-1.95.4. If you use iterator, this method is not called, but to define this affects to cause SKIPPED_ENTITY event. XMLEncoding class: To convert the character encoding, you must define map and convert method. Method map(code) This method is called to define byte stream information. Code is the first byte of stream, 00h to ffh. You must return the following value. >= 0 : treat as Unicode value -1 : the byte sequence is malformed -n (n>=2): n-byte sequence convert(s) This method is called to convert the byte sequence into a Unicode. The byte sequence is n-byte string (n is defined by map), you must return an integer value (treat as Unicode code point [<=65535]), an ASCII character or two byte string (treat as a little endian UCS-2 character). Exapmle: class EUCHandler XPointer support is contributed by Masaki Fukushima - History Feb 28, 2011 version 0.7.2 reverts once removed digest.rb Dec 28, 2009 version 0.7.1 Ruby 1.9.1 encoding conversion Dec 15, 2009 version 0.7.0 Ruby 1.9.1 Apr 5, 2004 version 0.6.8 fixes overflow, and taints output. Sep 20, 2002 version 0.6.5 fixes reset adds skippedEntity event for expat-1.95.4 adds XML::Parser.getFeatureList and XML::Parser#useForeignDTD for expat-1.95.5 Jun 18, 2002 version 0.6.4 adds XML::Parser#reset for expat-1.95.3. Mar 23, 2002 version 0.6.2 changes a layout under lib changes the parent class of XML::Parser::Error adds an experimental implementaion of DOM Level 2 adds XML::ParserNS (experimental) Oct 15 2000 version 0.6.1 support expat-1.95.0 and expat-1.2 Aug 5, 2000 version 0.5.19 RDize xmltree.rb by TAKAHASHI Masayoshi May 30, 2000 version 0.5.18 fix for Ruby 1.5 Oct 14, 1999 version 0.5.16 change some samples Aug 18, 1999 version 0.5.15 support start/endDoctypeDecl event of expat-19990728. fix SAX driver bug. Jun 29, 1999 version 0.5.14 support to parse external parameter entities for expat-19990626 Jun 10, 1999 version 0.5.13 support experimental SAX driver support expat-1.1 May 13, 1999 version 0.5.12 fix extconf.rb bug Apr 28, 1999 version 0.5.11 for expat-19990425, add NotStandalone event, getSpecifiedAttributes method and byteCount method Apr 20, 1999 version 0.5.10 change xmldigest.rb for xss4j Mar 29, 1999 version 0.5.9 change the object structure for Ruby 1.3 Mar 23, 1999 version 0.5.8 support the omission of keywords of XPointer support to parse external parsed entities in XML::DOM::Builder Mar 8, 1999 version 0.5.7 support start/endNamespaceDecl event of expat-19990307. Jan 25, 1999 version 0.5.6 class name aliases are defined in C module. support cygwin. Jan 14, 1999 version 0.5.5 support start/endCdataSection event of expat-19981231 Jan 13, 1999 version 0.5.4 modify xmltree and xmltreebuilder Jan 10, 1999 version 0.5.3 encoding map support Dec 1, 1998 version 0.5.1 fix some bugs Nov 24, 1998 version 0.5.0 support the test version of expat Nov 5, 1998 version 0.4.18 fix some bugs, class name alias XMLParserErorr -> XML::Parser::Error and change some internal functions. Oct 28, 1998 version 0.4.17 mIDs are stored into static vars Oct 28, 1998 version 0.4.16 change ID attribute support of XPointer. Node#trim is now xml:space-aware Oct 23, 1998 version 0.4.15 fix some bugs, add class name alias XMLParser -> XML::Parser XML::SimpleTree -> XML::DOM XML::SimpleTreeBuilder -> XML::DOM::Builder Oct 20, 1998 version 0.4.14 add better XPointer support by Masaki Fukushima Sep 17, 1998 version 0.4.5 add methods to SimpleTree Sep 8, 1998 version 0.4.4 change parser object type from T_DATA to T_OBJECT (now can use instance variables) Sep 3, 1998 version 0.4.3 add isFinal flag, and stream parsing facility Sep 2, 1998 version 0.4.2 add external entity event and parser Aug 14, 1998 version 0.3.3 support expat 1.0 Aug 12, 1998 version 0.3.2 Aug 4, 1998 version 0.3.1 Jul 17, 1998 version 0.3 Jul 3, 1998 version 0.2 Jul 1, 1998 version 0.1 xmlparser/encoding.h0000644000076400007640000000616007633545002015265 0ustar yoshidamyoshidam/***************************************************************** ** encoding.h ** ** Copyright 1998 Clark Cooper ** All rights reserved. ** ** This program is free software; you can redistribute it and/or ** modify it under the same terms as Perl itself. */ #ifndef ENCODING_H #define ENCODING_H 1 #define ENCMAP_MAGIC 0xfeebface typedef struct prefixmap { unsigned char min; unsigned char len; /* 0 => 256 */ unsigned short bmap_start; unsigned char ispfx[32]; unsigned char ischar[32]; } PrefixMap; typedef struct encinf { unsigned short prefixes_size; unsigned short bytemap_size; int firstmap[256]; PrefixMap *prefixes; unsigned short *bytemap; } Encinfo; typedef struct encmaphdr { unsigned int magic; char name[40]; unsigned short pfsize; unsigned short bmsize; int map[256]; } Encmap_Header; /*================================================================ ** Structure of Encoding map binary encoding ** ** Note that all shorts and ints are in network order, ** so when packing or unpacking with perl, use 'n' and 'N' respectively. ** In C, use the htonl family of functions. ** ** The basic structure is: ** ** _______________________ ** |Header (including map expat needs for 1st byte) ** |PrefixMap * pfsize ** | This section isn't included for single-byte encodings. ** | For multiple byte encodings, when a byte represents a prefix ** | then it indexes into this vector instead of mapping to a ** | Unicode character. The PrefixMap type is declared above. The ** | ispfx and ischar fields are bitvectors indicating whether ** | the byte being mapped is a prefix or character respectively. ** | If neither is set, then the character is not mapped to Unicode. ** | ** | The min field is the 1st byte mapped for this prefix; the ** | len field is the number of bytes mapped; and bmap_start is ** | the starting index of the map for this prefix in the overall ** | map (next section). ** |unsigned short * bmsize ** | This section also is omitted for single-byte encodings. ** | Each short is either a Unicode scalar or an index into the ** | PrefixMap vector. ** ** The header for these files is declared above as the Encmap_Header type. ** The magic field is a magic number which should match the ENCMAP_MAGIC ** macro above. The next 40 bytes stores IANA registered name for the ** encoding. The pfsize field holds the number of PrefixMaps, which should ** be zero for single byte encodings. The bmsize field holds the number of ** shorts used for the overall map. ** ** The map field contains either the Unicode scalar encoded by the 1st byte ** or -n where n is the number of bytes that such a 1st byte implies (Expat ** requires that the number of bytes to encode a character is indicated by ** the 1st byte) or -1 if the byte doesn't map to any Unicode character. ** ** If the encoding is a multiple byte encoding, then there will be PrefixMap ** and character map sections. The 1st PrefixMap (index 0), covers a range ** of bytes that includes all 1st byte prefixes. ** ** Look at convert_to_unicode in Expat.xs to see how this data structure ** is used. */ #endif /* ndef ENCODING_H */ xmlparser/Encodings/euc-jp.enc0000644000076400007640000011200207633545247017115 0ustar yoshidamyoshidamþëúÎEUC-JP”4A  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŽgÀþÿÿÿÿÿÿÿÿ¡?gþÿÿÿÿÿÿÿ¢L¦Äÿÿÿÿÿÿÿ?¡^òþÿÿÿÿÿÿÿÿÿÿ¡^PþüüðÿüC°K®ÿþÿÿþÿÿ¡Sùþÿÿÿÿÿÿÿÿÿ¡VLþÿÿÿÿÿÿÿÿÿ¡8¢þÿÿþÿÿ¡QÚþÿÿÿþÿÿÿ¡ +þÿÿÿ¡^Kþÿÿÿÿÿÿÿÿÿÿ¡^©þÿÿÿÿÿÿÿÿÿÿ¡^þÿÿÿÿÿÿÿÿÿÿ¡^eþÿÿÿÿÿÿÿÿÿÿ¡^Ãþÿÿÿÿÿÿÿÿÿÿ¡^!þÿÿÿÿÿÿÿÿÿÿ¡^þÿÿÿÿÿÿÿÿÿÿ¡^Ýþÿÿÿÿÿÿÿÿÿÿ¡^;þÿÿÿÿÿÿÿÿÿÿ¡^™þÿÿÿÿÿÿÿÿÿÿ¡^÷þÿÿÿÿÿÿÿÿÿÿ¡^Uþÿÿÿÿÿÿÿÿÿÿ¡^³þÿÿÿÿÿÿÿÿÿÿ¡^þÿÿÿÿÿÿÿÿÿÿ¡^oþÿÿÿÿÿÿÿÿÿÿ¡^Íþÿÿÿÿÿÿÿÿÿÿ¡^ +þÿÿÿÿÿÿÿÿÿÿ¡^ ‰þÿÿÿÿÿÿÿÿÿÿ¡^ çþÿÿÿÿÿÿÿÿÿÿ¡^ Eþÿÿÿÿÿÿÿÿÿÿ¡^ £þÿÿÿÿÿÿÿÿÿÿ¡^ þÿÿÿÿÿÿÿÿÿÿ¡^ _þÿÿÿÿÿÿÿÿÿÿ¡^ ½þÿÿÿÿÿÿÿÿÿÿ¡^ þÿÿÿÿÿÿÿÿÿÿ¡^ yþÿÿÿÿÿÿÿÿÿÿ¡^ ×þÿÿÿÿÿÿÿÿÿÿ¡^ 5þÿÿÿÿÿÿÿÿÿÿ¡^ “þÿÿÿÿÿÿÿÿÿÿ¡^ ñþÿÿÿÿÿÿÿÿÿÿ¡^Oþÿÿÿÿÿÿÿÿÿÿ¡3­þÿÿÿÿÿ¡^àþÿÿÿÿÿÿÿÿÿÿ¡^>þÿÿÿÿÿÿÿÿÿÿ¡^œþÿÿÿÿÿÿÿÿÿÿ¡^úþÿÿÿÿÿÿÿÿÿÿ¡^Xþÿÿÿÿÿÿÿÿÿÿ¡^¶þÿÿÿÿÿÿÿÿÿÿ¡^þÿÿÿÿÿÿÿÿÿÿ¡^rþÿÿÿÿÿÿÿÿÿÿ¡^Ðþÿÿÿÿÿÿÿÿÿÿ¡^.þÿÿÿÿÿÿÿÿÿÿ¡^Œþÿÿÿÿÿÿÿÿÿÿ¡^êþÿÿÿÿÿÿÿÿÿÿ¡^Hþÿÿÿÿÿÿÿÿÿÿ¡^¦þÿÿÿÿÿÿÿÿÿÿ¡^þÿÿÿÿÿÿÿÿÿÿ¡^bþÿÿÿÿÿÿÿÿÿÿ¡^Àþÿÿÿÿÿÿÿÿÿÿ¡^þÿÿÿÿÿÿÿÿÿÿ¡^|þÿÿÿÿÿÿÿÿÿÿ¡^Úþÿÿÿÿÿÿÿÿÿÿ¡^8þÿÿÿÿÿÿÿÿÿÿ¡^–þÿÿÿÿÿÿÿÿÿÿ¡^ôþÿÿÿÿÿÿÿÿÿÿ¡^Rþÿÿÿÿÿÿÿÿÿÿ¡^°þÿÿÿÿÿÿÿÿÿÿ¡^þÿÿÿÿÿÿÿÿÿÿ¡^lþÿÿÿÿÿÿÿÿÿÿ¡^Êþÿÿÿÿÿÿÿÿÿÿ¡^(þÿÿÿÿÿÿÿÿÿÿ¡^†þÿÿÿÿÿÿÿÿÿÿ¡^äþÿÿÿÿÿÿÿÿÿÿ¡^Bþÿÿÿÿÿÿÿÿÿÿ¡^ þÿÿÿÿÿÿÿÿÿÿ¡^þþÿÿÿÿÿÿÿÿÿÿ¡^\þÿÿÿÿÿÿÿÿÿÿ¡^ºþÿÿÿÿÿÿÿÿÿÿ¡~¯C€ÿøáa¾þÂ=}üü¡0ºV»þÿ¡Wêþÿÿýÿÿÿÿÿÿÿ¡WAþÿÿïïÿÿÿÿÿÿ¡^˜þÿÿÿÿÿÿÿÿÿÿ¡^öþÿÿÿÿÿÿÿÿÿÿ¡^Tþÿÿÿÿÿÿÿÿÿÿ¡^²þÿÿÿÿÿÿÿÿÿÿ¡^þÿÿÿÿÿÿÿÿÿÿ¡^nþÿÿÿÿÿÿÿÿÿÿ¡^Ìþÿÿÿÿÿÿÿÿÿÿ¡^ *þÿÿÿÿÿÿÿÿÿÿ¡^ ˆþÿÿÿÿÿÿÿÿÿÿ¡^ æþÿÿÿÿÿÿÿÿÿÿ¡^!Dþÿÿÿÿÿÿÿÿÿÿ¡^!¢þÿÿÿÿÿÿÿÿÿÿ¡^"þÿÿÿÿÿÿÿÿÿÿ¡^"^þÿÿÿÿÿÿÿÿÿÿ¡^"¼þÿÿÿÿÿÿÿÿÿÿ¡^#þÿÿÿÿÿÿÿÿÿÿ¡^#xþÿÿÿÿÿÿÿÿÿÿ¡^#Öþÿÿÿÿÿÿÿÿÿÿ¡^$4þÿÿÿÿÿÿÿÿÿÿ¡^$’þÿÿÿÿÿÿÿÿÿÿ¡^$ðþÿÿÿÿÿÿÿÿÿÿ¡^%Nþÿÿÿÿÿÿÿÿÿÿ¡^%¬þÿÿÿÿÿÿÿÿÿÿ¡^& þÿÿÿÿÿÿÿÿÿÿ¡^&hþÿÿÿÿÿÿÿÿÿÿ¡^&Æþÿÿÿÿÿÿÿÿÿÿ¡^'$þÿÿÿÿÿÿÿÿÿÿ¡^'‚þÿÿÿÿÿÿÿÿÿÿ¡^'àþÿÿÿÿÿÿÿÿÿÿ¡^(>þÿÿÿÿÿÿÿÿÿÿ¡^(œþÿÿÿÿÿÿÿÿÿÿ¡^(úþÿÿÿÿÿÿÿÿÿÿ¡^)Xþÿÿÿÿÿÿÿÿÿÿ¡^)¶þÿÿÿÿÿÿÿÿÿÿ¡^*þÿÿÿÿÿÿÿÿÿÿ¡^*rþÿÿÿÿÿÿÿÿÿÿ¡^*Ðþÿÿÿÿÿÿÿÿÿÿ¡^+.þÿÿÿÿÿÿÿÿÿÿ¡^+Œþÿÿÿÿÿÿÿÿÿÿ¡^+êþÿÿÿÿÿÿÿÿÿÿ¡^,Hþÿÿÿÿÿÿÿÿÿÿ¡^,¦þÿÿÿÿÿÿÿÿÿÿ¡^-þÿÿÿÿÿÿÿÿÿÿ¡^-bþÿÿÿÿÿÿÿÿÿÿ¡^-Àþÿÿÿÿÿÿÿÿÿÿ¡^.þÿÿÿÿÿÿÿÿÿÿ¡^.|þÿÿÿÿÿÿÿÿÿÿ¡^.Úþÿÿÿÿÿÿÿÿÿÿ¡^/8þÿÿÿÿÿÿÿÿÿÿ¡^/–þÿÿÿÿÿÿÿÿÿÿ¡^/ôþÿÿÿÿÿÿÿÿÿÿ¡^0Rþÿÿÿÿÿÿÿÿÿÿ¡^0°þÿÿÿÿÿÿÿÿÿÿ¡^1þÿÿÿÿÿÿÿÿÿÿ¡^1lþÿÿÿÿÿÿÿÿÿÿ¡^1Êþÿÿÿÿÿÿÿÿÿÿ¡^2(þÿÿÿÿÿÿÿÿÿÿ¡^2†þÿÿÿÿÿÿÿÿÿÿ¡^2äþÿÿÿÿÿÿÿÿÿÿ¡^3Bþÿÿÿÿÿÿÿÿÿÿ¡^3 þÿÿÿÿÿÿÿÿÿÿ¡C3þþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOÿaÿbÿcÿdÿeÿfÿgÿhÿiÿjÿkÿlÿmÿnÿoÿpÿqÿrÿsÿtÿuÿvÿwÿxÿyÿzÿ{ÿ|ÿ}ÿ~ÿÿ€ÿÿ‚ÿƒÿ„ÿ…ÿ†ÿ‡ÿˆÿ‰ÿŠÿ‹ÿŒÿÿŽÿÿÿ‘ÿ’ÿ“ÿ”ÿ•ÿ–ÿ—ÿ˜ÿ™ÿšÿ›ÿœÿÿžÿŸPÿÿÿÿÿÿQRÿÿSTUÿÿÿÿÿÿÿÿVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“000ÿ ÿ0ûÿÿÿÿ0›0œ´ÿ@¨ÿ>ÿãÿ?0ý0þ00ž0NÝ0000ü  ÿ\0 ÿ\ & %    ÿÿ 00ÿ;ÿ=ÿ[ÿ]00 0 0 0 0 0000ÿ "±×÷ÿ"`ÿÿ"f"g""4&B&@° 2 3!ÿåÿ¢£ÿÿÿÿ ÿ §&&%Ë%Ï%Î%Ç%Æ%¡% %³%²%½%¼ ;0!’!!‘!“0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"" "†"‡"‚"ƒ"*")ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"'"(¬!Ò!Ô""ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ" "¥#"""a"R"j"k""=""5"+",ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!+ 0&o&m&j !¶ÿÿÿÿÿÿÿÿ%ïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿ"ÿ#ÿ$ÿ%ÿ&ÿ'ÿ(ÿ)ÿ*ÿ+ÿ,ÿ-ÿ.ÿ/ÿ0ÿ1ÿ2ÿ3ÿ4ÿ5ÿ6ÿ7ÿ8ÿ9ÿ:ÿÿÿÿÿÿÿÿÿÿÿÿÿAÿBÿCÿDÿEÿFÿGÿHÿIÿJÿKÿLÿMÿNÿOÿPÿQÿRÿSÿTÿUÿVÿWÿXÿYÿZ0A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0W0X0Y0Z0[0\0]0^0_0`0a0b0c0d0e0f0g0h0i0j0k0l0m0n0o0p0q0r0s0t0u0v0w0x0y0z0{0|0}0~00€00‚0ƒ0„0…0†0‡0ˆ0‰0Š0‹0Œ00Ž000‘0’0“0¡0¢0£0¤0¥0¦0§0¨0©0ª0«0¬0­0®0¯0°0±0²0³0´0µ0¶0·0¸0¹0º0»0¼0½0¾0¿0À0Á0Â0Ã0Ä0Å0Æ0Ç0È0É0Ê0Ë0Ì0Í0Î0Ï0Ð0Ñ0Ò0Ó0Ô0Õ0Ö0×0Ø0Ù0Ú0Û0Ü0Ý0Þ0ß0à0á0â0ã0ä0å0æ0ç0è0é0ê0ë0ì0í0î0ï0ð0ñ0ò0ó0ô0õ0ö‘’“”•–—˜™š›œžŸ ¡£¤¥¦§¨©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ±²³´µ¶·¸¹º»¼½¾¿ÀÁÃÄÅÆÇÈÉ !"#$%&'()*+,-./ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ012345Q6789:;<=>?@ABCDEFGHIJKLMNO%%% %%%%%,%$%4%<%%%%%%%#%3%+%;%K% %/%(%7%?%%0%%%8%BNœUZ–?TÀac(Yö"„uƒzP`ªcán%eí„f‚¦›õh“W'e¡bq[›YІ{˜ô}b}¾›Žb|Ÿˆ·[‰^µc f—hH•Ç—gONåO OMOPIVòY7YÔZ\ `ßaapfipºuOupyû}­}ï€Ã„ˆc‹UzS;N•N¥W߀²ÁxïNXñn¢8z2ƒ(‚‹œ/QASpT½TáVàYû_˜òmë€ä…-–b–p– —ûT Só[‡pϽ–èSo\zºNx“ün&VUk…œ;YåS©mftÜ•VBN‘K–òƒO™ SáU¶[0_qf fóhl8lóm)t[vÈzN˜4‚ñˆ[Š`’ím²u«vÊ™Å`¦‹Š•²iŽS­Q†WX0YD[´^ö`(c©côl¿opŽqqYqÕs?~‚v‚Ñ…—`’[Xie¼lZu%QùY.Ye_€_Üb¼eúj*k'k´s‹Á‰V,žÄ\¡l–ƒ{Q\Ka¶ÆhvraNYOúSx`in)zO—óN SNîOUO=O¡OsR SïV YZÁ[¶[áyÑf‡gœg¶kLl³pksÂyy¾z<{‡‚±‚ÛƒƒwƒïƒÓ‡fвV)Œ¨æN—†ŠOÄ\èbrYu;傽†þŒÀ–Å™™ÕNËO‰ãVÞXJXÊ^û_ë`*`”`baÐbbÐe9›Affh°mwppuLv†}u‚¥‡ù•‹–ŽŒQñR¾YT³[³]ahi‚m¯x„ˈWŠr“§š¸ml™¨†ÙW£gÿ†Î’RƒV‡T^Óbád¹hkSlWo"o—oEt°uvãw zÿ{¡|!}é6ð€‚fƒž‰³ŠÌŒ«„”Q•“•‘•¢–e—Ó™(‚N8T+\¸]Ìs©vLw<\©ë –Á˜˜T˜XOOSqUœVhWúYG[ [Ä\^ ^~_Ìcîg:e×eâghËhÄj_^0kÅll}uyH[cz}_½‰ŠŒ´wŽÌ˜âš›Z/_Œ_¡`Ÿh§jŽtZxŠžŠ¤‹w‘N^›ÉN¤O|O¯PPQIQlRŸR¹RþSšSãTTU‰WQW¢Y}[T[][]å]ç]÷^x^ƒ^š^·_`RaLb—bØc§e;ffCfôgmh!h—iËl_m*min/nu2v‡xlz?|à}}}^}±€€€¯€±T‚*ƒRˆLˆa‹Œ¢ŒüÊ‘u’qx?’ü•¤–M˜™™šØ;R[R«S÷TXÕb÷oàŒj_ž¹QKR;TJVýz@‘w`žÒsDo pu_ý`Úš¨rÛ¼kd˜NÊVðWdX¾ZZ`haÇffh9h±m÷uÕ}:‚n›BN›OPSÉU]o]æ]îgûl™tsxŠP“–ˆßWP^§c+PµP¬QgTÉX^Y»[°_ibMc¡h=ksnp}‘Çr€xx&ymeŽ}0ƒÜˆÁ –›RdW(gPjŒ¡Q´WB–*X:iŠ€´T²]Wüx•úO\RJT‹d>f(ggõz„{V}"“/h\›­{9SQŠR7[ßböd®dæg-kº…©–Ñv›ÖcL“›«v¿fRN P˜SÂ\q`èd’ech_qæsÊu#{—~‚†•‹ƒŒÛ‘x™e¬f«k‹NÕNÔO:OR:SøSòUãVÛXëYËYÉYÿ[P\M^^+_×`ce/[\e¯e½eègkbk{lsEyIyÁ|ø}}+€¢ó‰–Š^ŠiŠfŠŒŠîŒÇŒÜ–̘ükoN‹Ot½uÔxÁy:€ €3ê„”žlPž_‹X+zúŽø[–ëNSñW÷Y1ZÉ[¤`‰nou¾Œê[Ÿ…{àPrgô‚\a…J~‚Q™\chfeœqny>}€‹ŽÊn†ÇªPRú\:gSp|r5‘L‘È“+‚å[Â_1`ùN;SÖ[ˆbKg1kŠrésàz.k£‘R™–QS×Tj[ÿcˆj9}¬—VÚSÎTh[—\1]ÞOîabþm2yÀyË}B~MÒí‚„ˆF‰r‹Žt/1‘K‘l–Æ‘œNÀOOQESA_“bgÔlAn sc~&‘Í’ƒSÔY[¿mÑy]~.|›X~qŸQúˆSðOÊ\ûf%w¬zã‚™ÿQÆ_ªeìiok‰món–odvþ}]áu‘‡˜QæRb@f‘fÙn^¶}Òrfø…¯…÷ŠøR©SÙYs^_`U’ä–dP·QRÝS SGSìTèUFU1VYhY¾Z<[µ\\\\^„^Š^à_pbb„bÛcŒcwff f-fvg~h¢jj5l¼mˆn nXq Œ¬dáŽ_x©RbÙc¥dBb˜Š-zƒ{ÀЬ–ê}v‚ ‡INÙQHSCS`[£\\]Ýb&bGd°hh4lÉmEmgÓo\qNq}eËz{­}Ú~J¨z‚‚9…¦ŠnŒÎõxw’­’‘•ƒ›®RMU„o8q6Qhy…~U³|ÎVLXQ\¨cªfþfýiZrÙuuŽyyVyß|—} }D†Š4–;aŸ PçRuSÌSâP UªXîYOr=[‹\dS`ã`óc\cƒc?c»dÍeéfù]ãiÍiýoqåN‰uévøz“|ß}Ï}œ€aƒIƒX„l„¼…ûˆÅpm“——šPÏX—aŽÓ…5 OÃPtRGSs`ocIg_n,³O×\^ŒÊeÏ}šSRˆ–QvcÃ[X[k\ d gQ\NÖYY*lpŠQU>XY¥`ðbSgÁ‚5iU–@™Äš(OSX[þ€\±^/_…` aKb4fÿlðnހ΂Ԉ‹Œ¸.–ŠžÛ›ÛNãSðY'{,‘˜LùnÝp'SSUD[…bXbžbÓl¢oït"Š”8oÁŠþƒ8Qç†øSêSéOFT°Yj1]ýzê¿hÚŒ7røœHj=аN9SXVWfbÅc¢eækNmán[p­wízï{ª}»€=€Æ†ËŠ•“[VãXÇ_>e­f–j€kµu7ŠÇP$wåW0_`efzl`uôznô‡E™³{Éu\zù{Q„Äyéz’ƒ6Záw@N-Nò[™_àb½ft6x4ZFu‚­™¬Oó^ÃbÝc’eWgovÃrL€Ì€º)‘MP WùZ’h…isqdrýŒ·XòŒà–j‡yäwç„)O/ReSZbÍgÏlÊv}{”|•‚6…„ëfÝo r~ƒ«™Áž¦Qý{±xr{¸€‡{Hjè^a€ŒuQu`Qk’bnŒvz‘—šêOpbœ{O•¥œéVzXY†ä–¼O4R$SJSÍSÛ^d,e‘gl>lNrHr¯síuT~A‚,…錩{Ä‘Æqi˜˜ïc=fiujväxÐ…C†îS*SQT&Yƒ^‡_|`²bIbyb«ekÔlÌu²v®x‘yØ}Ëw€¥ˆ«Š¹Œ»—^˜Ûj |8P™\>_®g‡kØt5w ŽŸ;gÊzS9u‹ší_fƒñ€˜_<_Åub{Fe¹g lÕlápùx2~+€Þ‚³„ „쇉Š*ŒJ¦’Ò˜ýœólNON¡PRVWJY¨^=_Ø_Ùb?f´ggÐhÒQ’}!€ª¨‹ŒŒŒ¿’~–2T ˜,SPÕS\X¨d²g4rgwfzF‘æRÃl¡k†X^LYTg,ûQávÆdixè›Tž»WËY¹f'gškÎTéiÙ^Uœg•›ªgþœRh]N¦OãSÈb¹g+l«ÄO­~mž¿Nabn€o+…Tsg*›E]ó{•\¬[ƇnJ„ÑzY™|lw RÙY"q!r_wÛ—'ai ZZQ¥T T}fvß÷’˜œôYêr]nÅQMhÉ}¿}ì—bžºdxj!ƒY„[_kÛsvò}²€„™Q2g(žÙvîgbRÿ™\$b;|~Œ°UO`¶} •€SN_Q¶Yr:€6‘Î_%wâS„_y}…¬Š3Ž—Vgó…®”Sa al¹vRŠí8U/OQQ*RÇSË[¥^}` a‚cÖg gÚngmŒs6s7u1yPˆÕŠ˜J‘õ–ćYNˆOYNЉ?˜P­^|Y–[¹^¸cÚcúdÁfÜiJiØm n¶q”u(z¯Š€„I„ɉ‹!Ž e–}™ a~b‘k2lƒmtÌümÀ…‡ºˆøgeƒ±˜<–÷m}a„=‘jNqSu]Pkoë…͆-‰§R)T\egNh¨ttƒuâˆÏˆá‘Ì–â–x_‹s‡zË„Nc ueR‰mAnœt uYxk|’–†zÜŸO¶aneņ\N†N®PÚN!QÌ[îe™hm¼svBw­z|ç‚oŠÒ|‘Ï–u˜R›}ÑP+S˜g—mËqÐt3è*–£œWžŸt`XAm™}/˜^NäO6O‹Q·R±]º`s²y<‚Ó’4–·–ö— ž—Ÿbf¦ktRR£pȈÂ^É`Kao#qI|>}ô€o„î#“,TB›ojÓp‰ŒÂï—2R´ZA^Ê_gi|i”mjorbrü{퀀~‡KÎQmž“y„€‹“2ŠÖP-TŒŠqkjŒÄ`Ñg òN™N˜œŠk…Á…hin~x—U_ NNN*N1N6NzÒYUYPYNYZYXYbY`YgYlYiYxYYO^O«Y£Y²YÆYèYÜYYÙYÚZ%ZZZZ ZZ@ZlZIZ5Z6ZbZjZšZ¼Z¾ZËZÂZ½ZãZ×ZæZéZÖZúZû[ [ [[2ZÐ[*[6[>[C[E[@[Q[U[Z[[[e[i[p[s[u[xeˆ[z[€[ƒ[¦[¸[Ã[Ç[É[Ô[Ð[ä[æ[â[Þ[å[ë[ð[ö[ó\\\\ \\ \"\(\8\9\A\F\N\S\P\O[q\l\nNb\v\y\Œ\‘\”Y›\«\»\¶\¼\·\Å\¾\Ç\Ù\é\ý\ú\í]Œ\ê] ]]]\]]]]]"]]]]L]R]N]K]l]s]v]‡]„]‚]¢]]¬]®]½]]·]¼]É]Í]Ó]Ò]Ö]Û]ë]ò]õ^ ^^^^^6^7^D^C^@^N^W^T^_^b^d^G^u^v^zž¼^^ ^Á^Â^È^Ð^Ï^Ö^ã^Ý^Ú^Û^â^á^è^é^ì^ñ^ó^ð^ô^ø^þ__ _]_\_ ___)_-_8_A_H_L_N_/_Q_V_W_Y_a_m_s_w_ƒ_‚__Š_ˆ_‘_‡_ž_™_˜_ _¨_­_¼_Ö_û_ä_ø_ñ_Ý`³_ÿ`!`````)``1```+`&``:`Z`A`j`w`_`J`F`M`c`C`d`B`l`k`Y```ç`ƒ`š`„`›`–`—`’`§`‹`á`¸`à`Ó`´_ð`½`Æ`µ`ØaMaa`ö`÷a`ô`úaa!`û`ña aaGa>a(a'aJa?acMdcOc–cŽc€c«cvc£cc‰cŸcµckcic¾cécÀcÆcãcÉcÒcöcÄdd4ddd&d6edd(ddgdodvdNe*d•d“d¥d©dˆd¼dÚdÒdÅdÇd»dØdÂdñdç‚ dàdáb¬dãdïe,dödôdòdúedýeeee$e#e+e4e5e7e6e8uKeHeVeUeMeXe^e]erexe‚eƒ‹Še›eŸe«e·eÃeÆeÁeÄeÌeÒeÛeÙeàeáeñgrf feûgsf5f6f4ffOfDfIfAf^f]fdfgfhf_fbfpfƒfˆfŽf‰f„f˜ffÁf¹fÉf¾f¼fÄf¸fÖfÚfàf?fæféfðfõf÷gggg&g'—8g.g?g6gAg8g7gFg^g`gYgcgdg‰gpg©g|gjgŒg‹g¦g¡g…g·gïg´gìg³gég¸gägÞgÝgâgîg¹gÎgÆgçjœhhFh)h@hMh2hNh³h+hYhchwhhŸhh­h”hh›hƒj®h¹hthµh hºihh~ihÊihØi"i&hái hÍhÔhçhÕi6iih×hãi%hùhàhïi(i*ii#i!hÆiyiwi\ixikiTi~ini9iti=iYi0iai^i]iiji²i®iÐi¿iÁiÓi¾iÎ[èiÊiÝi»iÃi§j.i‘i iœi•i´iÞièjjiÿk iùiòiçji±jiíjiëj jjÁj#jjDj jrj6jxjGjbjYjfjHj8j"jjj j„j¢j£j—†j»jÃjÂj¸j³j¬jÞjÑjßjªjÚjêjûk†júkk›1kk8k7vÜk9˜îkGkCkIkPkYkTk[k_kakxkykk€k„kƒkk˜k•kžk¤kªk«k¯k²k±k³k·k¼kÆkËkÓkßkìkëkókïž¾lllll$l#l^lUlbljl‚llšll›l~lhlsl’llÄlñlÓl½l×lÅlÝl®l±l¾lºlÛlïlÙlêmˆMm6m+m=m8mm5m3mm mcm“mdmZmymYmŽm•oäm…mùnn mµmÇmæm¸mÆmìmÞmÌmèmÒmÅmúmÙmämÕmêmîn-nnn.nnrn_n>n#nkn+nvnMnnCn:nNn$nÿnn8n‚nªn˜nÉn·nÓn½n¯nÄn²nÔnÕnn¥nÂnŸoAopLnìnønþo?nòo1nïo2nÌo>on÷o†ozoxoo€ooo[oóomo‚o|oXoŽo‘oÂofo³o£o¡o¤o¹oÆoªoßoÕoìoÔoØoñoîoÛp p oúpppoþppotpppp0p>p2pQpcp™p’p¯pñp¬p¸p³p®pßpËpÝpÙq pýqqqeqUqˆqfqbqLqVqlqqûq„q•q¨q¬q×q¹q¾qÒqÉqÔqÎqàqìqçqõqüqùqÿr rrr(r-r,r0r2r;rsNsOžØsWsjshspsxsus{szsÈs³sÎs»sÀsåsîsÞt¢ttot%søt2t:tUt?t_tYtAt\titptctjtvt~t‹tžt§tÊtÏtÔsñtàtãtçtétîtòtðtñtøt÷uuuu uu uuuu&u,uz7zCzWzIzazbziŸzpzyz}zˆz—z•z˜z–z©zÈz°z¶zÅzÄz¿ƒzÇzÊzÍzÏzÕzÓzÙzÚzÝzázâzæzízð{{{ {{3{{{{5{({6{P{z{{M{ {L{E{u{e{t{g{p{q{l{n{{˜{Ÿ{{œ{š{‹{’{{]{™{Ë{Á{Ì{Ï{´{Æ{Ý{é||{æ{å|`|||{ó{÷|| {ö|#|'|*||7|+|=|L|C|T|O|@|P|X|_|d|V|e|l|u|ƒ||¤|­|¢|«|¡|¨|³|²|±|®|¹|½|À|Å|Â|Ø|Ò|Ü|â›;|ï|ò|ô|ö|ú}}}}} }E}K}.}2}?}5}F}s}V}N}r}h}n}O}c}“}‰}[}}}}›}º}®}£}µ}Ç}½}«~=}¢}¯}Ü}¸}Ÿ}°}Ø}Ý}ä}Þ}û}ò}á~~ ~#~!~~1~~ ~ ~"~F~f~;~5~9~C~7~2~:~g~]~V~^~Y~Z~y~j~i~|~{~ƒ}Õ~}®~~ˆ~‰~Œ~’~~“~”~–~Ž~›~œ8:ELMNPQUTX_`higx‚†ƒˆ‡Œ”žš£¯²¹®¶¸‹qÅÆÊÕÔáæéóù˜Ü€€€ €€€€€!€(€?€;€J€F€R€X€Z€_€b€h€s€r€p€v€y€}€€„€†€…€›€“€š€­Q€¬€Û€å€Ù€Ý€Ä€Ú€Ö €ï€ñ)#/K–‹F>SQ€üqneftƒˆŠ€‚ •¤£_“©°µ¾¸½ÀºÉÍÑÙØÈÚßàçúûþ‚‚‚‚‚ ‚ ‚‚‚)‚+‚8‚3‚@‚Y‚X‚]‚Z‚_‚d‚b‚h‚j‚k‚.‚q‚w‚x‚~‚‚’‚«‚Ÿ‚»‚¬‚á‚ã‚߂҂ô‚ó‚úƒ“ƒ‚û‚ù‚Þƒ‚܃ ‚Ùƒ5ƒ4ƒƒ2ƒ1ƒ@ƒ9ƒPƒEƒ/ƒ+ƒƒƒ…ƒšƒªƒŸƒ¢ƒ–ƒ#ƒŽƒ‡ƒŠƒ|ƒµƒsƒuƒ ƒ‰ƒ¨ƒô„ƒëƒÎƒý„ƒØ„ ƒÁƒ÷„ƒàƒò„ „"„ ƒ½„8…ƒû„m„*„<…Z„„„w„k„­„n„‚„i„F„,„o„y„5„Ê„b„¹„¿„Ÿ„Ù„Í„»„ڄЄÁ„Ƅք¡…!„ÿ„ô………,………„ü…@…c…X…H…A†…K…U…€…¤…ˆ…‘…Š…¨…m…”…›…ê…‡…œ…w…~……É…º…Ï…¹…Ð…Õ…Ý…å…Ü…ù† †† …þ…ú††"††0†?†MNU†T†_†g†q†“†£†©†ª†‹†Œ†¶†¯†Ä†Æ†°†Éˆ#†«†Ô†Þ†é†ì†ß†Û†ï‡‡‡‡‡†û‡‡ ‡ †ù‡ ‡4‡?‡7‡;‡%‡)‡‡`‡_‡x‡L‡N‡t‡W‡h‡n‡Y‡S‡c‡jˆ‡¢‡Ÿ‡‚‡¯‡Ë‡½‡À‡Ð–Ö‡«‡Ä‡³‡Ç‡Æ‡»‡ï‡ò‡àˆˆ ‡þ‡ö‡÷ˆ‡Òˆˆˆˆ"ˆ!ˆ1ˆ6ˆ9ˆ'ˆ;ˆDˆBˆRˆYˆ^ˆbˆkˆˆ~ˆžˆuˆ}ˆµˆrˆ‚ˆ—ˆ’ˆ®ˆ™ˆ¢ˆˆ¤ˆ°ˆ¿ˆ±ˆÃˆÄˆÔˆØˆÙˆÝˆù‰ˆüˆôˆèˆò‰‰ ‰ ‰‰C‰‰%‰*‰+‰A‰D‰;‰6‰8‰L‰‰`‰^‰f‰d‰m‰j‰o‰t‰w‰~‰ƒ‰ˆ‰Š‰“‰˜‰¡‰©‰¦‰¬‰¯‰²‰º‰½‰¿‰À‰Ú‰Ü‰Ý‰ç‰ô‰øŠŠŠŠ ŠŠŠ%Š6ŠAŠ[ŠRŠFŠHŠ|ŠmŠlŠbŠ…Š‚Š„Š¨Š¡Š‘Š¥Š¦ŠšŠ£ŠÄŠÍŠÂŠÚŠëŠóŠçŠäŠñ‹ŠàŠâŠ÷ŠÞŠÛ‹ ‹‹Šá‹‹‹‹ ‹3—«‹&‹+‹>‹(‹A‹L‹O‹N‹I‹V‹[‹Z‹k‹_‹l‹o‹t‹}‹€‹Œ‹Ž‹’‹“‹–‹™‹šŒ:ŒAŒ?ŒHŒLŒNŒPŒUŒbŒlŒxŒzŒ‚Œ‰Œ…ŒŠŒŒŽŒ”Œ|Œ˜bŒ­ŒªŒ½Œ²Œ³Œ®Œ¶ŒÈŒÁŒäŒãŒÚŒýŒúŒû  ŸNŒÍgmqs™Â¾ºÏÚÖÌÛËêëßãüŽŽ ÿŽŽŽŽŽBŽ5Ž0Ž4ŽJŽGŽIŽLŽPŽHŽYŽdŽ`Ž*ŽcŽUŽvŽrŽ|ŽŽ‡Ž…Ž„Ž‹ŽŠŽ“Ž‘Ž”Ž™ŽªŽ¡Ž¬Ž°ŽÆŽ±Ž¾ŽÅŽÈŽËŽÛŽãŽüŽûŽëŽþ  &3;9EB>LIFNW\bcdœŸ£­¯·Úåâêï‡ôùú!  '659øOPQRI>VX^hov–¨r‚}€Š‰¨¯±µâäbHÛ‘‘‘‘2‘0‘J‘V‘X‘c‘e‘i‘s‘r‘‹‘‰‘‚‘¢‘«‘¯‘ª‘µ‘´‘º‘À‘Á‘ɑˑБ֑ߑá‘Û‘ü‘õ‘ö’‘ÿ’’,’’’^’W’E’I’d’H’•’?’K’P’œ’–’“’›’Z’Ï’¹’·’é“’ú“D“.““"““#“:“5“;“\“`“|“n“V“°“¬“­“”“¹“֓דè“哨“ÓݓГȓä”””””””6”+”5”!”:”A”R”D”[”`”b”^”j’)”p”u”w”}”Z”|”~””•‚•‡•Š•”•–•˜•™• •¨•§•­•¼•»•¹•¾•Êoö•Õ͕̕Օԕ֕ܕá•å•â–!–(–.–/–B–L–O–K–w–\–^–]–_–f–r–l––˜–•–—–ª–§–±–²–°–´–¶–¸–¹–Ζ˖ɖ͉M–Ü— –Õ–ù——————————$—*—0—9—=—>—D—F—H—B—I—\—`—d—f—hRÒ—k—q—y—…—|——z—†—‹———œ—¨—¦—£—³—´—×Ɨȗ˗ܗíŸO—òzß—ö—õ˜˜ ˜8˜$˜!˜7˜=˜F˜O˜K˜k˜o˜p˜q˜t˜s˜ª˜¯˜±˜¶˜Ä˜Ã˜Æ˜é˜ë™™ ™™™™!™™™$™ ™,™.™=™>™B™I™E™P™K™Q™R™L™U™—™˜™¥™­™®™¼™ß™Û™Ý™Ø™Ñ™í™î™ñ™ò™û™øššš™âšš+š7šEšBš@šCš>šUšMš[šWš_šbšešdšiškšjš­š°š¼šÀšÏšÑšÓšÔšÞšßšâšãšæšïšëšîšôšñš÷šû›››››"›#›%›'›(›)›*›.›/›2›D›C›O›M›N›Q›X›t›“›ƒ›‘›–›—›Ÿ› ›¨›´›À›Ê›¹›Æ›Ï›Ñ›Ò›ã›â›ä›Ô›áœ:›ò›ñ›ðœœœ œœ œœœœ œœ.œœ%œ$œ!œ0œGœ2œFœ>œZœ`œgœvœxœçœìœð œë*&¯#DA?>FH]^dQPYr‰‡«oz𤩲ÄÁ»¸ºÆÏÂÙÓøæíïýžžžžužyž}žžˆž‹žŒž’ž•ž‘žž¥ž©ž¸žªž­—ažÌžÎžÏžÐžÔžÜžÞžÝžàžåžèžïžôžöž÷žùžûžüžýŸŸv·ŸŸ!Ÿ,Ÿ>ŸJŸRŸTŸcŸ_Ÿ`ŸaŸfŸgŸlŸjŸwŸrŸvŸ•ŸœŸ X/iÇYtdQÜq™ØǸÙݯÛÚ~„…ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡¦¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿºª©®!"¤!†ˆ‰ŠªÿÿŒÿÿŽ«ÿÿÿÿÿÿÿÿÿÿ¬­®¯ÊÌÂÍ˰Π   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿRSTUVWXYZ[\^_Æÿÿ&ÿÿ2ÿÿA?ÿÿJØRÿÿfÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿæð'138B@IKøSßgþÁÀÄÂÍÅÃ Ç ÉÈËÊÿÿ" $ÍÌÏÎÏ0*.(469=;CGEÑÓÒÖÔÑPLÕTXVZ\`^dbÚÙÜÛlÓpjrnh×ÛÙÕtÝxvy}{áàäâÎåã  ç éèëêõÿÿ!%íìïîÐÿÿ+/)57:><DHFñóòöôÒQMõUYW[]a_ecúùüûmÔqksoiØÜÚÖuýÿwz~|NNNN NNN#N$N(N+N.N/N0N5N@NANDNGNQNZN\NcNhNiNtNuNyNNN–N—NN¯N¹NÃNÐNÚNÛNàNáNâNèNïNñNóNõNýNþNÿOOOOO O OOOOOO.O1O`O3O5O7O9O;O>O@OBOHOIOKOLOROTOVOXO_OcOjOlOnOqOwOxOyOzO}O~OO‚O„O…O‰OŠOŒOŽOO’O“O”O—O™OšOžOŸO²O·O¹O»O¼O½O¾OÀOÁOÅOÆOÈOÉOËOÌOÍOÏOÒOÜOàOâOðOòOüOýOÿPPPPP P PPPPPPPPPP"P'P.P0P2P3P5P@PAPBPEPFPJPLPNPQPRPSPWPYP_P`PbPcPfPgPjPmPpPqP;PPƒP„P†PŠPŽPPP’P“P”P–P›PœPžPŸP P¡P¢PªP¯P°P¹PºP½PÀPÃPÄPÇPÌPÎPÐPÓPÔPØPÜPÝPßPâPäPæPèPéPïPñPöPúPþQQQQQ Q Q QPòQQQQQQQQ#Q'Q(Q,Q-Q/Q1Q3Q4Q5Q8Q9QBQJQOQSQUQWQXQ_QdQfQ~QƒQ„Q‹QŽQ˜QQ¡Q£Q­Q¸QºQ¼Q¾Q¿QÂQÈQÏQÑQÒQÓQÕQØQÞQâQåQîQòQóQôQ÷RRRRRRRRR"R(R1R2R5RSBSLSKSYS[SaScSeSlSmSrSyS~SƒS‡SˆSŽS“S”S™SS¡S¤SªS«S¯S²S´SµS·S¸SºS½SÀSÅSÏSÒSÓSÕSÚSÝSÞSàSæSçSõTTTT!T'T(T*T/T1T4T5TCTDTGTMTOT^TbTdTfTgTiTkTmTnTtTTTƒT…TˆT‰TT‘T•T–TœTŸT¡T¦T§T©TªT­T®T±T·T¹TºT»T¿TÆTÊTÍTÎTàTêTìTïTöTüTþTÿUUUUU U U UUU*U+U2U5U6U;UW?WEWFWLWMWRWbWeWgWhWkWmWnWoWpWqWsWtWuWwWyWzW{W|W~WWƒWŒW”W—W™WšWœWWžWŸW¡W•W§W¨W©W¬W¸W½WÇWÈWÌWÏWÕWÝWÞWäWæWçWéWíWðWõWöWøWýWþWÿXXXX WáX X XXXX X&X'X-X2X9X?XIXLXMXOXPXUX_XaXdXgXhXxX|XX€XX‡XˆX‰XŠXŒXXXX”X–XX X¡X¢X¦X©X±X²XÄX¼XÂXÈXÍXÎXÐXÒXÔXÖXÚXÝXáXâXéXóYYY Y YYY†AYY!Y#Y$Y(Y/Y0Y3Y5Y6Y?YCYFYRYSYYY[Y]Y^Y_YaYcYkYmYoYrYuYvYyY{Y|Y‹YŒYŽY’Y•Y—YŸY¤Y§Y­Y®Y¯Y°Y³Y·YºY¼YÁYÃYÄYÈYÊYÍYÒYÝYÞYßYãYäYçYîYïYñYòYôY÷ZZZ Z ZZZZZ#Z$Z'Z(Z*Z-Z0ZDZEZGZHZLZPZUZ^ZcZeZgZmZwZzZ{Z~Z‹ZZ“Z–Z™ZœZžZŸZ Z¢Z§Z¬Z±Z²Z³ZµZ¸ZºZ»Z¿ZÄZÆZÈZÏZÚZÜZàZåZêZîZõZöZý[[[[[4[[[[![%[-[8[A[K[L[R[V[^[h[n[o[|[}[~[[[„[†[Š[Ž[[‘[“[”[–[¨[©[¬[­[¯[±[²[·[º[¼[À[Á[Í[Ï[Ö[×[Ø[Ù[Ú[à[ï[ñ[ô[ý\ \\\\#\&\)\+\,\.\0\2\5\6\Y\Z\\\b\c\g\h\i\m\p\t\u\z\{\|\}\‡\ˆ\Š\\’\\Ÿ\ \¢\£\¦\ª\²\´\µ\º\É\Ë\Ò\Ý\×\î\ñ\ò\ô]]] ]]+]#]$]&]']1]4]9]=]?]B]C]F]H]U]Q]Y]J]_]`]a]b]d]j]m]p]y]z]~]]]ƒ]ˆ]Š]’]“]”]•]™]›]Ÿ] ]§]«]°]´]¸]¹]Ã]Ç]Ë]Ð]Î]Ø]Ù]à]ä]é]ø]ù^^^ ^^^^^^ ^.^(^2^5^>^K^P^I^Q^V^X^[^\^^^h^j^k^l^m^n^p^€^‹^Ž^¢^¤^¥^¨^ª^¬^±^³^½^¾^¿^Æ^Ì^Ë^Î^Ñ^Ò^Ô^Õ^Ü^Þ^å^ë_________!_"_#_$_(_+_,_._0_4_6_;_=_?_@_D_E_G_M_P_T_X_[_`_c_d_g_o_r_t_u_x_z_}_~_‰___–_œ__¢_§_«_¤_¬_¯_°_±_¸_Ä_Ç_È_É_Ë_Ð_Ñ_Ò_Ó_Ô_Þ_á_â_è_é_ê_ì_í_î_ï_ò_ó_ö_ú_ü`` ` ```````$`-`3`5`@`G`H`I`L`Q`T`V`W`]`a`g`q`~``‚`†`ˆ`Š`Ž`‘`“`•`˜``ž`¢`¤`¥`¨`°`±`·`»`¾`Â`Ä`È`É`Ê`Ë`Î`Ï`Ô`Õ`Ù`Û`Ý`Þ`â`å`ò`õ`ø`ü`ýaaa a aaaaaaaaaaa"a*a+a0a1a5a6a7a9aAaEaFaIa^a`alaraxa{a|aa€aaƒa„a‹aa’a“a—a˜aœaaŸa a¥a¨aªa­a¸a¹a¼aÀaÁaÂaÎaÏaÕaÜaÝaÞaßaáaâaçaéaåaìaíaïbbbbbbbb b"b#b'b)b+b9b=bBbCbDbFbLbPbQbRbTbVbZb\bdbmbobsbzb}bbŽbbb¦b¨b³b¶b·bºb¾b¿bÄbÎbÕbÖbÚbêbòbôbübýccc c c ccccc)c*c-c5c6c9cgEgGgHgLgTgUg]gfglgngtgvg{gg„gŽgg‘g“g–g˜g™g›g°g±g²gµg»g¼g½gùgÀgÂgÃgÅgÈgÉgÒg×gÙgÜgágægðgògög÷hRhhhhh(h'h,h-h/h0h1h3h;h?hDhEhJhLhUhWhXh[hkhnhohphqhrhuhyhzh{h|h‚h„h†hˆh–h˜hšhœh¡h£h¥h©hªh®h²h»hÅhÈhÌhÏhÐhÑhÓhÖhÙhÜhÝhåhèhêhëhìhíhðhñhõhöhûhühýii i iiiiii1i3i5i8i;iBiEiIiNiWi[icidieifihiiilipiqirizi{ii€ii’i–i˜i¡i¥i¦i¨i«i­i¯i·i¸iºi¼iÅiÈiÑiÖi×iâiåiîiïiñióiõiþjjjjjjjjj j$j(j0j2j4j7j;j>j?jEjFjIjJjNjPjQjRjUjVj[jdjgjjjqjsj~jjƒj†j‡j‰j‹j‘j›jjžjŸj¥j«j¯j°j±j´j½j¾j¿jÆjÉjÈjÌjÐjÔjÕjÖjÜjÝjäjçjìjðjñjòjüjýkkkkk kkkkkkk$k(k+k,k/k5k6k;k?kFkJkMkRkVkXk]k`kgkkknkpkuk}k~k‚k…k—k›kŸk k¢k£k¨k©k¬k­k®k°k¸k¹k½k¾kÃkÄkÉkÌkÖkÚkákãkækçkîkñk÷kùkÿllll l llllll&l'l(l,l.l3l5l6l:l;l?lJlKlMlOlRlTlYl[l\lklmloltlvlxlyl{l…l†l‡l‰l”l•l—l˜lœlŸl°l²l´lÂlÆlÍlÏlÐlÑlÒlÔlÖlÚlÜlàlçlélëlìlîlòlômmm mmmmmm&m'm(lgm.m/m1m9mu?u@uCuGuHuNuPuRuWu^u_uauouquyuzu{u|u}u~uu…uu’u“u•u™uœu¢u¤u´uºu¿uÀuÁuÄuÆuÌuÎuÏu×uÜußuàuáuäuçuìuîuïuñuùvvvvvvv v vvvvvvvvvvv#v%v&v)v-v2v3v5v8v9v:vwBwEwFwJwMwNwOwRwVwWw\w^w_w`wbwdwgwjwlwpwrwswtwzw}w€w„wŒww”w•w–wšwŸw¢w§wªw®w¯w±wµw¾wÃwÉwÑwÒwÕwÙwÞwßwàwäwæwêwìwðwñwôwøwûxxx x xxxx!x"x#x-x.x0x5x7xCxDxGxHxLxNxRx\x^x`xaxcxdxhxjxnxzx~xŠxx”x˜x¡xxžxŸx¤x¨x¬x­x°x±x²x³x»x½x¿xÇxÈxÉxÌxÎxÒxÓxÕxÖxäxÛxßxàxáxæxêxòxóyxöx÷xúxûxÿyy yyyyyy y%y'y)y-y1y4y5y;y=y?yDyEyFyJyKyOyQyTyXy[y\ygyiykyryyy{y|y~y‹yŒy‘y“y”y•y–y˜y›yœy¡y¨y©y«y¯y±y´y¸y»yÂyÄyÇyÈyÊyÏyÔyÖyÚyÝyÞyàyâyåyêyëyíyñyøyüzzzz z z zzzzz!z'z+z-z/z0z4z5z8z9z:zDzEzGzHzLzUzVzYz\z]z_z`zezgzjzmzuzxz~z€z‚z…z†zŠz‹zz‘z”zžz z£z¬z³zµz¹z»z¼zÆzÉzÌzÎzÑzÛzèzézëzìzñzôzûzýzþ{{{{#{'{){*{+{-{.{/{0{1{4{={?{@{A{G{N{U{`{d{f{i{j{m{o{r{s{w{„{‰{Ž{{‘{–{›{ž{ {¥{¬{¯{°{²{µ{¶{º{»{¼{½{Â{Å{È{Ê{Ô{Ö{×{Ù{Ú{Û{è{ê{ò{ô{õ{ø{ù{ú{ü{þ|||||| | | ||||| |%|&|(|,|1|3|4|6|9|:|F|J|U|Q|R|S|Y|Z|[|\|]|^|a|c|g|i|m|n|p|r|y|||}|†|‡||”|ž| |¦|°|¶|·|º|»|¼|¿|Ä|Ç|È|É|Í|Ï|Ó|Ô|Õ|×|Ù|Ú|Ý|æ|é|ë|õ}}}} }}}}}}}}#}&}*}-}1}<}=}>}@}A}G}H}M}Q}S}W}Y}Z}\}]}e}g}j}p}x}z}{}}}‚}ƒ}…}†}ˆ}‹}Œ}}‘}–}—}}ž}¦}§}ª}³}¶}·}¹}Â}Ã}Ä}Å}Æ}Ì}Í}Î}×}Ù~}â}å}æ}ê}ë}í}ñ}õ}ö}ù}ú~~~~~~~~ ~'~(~,~-~/~3~6~?~D~E~G~N~P~R~X~_~a~b~e~k~n~o~s~x~~~~†~‡~Š~~‘~•~˜~š~~ž<;=>?CDGORS[\]acdefmq}~€‹‘–—œ¡¢¦ª­´¼¿ÀÃÈÎÏÛßãåèìîïòúýþÿ€€€ € €€€€€€€€€€ €$€&€,€.€0€4€5€7€9€:€<€>€@€D€`€d€f€m€q€u€€ˆ€Ž€œ€ž€¦€§€«€¸€¹€È€Í€Ï€Ò€Ô€Õ€×€Ø€à€í€î€ð€ò€ó€ö€ù€ú€þ  $',05:‡@‡C‡E‡M‡X‡]‡a‡d‡e‡o‡q‡r‡{‡ƒ‡„‡…‡†‡‡‡ˆ‡‰‡‹‡Œ‡‡“‡•‡—‡˜‡™‡ž‡ ‡£‡§‡¬‡­‡®‡±‡µ‡¾‡¿‡Á‡È‡É‡Ê‡Î‡Õ‡Ö‡Ù‡Ú‡Ü‡ß‡â‡ã‡ä‡ê‡ë‡í‡ñ‡ó‡ø‡ú‡ÿˆˆˆˆ ˆ ˆ ˆˆˆˆˆˆˆˆˆˆˆˆ(ˆ-ˆ.ˆ0ˆ2ˆ5ˆ:ˆ<ˆAˆCˆEˆHˆIˆJˆKˆNˆQˆUˆVˆXˆZˆ\ˆ_ˆ`ˆdˆiˆqˆyˆ{ˆ€ˆ˜ˆšˆ›ˆœˆŸˆ ˆ¨ˆªˆºˆ½ˆ¾ˆÀˆÊˆËˆÌˆÍˆÎˆÑˆÒˆÓˆÛˆÞˆçˆïˆðˆñˆõˆ÷‰‰‰ ‰‰‰‰‰‰‰‰‰ ‰&‰'‰(‰0‰1‰2‰5‰9‰:‰>‰@‰B‰E‰F‰I‰O‰R‰W‰Z‰[‰\‰a‰b‰c‰k‰n‰p‰s‰u‰z‰{‰|‰}‰‰‰‰‰”‰•‰›‰œ‰Ÿ‰ ‰¥‰°‰´‰µ‰¶‰·‰¼‰Ô‰Õ‰Ö‰×‰Ø‰å‰é‰ë‰í‰ñ‰ó‰ö‰ù‰ý‰ÿŠŠŠŠŠŠŠŠŠŠ Š"Š$Š&Š+Š,Š/Š5Š7Š=Š>Š@ŠCŠEŠGŠIŠMŠNŠSŠVŠWŠXŠ\Š]ŠaŠeŠgŠuŠvŠwŠyŠzŠ{Š~ŠŠ€ŠƒŠ†Š‹ŠŠŠ’Š–Š—Š™ŠŸŠ§Š©Š®Š¯Š³Š¶Š·Š»Š¾ŠÃŠÆŠÈŠÉŠÊŠÑŠÓŠÔŠÕŠ×ŠÝŠßŠìŠðŠôŠõŠöŠüŠÿ‹‹‹ ‹‹‹‹‹ ‹-‹0‹7‹<‹B‹C‹D‹E‹F‹H‹R‹S‹T‹Y‹M‹^‹c‹m‹v‹x‹y‹|‹~‹‹„‹…‹‹‹‹‹”‹•‹œ‹ž‹ŸŒ8Œ9Œ=Œ>ŒEŒGŒIŒKŒOŒQŒSŒTŒWŒXŒ[Œ]ŒYŒcŒdŒfŒhŒiŒmŒsŒuŒvŒ{Œ~Œ†Œ‡Œ‹ŒŒ’Œ“Œ™Œ›ŒœŒ¤Œ¹ŒºŒÅŒÆŒÉŒËŒÏŒÖŒÕŒÙŒÝŒáŒèŒìŒïŒðŒòŒõŒ÷ŒøŒþŒÿ eiln‚„ˆ‘•žŸ ¦«¬¯²µ·¹»ÀÅÆÇÈÊÎÑÔÕ×Ùäåçìð¼ñòôýŽŽŽŽŽ ŽŽŽŽ Ž!Ž"Ž#Ž&Ž'Ž1Ž3Ž6Ž7Ž8Ž9Ž=Ž@ŽAŽKŽMŽNŽOŽTŽ[Ž\Ž]Ž^ŽaŽbŽiŽlŽmŽoŽpŽqŽyŽzŽ{Ž‚ŽƒŽ‰ŽŽ’Ž•ŽšŽ›ŽŽžŽ¢Ž§Ž©Ž­Ž®Ž³ŽµŽºŽ»ŽÀŽÁŽÃŽÄŽÇŽÏŽÑŽÔŽÜŽèŽîŽðŽñŽ÷ŽùŽúŽí !#%'(,-.4567:@ACGOQRSTUX]^e ¡¤¥¦µ¶¸¾ÀÁÆÊËÍÐÒÓÕàãäèîñõöûþ ()/*,-347?CDL[]bfglpty…ˆ‹ŒŽ•—˜™› ¡¢¥°²³´¶½Ì¾ÃÄÅÇÈÕרÙÜÝßåÒöëïðôþÿ‘‘‘‘‘‘ ‘‘‘‘‘‘‘‘‘ ‘%‘"‘#‘'‘)‘.‘/‘1‘4‘6‘7‘9‘:‘<‘=‘C‘G‘H‘O‘S‘W‘Y‘Z‘[‘a‘d‘g‘m‘t‘y‘z‘{‘‘ƒ‘…‘†‘Бޑ‘‘“‘”‘•‘˜‘ž‘¡‘¦‘¨‘¬‘­‘®‘°‘±‘²‘³‘¶‘»‘¼‘½‘¿‘‘Ñőӑԑבّڑޑä‘å‘é‘ê‘ì‘í‘î‘ï‘ð‘ñ‘÷‘ù‘û‘ý’’’’’’’ ’ ’ ’’’’’’’’#’$’%’&’(’.’/’0’3’5’6’8’9’:’<’>’@’B’C’F’G’J’M’N’O’Q’X’Y’\’]’`’a’e’g’h’i’n’o’p’u’v’w’x’y’{’|’}’’ˆ’‰’Š’’Ž’’’—’™’Ÿ’ ’¤’¥’§’¨’«’¯’²’¶’¸’º’»’¼’½’¿’À’Á’’ÒŒƒǒȒ˒̒͒ΒВӒՒגْؒܒݒߒà’á’ã’å’ç’è’ì’î’ð’ù’û’ÿ““““ ““““““““!“$“%“'“)“*“3“4“6“7“G“H“I“P“Q“R“U“W“X“Z“^“d“e“g“i“j“m“o“p“q“s“t“v“z“}““€““‚“ˆ“Š“‹“““’“•“˜“›“ž“¡“£“¤“¦“¨“«“´“µ“¶“º“©“Á“Ä“Å“Æ“Ç“É“Ê“Ë“Ì“Í“Ó“Ù“Ü“Þ“ß“â“æ“ç“ù“÷“ø“ú“û“ý””””” ” ”””””””.”/”1”2”3”4”;”?”=”C”E”H”J”L”U”Y”\”_”a”c”h”k”m”n”o”q”r”„”ƒ•x•y•~•„•ˆ•Œ••Ž••ž•Ÿ•¡•¦•©•«•¬•´•¶•º•½•¿•ƕȕɕ˕Еѕҕӕٕڕݕޕߕà•䕿–––"–$–%–&–,–1–3–7–8–9–:–<–=–A–R–T–V–W–X–a–n–t–{–|–~–––‚–ƒ–„–‰–‘–––š––Ÿ–¤–¥–¦–©–®–¯–³–º–Ê–Ò]²–Ø–Ú–Ý–Þ–ß–é–ï–ñ–ú———— ————!—"—#—(—1—3—A—C—J—N—O—U—W—X—Z—[—c—g—j—n—s—v—w—x—{—}——€—‰—•—–———™—š—ž—Ÿ—¢—¬—®—±—²—µ—¶—¸—¹—º—¼—¾—¿—Á—ėŗǗɗʗ̗͗ΗЗїԗחؗٗݗޗà—Û—á—ä—ï—ñ—ô—÷—ø—ú˜˜ ˜˜ ˜˜˜˜˜˜ ˜#˜&˜+˜.˜/˜0˜2˜3˜5˜%˜>˜D˜G˜J˜Q˜R˜S˜V˜W˜Y˜Z˜b˜c˜e˜f˜j˜l˜«˜­˜®˜°˜´˜·˜¸˜º˜»˜¿˜Â˜Å˜È˜Ì˜á˜ã˜å˜æ˜ç˜ê˜ó˜ö™™™™™™™™™™™™"™&™'™+™1™2™3™4™5™9™:™;™<™@™A™F™G™H™M™N™T™X™Y™[™\™^™_™`™›™™Ÿ™¦™°™±™²™µ™¹™º™½™¿™Ã™É™Ó™Ô™Ù™Ú™Ü™Þ™ç™ê™ë™ì™ð™ô™õ™ù™ý™þšššš š ššššš š"š#š$š'š-š.š3š5š6š8šGšAšDšJšKšLšNšQšTšVš]šªš¬š®š¯š²š´šµš¶š¹š»š¾š¿šÁšÃšÆšÈšÎšÐšÒšÕšÖš×šÛšÜšàšäšåšçšéšìšòšóšõšùšúšýšÿ›››››››› › › › ›››››››› ›&›+›-›3›4›5›7›9›:›=›H›K›L›U›V›W›[›^›a›c›e›f›h›j›k›l›m›n›s›u›w›x›y››€›„›…›†›‡›‰›Š›‹››››”›š››ž›¦›§›©›¬›°›±›²›·›¸›»›¼›¾›¿›Á›Ç›È›Î›Ð›×›Ø›Ý›ß›å›ç›ê›ë›ï›ó›÷›ø›ù›ú›ý›ÿœœœ œœœœœœœœœ"œ#œ&œ'œ(œ)œ*œ1œ5œ6œ7œ=œAœCœDœEœIœJœNœOœPœSœTœVœXœ[œ]œ^œ_œcœiœjœ\œkœhœnœpœrœuœwœ{œæœòœ÷œù /0234:?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿaÿbÿcÿdÿeÿfÿgÿhÿiÿjÿkÿlÿmÿnÿoÿpÿqÿrÿsÿtÿuÿvÿwÿxÿyÿzÿ{ÿ|ÿ}ÿ~ÿÿ€ÿÿ‚ÿƒÿ„ÿ…ÿ†ÿ‡ÿˆÿ‰ÿŠÿ‹ÿŒÿÿŽÿÿÿ‘ÿ’ÿ“ÿ”ÿ•ÿ–ÿ—ÿ˜ÿ™ÿšÿ›ÿœÿÿžÿŸÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿ\¡žÿÿÿÿg@þÿÿÿÿÿÿÿ@½¡ÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿO£^€ÿÿÿÿþÿÿ‡ÿÿÿÿÿÿÿÿÿÿ@—ÿÿÿÿÿÿÿÿÿ€ÿÿ€ÿÿ@˜ÿÿÿÿÿÿÿ€ÿÿÿ@]ÿÿÿ¿ÿÿ?@ÿÿÿŸ^t€ÿÿÿÿÿÿÿÿÿÿÿ@½Òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Lÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Æÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ƒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ ºÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ wÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ 4ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ ñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ ®ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½(ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½åÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿ@½¢ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½_ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Sÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Íÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Šÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Gÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Áÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½~ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½;ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½µÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½rÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@e/ÿÿÿÿÿÿÿÿÿÿÿ@½”ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½QÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸÿ@½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@½Ëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@ ˆÿ\ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ~ÿÿÿÿÿÿÿÿ ÿÿÿaÿbÿcÿdÿeÿfÿgÿhÿiÿjÿkÿlÿmÿnÿoÿpÿqÿrÿsÿtÿuÿvÿwÿxÿyÿzÿ{ÿ|ÿ}ÿ~ÿÿ€ÿÿ‚ÿƒÿ„ÿ…ÿ†ÿ‡ÿˆÿ‰ÿŠÿ‹ÿŒÿÿŽÿÿÿ‘ÿ’ÿ“ÿ”ÿ•ÿ–ÿ—ÿ˜ÿ™ÿšÿ›ÿœÿÿžÿŸ !"#$%&'(ÿÿÿÿ)*ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ+,-000ÿ ÿ0ûÿÿÿÿ0›0œ´ÿ@¨ÿ>ÿãÿ?0ý0þ00ž0NÝ0000ü  ÿÿ<ÿ^"%ÿ\ & %    ÿÿ 00ÿ;ÿ=ÿ[ÿ]00 0 0 0 0 0000ÿ ÿ ±×ÿÿ÷ÿ"`ÿÿ"f"g""4&B&@° 2 3!ÿåÿÿàÿáÿÿÿÿ ÿ §&&%Ë%Ï%Î%Ç%Æ%¡% %³%²%½%¼ ;0!’!!‘!“0ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"" "†"‡"‚"ƒ"*")ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ"'"(ÿâ!Ò!Ô""ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ" "¥#"""a"R"j"k""=""5"+",ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!+ 0&o&m&j !¶ÿÿÿÿÿÿÿÿ%ïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿ"ÿ#ÿ$ÿ%ÿ&ÿ'ÿ(ÿ)ÿ*ÿ+ÿ,ÿ-ÿ.ÿ/ÿ0ÿ1ÿ2ÿ3ÿ4ÿ5ÿ6ÿ7ÿ8ÿ9ÿ:ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿAÿBÿCÿDÿEÿFÿGÿHÿIÿJÿKÿLÿMÿNÿOÿPÿQÿRÿSÿTÿUÿVÿWÿXÿYÿZÿÿÿÿÿÿÿÿ0A0B0C0D0E0F0G0H0I0J0K0L0M0N0O0P0Q0R0S0T0U0V0W0X0Y0Z0[0\0]0^0_0`0a0b0c0d0e0f0g0h0i0j0k0l0m0n0o0p0q0r0s0t0u0v0w0x0y0z0{0|0}0~00€00‚0ƒ0„0…0†0‡0ˆ0‰0Š0‹0Œ00Ž000‘0’0“0¡0¢0£0¤0¥0¦0§0¨0©0ª0«0¬0­0®0¯0°0±0²0³0´0µ0¶0·0¸0¹0º0»0¼0½0¾0¿0À0Á0Â0Ã0Ä0Å0Æ0Ç0È0É0Ê0Ë0Ì0Í0Î0Ï0Ð0Ñ0Ò0Ó0Ô0Õ0Ö0×0Ø0Ù0Ú0Û0Ü0Ý0Þ0ßÿÿ0à0á0â0ã0ä0å0æ0ç0è0é0ê0ë0ì0í0î0ï0ð0ñ0ò0ó0ô0õ0öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‘’“”•–—˜™š›œžŸ ¡£¤¥¦§¨©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ±²³´µ¶·¸¹º»¼½¾¿ÀÁÃÄÅÆÇÈÉ !"#$%&'()*+,-./ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ012345Q6789:;<=ÿÿ>?@ABCDEFGHIJKLMNOÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ%%% %%%%%,%$%4%<%%%%%%%#%3%+%;%K% %/%(%7%?%%0%%%8%B$`$a$b$c$d$e$f$g$h$i$j$k$l$m$n$o$p$q$r$s!`!a!b!c!d!e!f!g!h!iÿÿ3I33"3M33'3363Q3W3 3&3#3+3J3;3œ33ž3Ž33Ä3¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ3{ÿÿ00!3Í!!2¤2¥2¦2§2¨2122293~3}3|"R"a"+"."""¥" ""¿"5")"*NœUZ–?TÀac(Yö"„uƒzP`ªcán%eí„f‚¦›õh“W'e¡bq[›YІ{˜ô}b}¾›Žb|Ÿˆ·[‰^µc f—hH•Ç—gONåO OMOPIVòY7YÔZ\ `ßaapfipºuOupyû}­}ï€Ã„ˆc‹UzS;N•N¥W߀²ÁxïNXñn¢8z2ƒ(‚‹œ/QASpT½TáVàYû_˜òmë€ä…-–b–p– —ûT Só[‡pϽ–èSo\zºNx“ün&VUk…œ;YåS©mftÜ•VBN‘K–òƒO™ SáU¶[0_qf fóhl8lóm)t[vÈzN˜4‚ñˆ[Š`’ím²u«vÊ™Å`¦‹Š•²iŽS­Q†ÿÿWX0YD[´^ö`(c©côl¿opŽqqYqÕs?~‚v‚Ñ…—`’[Xie¼lZu%QùY.Ye_€_Üb¼eúj*k'k´s‹Á‰V,žÄ\¡l–ƒ{Q\Ka¶ÆhvraNYOúSx`in)zO—óN SNîOUO=O¡OsR SïV YZÁ[¶[áyÑf‡gœg¶kLl³pksÂyy¾z<{‡‚±‚ÛƒƒwƒïƒÓ‡fвV)Œ¨æN—†ŠOÄ\èbrYu;傽†þŒÀ–Å™™ÕNËO‰ãVÞXJXÊ^û_ë`*`”`baÐbbÐe9›Affh°mwppuLv†}u‚¥‡ù•‹–ŽŒQñR¾YT³[³]ahi‚m¯x„ˈWŠr“§š¸ml™¨†ÙW£gÿ†Î’RƒV‡T^Óbád¹hkSlWo"o—oEt°uvãw zÿ{¡|!}é6ð€‚fƒž‰³ŠÌŒ«„”Q•“•‘•¢–e—Ó™(‚N8T+\¸]Ìs©vLw<\©ë –Á˜˜T˜XOOSqUœVhWúYG[ [Ä\^ ^~_Ìcîg:e×eâghËhÄj_^0kÅll}uyH[cz}_½‰ŠŒ´wŽÌ˜âš›Z/_Œ_¡`Ÿh§jŽtZxŠžŠ¤‹w‘N^›ÉN¤O|O¯PPQIQlRŸR¹RþSšSãTTU‰WQW¢Y}[T[][]å]ç]÷^x^ƒ^š^·_`RaLb—bØc§e;ffCfôgmh!h—iËl_m*min/nu2v‡xlz?|à}}}^}±€€€¯€±T‚*ƒRˆLˆa‹Œ¢ŒüÊ‘u’qx?’ü•¤–Mÿÿ˜™™šØ;R[R«S÷TXÕb÷oàŒj_ž¹QKR;TJVýz@‘w`žÒsDo pu_ý`Úš¨rÛ¼kd˜NÊVðWdX¾ZZ`haÇffh9h±m÷uÕ}:‚n›BN›OPSÉU]o]æ]îgûl™tsxŠP“–ˆßWP^§c+PµP¬QgTÉX^Y»[°_ibMc¡h=ksnp}‘Çr€xx&ymeŽ}0ƒÜˆÁ –›RdW(gPjŒ¡Q´WB–*X:iŠ€´T²]Wüx•úO\RJT‹d>f(ggõz„{V}"“/h\›­{9SQŠR7[ßböd®dæg-kº…©–Ñv›ÖcL“›«v¿fRN P˜SÂ\q`èd’ech_qæsÊu#{—~‚†•‹ƒŒÛ‘x™e¬f«k‹NÕNÔO:OR:SøSòUãVÛXëYËYÉYÿ[P\M^^+_×`ce/[\e¯e½eègkbÿÿk{lsEyIyÁ|ø}}+€¢ó‰–Š^ŠiŠfŠŒŠîŒÇŒÜ–̘ükoN‹Ot½uÔxÁy:€ €3ê„”žlPž_‹X+zúŽø[–ëNSñW÷Y1ZÉ[¤`‰nou¾Œê[Ÿ…{àPrgô‚\a…J~‚Q™\chfeœqny>}€‹ŽÊn†ÇªPRú\:gSp|r5‘L‘È“+‚å[Â_1`ùN;SÖ[ˆbKg1kŠrésàz.k£‘R™–QS×Tj[ÿcˆj9}¬—VÚSÎTh[—\1]ÞOîabþm2yÀyË}B~MÒí‚„ˆF‰r‹Žt/1‘K‘l–Æ‘œNÀOOQESA_“bgÔlAn sc~&‘Í’ƒSÔY[¿mÑy]~.|›X~qŸQúˆSðOÊ\ûf%w¬zã‚™ÿQÆ_ªeìiok‰móÿÿn–odvþ}]áu‘‡˜QæRb@f‘fÙn^¶}Òrfø…¯…÷ŠøR©SÙYs^_`U’ä–dP·QRÝS SGSìTèUFU1VYhY¾Z<[µ\\\\^„^Š^à_pbb„bÛcŒcwff f-fvg~h¢jj5l¼mˆn nXq Œ¬dáŽ_x©RbÙc¥dBb˜Š-zƒ{ÀЬ–ê}v‚ ‡INÙQHSCS`[£\\]Ýb&bGd°hh4lÉmEmgÓo\qNq}eËz{­}Ú~J¨z‚‚9…¦ŠnŒÎõxw’­’‘•ƒ›®RMU„o8q6Qhy…~U³|ÎVLXQ\¨cªfþfýiZrÙuuŽyyVyß|—} }D†Š4–;aŸ PçRuSÌSâP UªXîYOr=[‹\dS`ã`óc\cƒc?c»ÿÿdÍeéfù]ãiÍiýoqåN‰uévøz“|ß}Ï}œ€aƒIƒX„l„¼…ûˆÅpm“——šPÏX—aŽÓ…5 OÃPtRGSs`ocIg_n,³O×\^ŒÊeÏ}šSRˆ–QvcÃ[X[k\ d gQ\NÖYY*lpŠQU>XY¥`ðbSgÁ‚5iU–@™Äš(OSX[þ€\±^/_…` aKb4fÿlðnހ΂Ԉ‹Œ¸.–ŠžÛ›ÛNãSðY'{,‘˜LùnÝp'SSUD[…bXbžbÓl¢oït"Š”8oÁŠþƒ8Qç†øSêSéOFT°Yj1]ýzê¿hÚŒ7røœHj=аN9SXVWfbÅc¢eækNmán[p­wízï{ª}»€=€Æ†ËŠ•“[VãXÇ_>e­f–j€kµu7ŠÇP$wåW0_`efzl`uôznô‡E™³{Éu\zù{Q„Äÿÿyéz’ƒ6Záw@N-Nò[™_àb½ft6x4ZFu‚­™¬Oó^ÃbÝc’eWgovÃrL€Ì€º)‘MP WùZ’h…ÿÿisqdrýŒ·XòŒà–j‡yäwç„)O/ReSZbÍgÏlÊv}{”|•‚6…„ëfÝo r~ƒ«™Áž¦Qý{±xr{¸€‡{Hjè^a€ŒuQu`Qk’bnŒvz‘—šêOpbœ{O•¥œéVzXY†ä–¼O4R$SJSÍSÛ^d,e‘gl>lNrHr¯síuT~A‚,…錩{Ä‘Æqi˜˜ïc=fiujväxÐ…C†îS*SQT&Yƒ^‡_|`²bIbyb«ekÔlÌu²v®x‘yØ}Ëw€¥ˆ«Š¹Œ»—^˜Ûj |8P™\>_®g‡kØt5w ŽŸ;gÊzS9u‹ší_fƒñ€˜_<_Åub{Fe¹g lÕlápùx2~+€Þ‚³„ „쇉Š*ŒJ¦’Ò˜ýœólNON¡PRVWJY¨^=_Ø_Ùb?f´ggÐhÒQ’}!€ª¨‹ŒŒŒ¿’~–2T ˜,SPÕS\X¨d²g4rgwfzF‘æRÃl¡k†X^LYTg,ûQávÆÿÿdixè›Tž»WËY¹f'gškÎTéiÙ^Uœg•›ªgþœRh]N¦OãSÈb¹g+l«ÄO­~mž¿Nabn€o+…Tsg*›E]ó{•\¬[ƇnJ„ÑzY™|lw RÙY"q!r_wÛ—'ai ZZQ¥T T}fvß÷’˜œôYêr]nÅQMhÉ}¿}ì—bžºdxj!ƒY„[_kÛsvò}²€„™Q2g(žÙvîgbRÿ™\$b;|~Œ°UO`¶} •€SN_Q¶Yr:€6‘Î_%wâS„_y}…¬Š3Ž—Vgó…®”Sa al¹vRŠí8U/OQQ*RÇSË[¥^}` a‚cÖg gÚngmŒs6s7u1yPˆÕŠ˜J‘õ–ćYNˆOYNЉ?˜P­^|Y–[¹^¸cÚcúdÁfÜiJiØm n¶q”u(z¯Š€„I„ɉ‹!Ž e–}™ a~b‘k2ÿÿlƒmtÌümÀ…‡ºˆøgeƒ±˜<–÷m}a„=‘jNqSu]Pkoë…͆-‰§R)T\egNh¨ttƒuâˆÏˆá‘Ì–â–x_‹s‡zË„Nc ueR‰mAnœt uYxk|’–†zÜŸO¶aneņ\N†N®PÚN!QÌ[îe™hm¼svBw­z|ç‚oŠÒ|‘Ï–u˜R›}ÑP+S˜g—mËqÐt3è*–£œWžŸt`XAm™}/˜^NäO6O‹Q·R±]º`s²y<‚Ó’4–·–ö— ž—Ÿbf¦ktRR£pȈÂ^É`Kao#qI|>}ô€o„î#“,TB›ojÓp‰ŒÂï—2R´ZA^Ê_gi|i”mjorbrü{퀀~‡KÎQmž“y„€‹“2ŠÖP-TŒŠqkjŒÄ`Ñg òN™N˜œŠk…Á…hin~x—Uÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ_ NNN*N1N6NzÒYUYPYNYZYXYbY`YgYlYiYxYYO^O«Y£Y²YÆYèYÜYYÙYÚZ%ZZZZ ZZ@ZlZIZ5Z6ZbZjZšZ¼Z¾ZËZÂZ½ZãZ×ZæZéZÖZúZû[ [ [[2ZÐ[*[6[>[C[E[@[Q[U[Z[[[e[i[p[s[u[xeˆ[z[€ÿÿ[ƒ[¦[¸[Ã[Ç[É[Ô[Ð[ä[æ[â[Þ[å[ë[ð[ö[ó\\\\ \\ \"\(\8\9\A\F\N\S\P\O[q\l\nNb\v\y\Œ\‘\”Y›\«\»\¶\¼\·\Å\¾\Ç\Ù\é\ý\ú\í]Œ\ê] ]]]\]]]]]"]]]]L]R]N]K]l]s]v]‡]„]‚]¢]]¬]®]½]]·]¼]É]Í]Ó]Ò]Ö]Û]ë]ò]õ^ ^^^^^6^7^D^C^@^N^W^T^_^b^d^G^u^v^zž¼^^ ^Á^Â^È^Ð^Ï^Ö^ã^Ý^Ú^Û^â^á^è^é^ì^ñ^ó^ð^ô^ø^þ__ _]_\_ ___)_-_8_A_H_L_N_/_Q_V_W_Y_a_m_s_w_ƒ_‚__Š_ˆ_‘_‡_ž_™_˜_ _¨_­_¼_Ö_û_ä_ø_ñ_Ý`³_ÿ`!``ÿÿ```)``1```+`&``:`Z`A`j`w`_`J`F`M`c`C`d`B`l`k`Y```ç`ƒ`š`„`›`–`—`’`§`‹`á`¸`à`Ó`´_ð`½`Æ`µ`ØaMaa`ö`÷a`ô`úaa!`û`ña aaGa>a(a'aJa?acMdcOc–cŽc€c«cvc£cc‰cŸcµckÿÿcic¾cécÀcÆcãcÉcÒcöcÄdd4ddd&d6edd(ddgdodvdNe*d•d“d¥d©dˆd¼dÚdÒdÅdÇd»dØdÂdñdç‚ dàdáb¬dãdïe,dödôdòdúedýeeee$e#e+e4e5e7e6e8uKeHeVeUeMeXe^e]erexe‚eƒ‹Še›eŸe«e·eÃeÆeÁeÄeÌeÒeÛeÙeàeáeñgrf feûgsf5f6f4ffOfDfIfAf^f]fdfgfhf_fbfpfƒfˆfŽf‰f„f˜ffÁf¹fÉf¾f¼fÄf¸fÖfÚfàf?fæféfðfõf÷gggg&g'—8g.g?g6gAg8g7gFg^g`gYgcgdg‰gpg©g|gjgŒg‹g¦g¡g…g·gïg´gìg³gég¸gägÞgÝgâgîg¹gÎgÆgçjœhhFh)h@hMh2hNÿÿh³h+hYhchwhhŸhh­h”hh›hƒj®h¹hthµh hºihh~ihÊihØi"i&hái hÍhÔhçhÕi6iih×hãi%hùhàhïi(i*ii#i!hÆiyiwi\ixikiTi~ini9iti=iYi0iai^i]iiji²i®iÐi¿iÁiÓi¾iÎ[èiÊiÝi»iÃi§j.i‘i iœi•i´iÞièjjiÿk iùiòiçji±jiíjiëj jjÁj#jjDj jrj6jxjGjbjYjfjHj8j"jjj j„j¢j£j—†j»jÃjÂj¸j³j¬jÞjÑjßjªjÚjêjûk†júkk›1kk8k7vÜk9˜îkGkCkIkPkYkTk[k_kakxkykk€k„kƒkk˜k•kžk¤kªk«k¯k²k±k³k·k¼kÆkËkÓkßkìkëkókïÿÿž¾lllll$l#l^lUlbljl‚llšll›l~lhlsl’llÄlñlÓl½l×lÅlÝl®l±l¾lºlÛlïlÙlêmˆMm6m+m=m8mm5m3mm mcm“mdmZmymYmŽm•oäm…mùnn mµmÇmæm¸mÆmìmÞmÌmèmÒmÅmúmÙmämÕmêmîn-nnn.nnrn_n>n#nkn+nvnMnnCn:nNn$nÿnn8n‚nªn˜nÉn·nÓn½n¯nÄn²nÔnÕnn¥nÂnŸoAopLnìnønþo?nòo1nïo2nÌo>on÷o†ozoxoo€ooo[oóomo‚o|oXoŽo‘oÂofo³o£o¡o¤o¹oÆoªoßoÕoìoÔoØoñoîoÛp p oúpppoþppotpppp0p>p2pQpcp™p’p¯pñp¬p¸p³p®pßpËpÝÿÿpÙq pýqqqeqUqˆqfqbqLqVqlqqûq„q•q¨q¬q×q¹q¾qÒqÉqÔqÎqàqìqçqõqüqùqÿr rrr(r-r,r0r2r;rsNsOžØsWsjshspsxsus{szsÈs³sÎs»sÀsåsîsÞt¢ttot%søt2t:tUt?t_tYtAt\titptctjtvt~t‹tžt§tÊtÏtÔsñtàtãtçtétîtòtðtñtøt÷uuuu uu uuuu&u,uz7zCzWzIzazbziŸzpzyz}zˆz—z•z˜z–z©zÈz°ÿÿz¶zÅzÄz¿ƒzÇzÊzÍzÏzÕzÓzÙzÚzÝzázâzæzízð{{{ {{3{{{{5{({6{P{z{{M{ {L{E{u{e{t{g{p{q{l{n{{˜{Ÿ{{œ{š{‹{’{{]{™{Ë{Á{Ì{Ï{´{Æ{Ý{é||{æ{å|`|||{ó{÷|| {ö|#|'|*||7|+|=|L|C|T|O|@|P|X|_|d|V|e|l|u|ƒ||¤|­|¢|«|¡|¨|³|²|±|®|¹|½|À|Å|Â|Ø|Ò|Ü|â›;|ï|ò|ô|ö|ú}}}}} }E}K}.}2}?}5}F}s}V}N}r}h}n}O}c}“}‰}[}}}}›}º}®}£}µ}Ç}½}«~=}¢}¯}Ü}¸}Ÿ}°}Ø}Ý}ä}Þ}û}ò}á~~ ~#~!~~1~~ ~ ~"~F~f~;~5~9~C~7ÿÿ~2~:~g~]~V~^~Y~Z~y~j~i~|~{~ƒ}Õ~}®~~ˆ~‰~Œ~’~~“~”~–~Ž~›~œ8:ELMNPQUTX_`higx‚†ƒˆ‡Œ”žš£¯²¹®¶¸‹qÅÆÊÕÔáæéóù˜Ü€€€ €€€€€!€(€?€;€J€F€R€X€Z€_€b€h€s€r€p€v€y€}€€„€†€…€›€“€š€­Q€¬€Û€å€Ù€Ý€Ä€Ú€Ö €ï€ñ)#/K–‹F>SQ€üqneftƒˆŠ€‚ •¤£_“©°µ¾¸½ÀºÉÍÑÙØÈÚßàçúûþ‚‚‚‚‚ ‚ ‚‚‚)‚+‚8‚3‚@‚Y‚X‚]‚Z‚_‚dÿÿ‚b‚h‚j‚k‚.‚q‚w‚x‚~‚‚’‚«‚Ÿ‚»‚¬‚á‚ã‚߂҂ô‚ó‚úƒ“ƒ‚û‚ù‚Þƒ‚܃ ‚Ùƒ5ƒ4ƒƒ2ƒ1ƒ@ƒ9ƒPƒEƒ/ƒ+ƒƒƒ…ƒšƒªƒŸƒ¢ƒ–ƒ#ƒŽƒ‡ƒŠƒ|ƒµƒsƒuƒ ƒ‰ƒ¨ƒô„ƒëƒÎƒý„ƒØ„ ƒÁƒ÷„ƒàƒò„ „"„ ƒ½„8…ƒû„m„*„<…Z„„„w„k„­„n„‚„i„F„,„o„y„5„Ê„b„¹„¿„Ÿ„Ù„Í„»„ڄЄÁ„Ƅք¡…!„ÿ„ô………,………„ü…@…c…X…H…A†…K…U…€…¤…ˆ…‘…Š…¨…m…”…›…ê…‡…œ…w…~……É…º…Ï…¹…Ð…Õ…Ý…å…Ü…ù† †† …þ…ú††"††0†?†MNU†T†_†g†q†“†£†©†ª†‹†Œ†¶†¯†Ä†Æ†°†Éˆ#†«†Ô†Þ†é†ìÿÿ†ß†Û†ï‡‡‡‡‡†û‡‡ ‡ †ù‡ ‡4‡?‡7‡;‡%‡)‡‡`‡_‡x‡L‡N‡t‡W‡h‡n‡Y‡S‡c‡jˆ‡¢‡Ÿ‡‚‡¯‡Ë‡½‡À‡Ð–Ö‡«‡Ä‡³‡Ç‡Æ‡»‡ï‡ò‡àˆˆ ‡þ‡ö‡÷ˆ‡Òˆˆˆˆ"ˆ!ˆ1ˆ6ˆ9ˆ'ˆ;ˆDˆBˆRˆYˆ^ˆbˆkˆˆ~ˆžˆuˆ}ˆµˆrˆ‚ˆ—ˆ’ˆ®ˆ™ˆ¢ˆˆ¤ˆ°ˆ¿ˆ±ˆÃˆÄˆÔˆØˆÙˆÝˆù‰ˆüˆôˆèˆò‰‰ ‰ ‰‰C‰‰%‰*‰+‰A‰D‰;‰6‰8‰L‰‰`‰^‰f‰d‰m‰j‰o‰t‰w‰~‰ƒ‰ˆ‰Š‰“‰˜‰¡‰©‰¦‰¬‰¯‰²‰º‰½‰¿‰À‰Ú‰Ü‰Ý‰ç‰ô‰øŠŠŠŠ ŠŠŠ%Š6ŠAŠ[ŠRŠFŠHŠ|ŠmŠlŠbŠ…Š‚Š„Š¨Š¡Š‘Š¥Š¦ŠšŠ£ŠÄŠÍŠÂŠÚŠëŠóŠçÿÿŠäŠñ‹ŠàŠâŠ÷ŠÞŠÛ‹ ‹‹Šá‹‹‹‹ ‹3—«‹&‹+‹>‹(‹A‹L‹O‹N‹I‹V‹[‹Z‹k‹_‹l‹o‹t‹}‹€‹Œ‹Ž‹’‹“‹–‹™‹šŒ:ŒAŒ?ŒHŒLŒNŒPŒUŒbŒlŒxŒzŒ‚Œ‰Œ…ŒŠŒŒŽŒ”Œ|Œ˜bŒ­ŒªŒ½Œ²Œ³Œ®Œ¶ŒÈŒÁŒäŒãŒÚŒýŒúŒû  ŸNŒÍgmqs™Â¾ºÏÚÖÌÛËêëßãüŽŽ ÿŽŽŽŽŽBŽ5Ž0Ž4ŽJŽGŽIŽLŽPŽHŽYŽdŽ`Ž*ŽcŽUŽvŽrŽ|ŽŽ‡Ž…Ž„Ž‹ŽŠŽ“Ž‘Ž”Ž™ŽªŽ¡Ž¬Ž°ŽÆŽ±Ž¾ŽÅŽÈŽËŽÛŽãŽüŽûŽëŽþ  &3;9EB>LIFNW\ÿÿbcdœŸ£­¯·Úåâêï‡ôùú!  '659øOPQRI>VX^hov–¨r‚}€Š‰¨¯±µâäbHÛ‘‘‘‘2‘0‘J‘V‘X‘c‘e‘i‘s‘r‘‹‘‰‘‚‘¢‘«‘¯‘ª‘µ‘´‘º‘À‘Á‘ɑˑБ֑ߑá‘Û‘ü‘õ‘ö’‘ÿ’’,’’’^’W’E’I’d’H’•’?’K’P’œ’–’“’›’Z’Ï’¹’·’é“’ú“D“.““"““#“:“5“;“\“`“|“n“V“°“¬“­“”“¹“֓דè“哨“ÓݓГȓä”””””””6”+”5”!”:”A”R”D”[”`”b”^”j’)”p”u”w”}”Z”|”~””•‚•‡•Š•”•–•˜•™ÿÿ• •¨•§•­•¼•»•¹•¾•Êoö•Õ͕̕Օԕ֕ܕá•å•â–!–(–.–/–B–L–O–K–w–\–^–]–_–f–r–l––˜–•–—–ª–§–±–²–°–´–¶–¸–¹–Ζ˖ɖ͉M–Ü— –Õ–ù——————————$—*—0—9—=—>—D—F—H—B—I—\—`—d—f—hRÒ—k—q—y—…—|——z—†—‹———œ—¨—¦—£—³—´—×Ɨȗ˗ܗíŸO—òzß—ö—õ˜˜ ˜8˜$˜!˜7˜=˜F˜O˜K˜k˜o˜p˜q˜t˜s˜ª˜¯˜±˜¶˜Ä˜Ã˜Æ˜é˜ë™™ ™™™™!™™™$™ ™,™.™=™>™B™I™E™P™K™Q™R™L™U™—™˜™¥™­™®™¼™ß™Û™Ý™Ø™Ñ™í™î™ñ™ò™û™øššš™âšš+š7šEšBš@šCÿÿš>šUšMš[šWš_šbšešdšiškšjš­š°š¼šÀšÏšÑšÓšÔšÞšßšâšãšæšïšëšîšôšñš÷šû›››››"›#›%›'›(›)›*›.›/›2›D›C›O›M›N›Q›X›t›“›ƒ›‘›–›—›Ÿ› ›¨›´›À›Ê›¹›Æ›Ï›Ñ›Ò›ã›â›ä›Ô›áœ:›ò›ñ›ðœœœ œœ œœœœ œœ.œœ%œ$œ!œ0œGœ2œFœ>œZœ`œgœvœxœçœìœð œë*&¯#DA?>FH]^dQPYr‰‡«oz𤩲ÄÁ»¸ºÆÏÂÙÓøæíïýžžžžužyž}žžˆž‹žŒž’ž•ž‘žž¥ž©ž¸žªž­—ažÌžÎžÏžÐžÔžÜžÞžÝžàžåžèžïÿÿžôžöž÷žùžûžüžýŸŸv·ŸŸ!Ÿ,Ÿ>ŸJŸRŸTŸcŸ_Ÿ`ŸaŸfŸgŸlŸjŸwŸrŸvŸ•ŸœŸ X/iÇYtdQÜq™~Љ“H’ˆ„ÜOÉp»f1hÈ’ùfû_EN(NáNüOOO9OVO’OŠOšO”OÍP@P"OÿPPFPpPBP”PôPØQJQdQQ¾QìRRœR¦RÀRÛSSS$SrS“S²SÝúTœTŠT©TÿU†WYWeW¬WÈWÇúÿÿúXžX²Y YSY[Y]YcY¤Yº[V[Àu/[Ø[ì\\¦\º\õ]']Sú]B]m]¸]¹]Ð_!_4_g_·_Þ`]`…`Š`Þ`Õa `òaa7a0a˜bb¦cõd`ddÎeNfff;f f.ff$fefWfYúfsf™f f²f¿fúgù)gfg»hRgÀhhDhÏúihúi˜iâj0jkjFjsj~jâjäkÖl?l\l†lolÚmm‡mom–m¬mÏmømòmün9n\n'n ¤òÆÉ¤ó¤Ç¡¤EUC-JP¡¤Shift_JIS ¤È Unicode ¤ÎÊÑ´¹¤ÎÌäÂêÅÀ¤ò¤è¤¯ Íý²ò¤·¤¿¤¦¤¨¤Ç»È¤Ã¤Æ¤¯¤À¤µ¤¤¡£ xmlparser/lib/xml/dom/core.rb0000644000076400007640000017636107662573307016756 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::SimpleTree ## 1998-2000 by yoshidam ## ## XPointer support is contributed by Masaki Fukushima ## ## require 'singleton' =begin = XML::DOM (XML::SimpleTree) =end =begin == Module XML =end module XML =begin === Class Methods --- XML.charRef(s) replace character '&','<','>',"'",'"' in string s to character reference. =end def XML.charRef(s) str = s.dup str.gsub!("&", "&") str.gsub!("<", "<") str.gsub!(">", ">") str.gsub!("'", "'") str.gsub!('"', """) str end =begin == Module XML::Spec Constants related to XML Specification. =end ## [Masaki Fukushima] module Spec ## Constants related to XML Specification ## (W3C Recommendation or Working Draft) # XML Letter_s = '[a-zA-Z]' Digit_s = '\d' NameChar_s = "(#{Letter_s}|#{Digit_s}|[\\.\\-_:])" Name_s = "(#{Letter_s}|[_:])#{NameChar_s}*" SkipLit_s = "(\"[^\"]*\"|'[^']*')" Name = /^#{Name_s}$/o SkipList = /^#{SkipLit_s}$/o # XPointer Instance_s = "(\\+|-)?[1-9]#{Digit_s}*" Instance = /^#{Instance_s}$/o end =begin == Module XML::DOM (XML::SimpleTree) DOM-like APIs module. =end module DOM ## Fundamental Interfaces =begin == Class XML::DOM::DOMException === superclass Exception DOM exception. =end class DOMException 0 end =begin === Methods --- Node#parentNode [DOM] return parent node. =end ## [DOM] def parentNode @parent end =begin --- Node#parentNode=(p) set node p as parent. =end def parentNode=(p) @parent = p end =begin --- Node#nodeType [DOM] return nodetype. =end ## [DOM] def nodeType NODE_NODE end =begin --- Node#nodeName [DOM] return nodename. =end ## [DOM] def nodeName "#node" end # def nodeName=(p) # @name = p # end =begin --- Node#nodeValue [DOM] return nodevalue. =end ## [DOM] def nodeValue; nil; end =begin --- Node#nodeValue=(p) [DOM] set nodevalue as p. =end ## [DOM] def nodeValue=(p) ## no effect end =begin --- Node#childNodes() [DOM] if method has block, apply block for children nodes. without block, return children nodelist. =end ## [DOM] def childNodes if iterator? @children.each do |child| yield(child) end if @children else return @children if !@children.nil? @children = NodeList.new end end =begin --- Node#childNodes=(p) set child node as p. =end def childNodes=(p) if @children.nil? @children = NodeList.new else @children.to_a.clear end if p.nil? || (p.is_a?(Array) && p.length == 0) return end p.flatten! p.each do |child| if child.is_a?(String) c = Text.new(child) @children.push(c) c.parentNode = self elsif child.is_a?(Node) @children.push(child) child.parentNode = self else raise "parameter error" end end if p end =begin --- Node#attributes [DOM] return attributes of node(but always return nil?). =end ## [DOM] def attributes nil end ## proper parameter type? # def attributes=(p) # end =begin --- Node#[]=(index, nodes) set children node as nodes with []-style. =end def []=(index, nodes) @children[index..index] = nodes @children.each do |child| child.parentNode = self end if @children end =begin --- Node#[](index) get children node with []-style. =end def [](index) @children[index] end =begin --- Node#+(node) concat node to Node. =end def +(node) [self, node] end =begin --- Node#to_s returns the string representation of the Node. =end def to_s @children.to_s end =begin --- Node#dump(depth = 0) dump the Node. =end def dump(depth = 0) print ' ' * depth * 2 print nodeName + "\n" @children.each do |child| child.dump(depth + 1) end if @children end =begin --- Node#inspect() returns the human-readable string representation. =end def inspect "#<#{self.class}: #{self.nodeName}>" end =begin --- Node#firstChild() [DOM] return the first child node. =end ## [DOM] def firstChild return nil if !@children || @children.length == 0 return @children[0] end =begin --- Node#lastChild() [DOM] return the last child node. =end ## [DOM] def lastChild return nil if !@children || @children.length == 0 return @children[-1] end =begin --- Node#previousSibling() [DOM] return the previous sibling node. =end ## [DOM] def previousSibling return nil if !@parent prev = nil @parent.childNodes do |child| return prev if child == self prev = child end nil end =begin --- Node#nextSibling() [DOM] return the next sibling node. =end ## [DOM] def nextSibling return nil if !@parent nexts = nil @parent.childNodes.reverse.each do |child| return nexts if child == self nexts = child end nil end def _getChildIndex(node) index = 0 @children.each do |child| if child == node return index end index += 1 end nil end def _removeFromTree parent = parentNode if parent parent.removeChild(self) end end def _checkNode(node) raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR) end def _insertNodes(index, node) if node.nodeType == DOCUMENT_FRAGMENT_NODE node.childNodes.to_a.each_with_index do |n, i| if index == -1 _insertNodes(-1, n) else _insertNodes(index + i, n) end end elsif node.is_a?(Node) ## to be checked _checkNode(node) node._removeFromTree if index == -1 @children.push(node) else @children[index, 0] = node end node.parentNode = self else raise ArgumentError, "invalid value for Node" end end def _removeNode(index, node) @children[index, 1] = nil node.parentNode = nil end # =begin # --- Node#insertAfter(newChild, refChild) # # insert newChild into the node after refChild. # =end # def insertAfter(newChild, refChild) # if @children.nil? || @children.length == 0 # raise DOMException.new(DOMException::NOT_FOUND_ERR) # end # index = _getChildIndex(refChild) # raise DOMException.new(DOMException::NOT_FOUND_ERR) if index.nil? # _insertNodes(index, newChild) # end =begin --- Node#insertBefore(newChild, refChild) [DOM] insert newChild into the node before refChild. =end ## [DOM] def insertBefore(newChild, refChild) if @children.nil? || @children.length == 0 raise DOMException.new(DOMException::NOT_FOUND_ERR) end index = _getChildIndex(refChild) raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index _insertNodes(index, newChild) end =begin --- Node#replaceChild(newChild, oldChild) [DOM] replace the child node oldChild with newChild. =end ## [DOM] def replaceChild(newChild, oldChild) if @children.nil? || @children.length == 0 raise DOMException.new(DOMException::NOT_FOUND_ERR) end index = _getChildIndex(oldChild) raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index _removeNode(index, oldChild) _insertNodes(index, newChild) end =begin --- Node#removeChild(oldChild) [DOM] remove the children node oldChild. =end ## [DOM] def removeChild(oldChild) if @children.nil? || @children.length == 0 raise DOMException.new(DOMException::NOT_FOUND_ERR) end index = _getChildIndex(oldChild) raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index _removeNode(index, oldChild) oldChild end =begin --- Node#appendChild(newChild) [DOM] adds the node newChild to the end of the list of children of this node. =end ## [DOM] def appendChild(newChild) @children = NodeList.new if !@children _insertNodes(-1, newChild) end =begin --- Node#hasChildNodes() [DOM] returns true if node has children, or return false if node has no children. =end ## [DOM] def hasChildNodes !@children.nil? && @children.length > 0 end ## get the Node object by IDs ## [experimental implement] def _searchID(value, ids = nil) if ids.nil? doc = nil if nodeType == DOCUMENT_NODE doc = self elsif !ownerDocument.nil? doc = ownerDocument else return nil end ids = doc._getIDAttrs end if nodeType == ELEMENT_NODE && _getIDVals(ids).include?(value) return self elsif !@children.nil? @children.each do |node| if !(match = node._searchID(value, ids)).nil? return match end end end return nil end def _getMyLocation(parent) index = parent._getChildIndex(self) if !index.nil? "child(#{index + 1},#all)" else nil end end =begin --- Node#makeXPointer(use_id = true) return XPointer's expression of this node. =end def makeXPointer(use_id = true) if use_id && !attributes.nil? && !(idvals = _getIDVals).empty? "id(#{idvals[0]})" elsif @parent.nil? || @parent.nodeType == DOCUMENT_NODE "root()" else @parent.makeXPointer(use_id) + "." + self._getMyLocation(@parent) end end ## [Masaki Fukushima] def _child(reverse = false) return if @children.nil? @children.reversible_each(reverse) do |child| yield child end end ## [Masaki Fukushima] def _descendant(reverse = false) return if @children.nil? @children.reversible_each(reverse) do |child| yield child child._descendant(reverse) do |node| yield node end end end ## [Masaki Fukushima] def _ancestor(reverse = false) return if @parent.nil? yield @parent if !reverse @parent._ancestor(reverse) do |node| yield node end yield @parent if reverse end ## [Masaki Fukushima] def __sibling(reverse, only_appeared_before_self) return if @parent.nil? self_appeared = false @parent.childNodes.reversible_each(reverse) do |node| if node == self self_appeared = true next end if only_appeared_before_self break if self_appeared yield node else # only appeared after self yield node if self_appeared end end end ## [Masaki Fukushima] def _psibling(reverse = false) __sibling(!reverse, reverse) do |sib| yield sib end end ## [Masaki Fukushima] def _fsibling(reverse = false) __sibling(reverse, reverse) do |sib| yield sib end end ## [Masaki Fukushima] def _preceding(reverse = false) return if @parent.nil? prev_sib = previousSibling if prev_sib prev_sib._preceding(reverse) {|node| yield node} if reverse yield prev_sib prev_sib._descendant(!reverse) {|node| yield node} prev_sib._preceding(reverse) {|node| yield node} if !reverse else @parent._preceding(reverse) {|node| yield node} if reverse yield @parent @parent._preceding(reverse) {|node| yield node} if !reverse end end ## [Masaki Fukushima] def _following(reverse = false) return if @parent.nil? next_sib = nextSibling if next_sib next_sib._following(reverse) {|node| yield node} if reverse yield next_sib next_sib._descendant(reverse) {|node| yield node} next_sib._following(reverse) {|node| yield node} if !reverse else @parent._following(reverse) {|node| yield node} if reverse yield @parent @parent._following(reverse) {|node| yield node} if !reverse end end ## [Masaki Fukushima] def _matchAttribute?(attr, value) case value when '*' return !attr.nil? when '#IMPLIED' return attr.nil? else return false if attr.nil? end case value when /^"([^"]*)"$/, /^'([^']*)'$/ ignore_case = false value = $1 when Spec::Name ignore_case = true else raise "invalid attribute value: #{value}" end if ignore_case return attr.nodeValue.downcase == value.downcase else return attr.nodeValue == value end end ## [Masaki Fukushima] def _matchNodeAttributes?(node, attributes) return true if attributes.nil? raise TypeError if !attributes.is_a?(Hash) return true if attributes.length == 0 return false if node.nodeType != ELEMENT_NODE attributes.each do |name, value| case name when '*' return catch(:match) { node.attributes.each do |attr| throw(:match, true) if _matchAttribute?(attr, value) end false } when Spec::Name attr = node.attributes[name] unless node.attributes.nil? return _matchAttribute?(attr, value) else raise "invalid attribute name: '#{name}'" end end end ## [Masaki Fukushima] def _matchNodeType?(node, ntype) case ntype when '#element' return (node.nodeType == ELEMENT_NODE) when '#pi' return (node.nodeType == PROCESSING_INSTRUCTION_NODE) when '#comment' return (node.nodeType == COMMENT_NODE) when '#text' return (node.nodeType == TEXT_NODE || node.nodeType == CDATA_SECTION_NODE) when '#cdata' return (node.nodeType == CDATA_SECTION_NODE) when '#all' case node.nodeType when ELEMENT_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, TEXT_NODE, CDATA_SECTION_NODE return true else return false end when /^#/ raise "unknown node type: '#{ntype}'" when Spec::Name return (node.nodeType == ELEMENT_NODE && node.nodeName == ntype) else raise "invalid element type: '#{ntype}'" end end ## [Masaki Fukushima] def _matchNode?(node, ntype, attributes) _matchNodeType?(node, ntype) && _matchNodeAttributes?(node, attributes) end ## [Masaki Fukushima] def _nodesByRelativeLocationTerm(location) if location !~ /^([a-z]+)\(([^\)]*)\)$/ raise "invalid relative location: '#{location}'" end keyword = $1 args = $2.split(/,/) number = args.shift ntype = args.shift ntype = '#element' if ntype.nil? attributes = args reverse = false # check instance number case number when nil, '' raise "missing instance number: '#{location}'" when 'all' when Spec::Instance number = number.to_i if number < 0 reverse = true number = -number end else raise "unknown instance number: '#{number}'" end # check attributes if attributes.length % 2 != 0 raise " missing attribute value: '#{location}'" end attributes = Hash[*attributes] # iterate over nodes specified with keyword i = 0 self.send("_#{keyword}", reverse) do |node| next unless _matchNode?(node, ntype, attributes) if number == "all" yield node else i += 1 if i >= number yield node break end end end end ## [Masaki Fukushima] def _nodesByLocationTerms(location, pre_keyword = nil) if location !~ /^([a-z]*)\(([^)]*)\)(\.(.+))?$/ raise "invalid location: \"#{location}\"" end keyword = $1 args = $2 rest = $4 ## omitted keyword keyword = pre_keyword if keyword == '' if keyword.nil? raise "cannot determine preceding keyword: \"#{location}\"" end case keyword when 'child', 'descendant', 'ancestor', 'psibling', 'fsibling', 'preceding', 'following' # relative location term _nodesByRelativeLocationTerm("#{keyword}(#{args})") do |node| if rest.nil? yield node else node._nodesByLocationTerms(rest, keyword) do |n| yield n end end end when 'attr' # attribute location term if args !~ Spec::Name raise "invalid attribute name: '#{args}'" end attr = attributes[args] value = (attr.nil? ? nil : Text.new(attr.nodeValue)) if rest.nil? yield value elsif !value.nil? value._nodesByLocationTerms(rest) do |node| yield node end end when 'span', 'string' raise "unsupported keyword: '#{keyword}'" else raise "unknown keyword: '#{keyword}'" end end ## [Masaki Fukushima] def _getNodeByAbsoluteLocationTerm(location) case location when 'root()', '' if nodeType == DOCUMENT_NODE root = documentElement elsif !ownerDocument.nil? root = ownerDocument.documentElement end root = self if root.nil? return root when 'origin()' return self when /^id\(([^\)]*)\)$/ value = $1 raise "invalid id value: #{value}" if value !~ Spec::Name return _searchID(value) when /^html\(([^\)]*)\)$/ value = $1 return getNodesByXPointer("root().descendant(1,A,NAME,\"#{value}\")")[0] else raise "unknown keyword: #{location}" end end =begin --- Node#getNodeByXPointer(pointer) return node indicated by the XPointer pointer. =end ## [Masaki Fukushima] def getNodesByXPointer(pointer) if pointer !~ /^([a-z]+)\(([^)]*)\)(\.(.+))?$/ raise "invalid XPointer: \"#{pointer}\"" end keyword = $1 args = $2 rest = $4 case keyword when 'root', 'origin', 'id', 'html' src = _getNodeByAbsoluteLocationTerm("#{keyword}(#{args})") else src = _getNodeByAbsoluteLocationTerm("root()") rest = pointer end ret = NodeList.new if src.nil? # no match elsif rest.nil? yield src if iterator? ret << src else src._nodesByLocationTerms(rest) do |node| yield node if iterator? ret << node end end ret end =begin --- Node#ownerDocument() [DOM] Document object associated with this node. =end ## [DOM] ## Floating objects are not owned by any documents. def ownerDocument return @ownerDocument if @ownerDocument parent = self.parentNode return nil if parent.nil? if parent.nodeType == DOCUMENT_NODE return parent else return parent.ownerDocument end end def ownerDocument=(document); @ownerDocument = document; end =begin --- Node#cloneNode() [DOM] return the copy of the Node. =end ## [DOM] def cloneNode(deep = true, *args) ret = self.class.new(*args) if (deep) @children.each do |child| ret.appendChild(child.cloneNode(true)) end end if @children ret end =begin --- Node#trim(preserve = false) trim extra whitespaces. =end ## trim extra whitespaces ## if attribute 'xml:space' is 'preserve', ## don't trim any white spaces def trim(preserve = false) return nil if @children.nil? children = @children.to_a.dup children.each do |child| if !preserve && (child.nodeType == TEXT_NODE || child.nodeType == CDATA_SECTION_NODE) if child.trim == "" self.removeChild(child) end else child.trim(preserve) end end nil end end =begin == Class XML::DOM::NamedNodeMap =end class NamedNodeMap =begin === Class Methods --- NamedNodeMap.new(nodes = nil) creates a new NamedNodeMap. =end def initialize(nodes = nil) @nodes = {} nodes.each do |node| @nodes[node.nodeName] = node end if nodes end =begin === Methods --- NamedNodeMap#getNamedItem(name) [DOM] retrieves a node specified by name. =end ## [DOM] def getNamedItem(name) @nodes[name] end =begin --- NamedNodeMap#setNamedItem(node) [DOM] adds a node using its nodeName attribute. =end ## [DOM] def setNamedItem(node) @nodes[node.nodeName] = node end =begin --- NamedNodeMap#removeNamedItem(name) [DOM] removes a node specified by name. =end ## [DOM] def removeNamedItem(name) ret = @nodes[name] @nodes[name] = nil ret end =begin --- NamedNodeMap#item(index) [DOM] returns the index item in the map. =end ## [DOM] def item(index) v = @nodes.to_a[index] return v[1] if v nil end =begin --- NamedNodeMap#[](name) returns nodes associated to name. =end def [](name) @nodes[name] end =begin --- NamedNodeMap#[]=(name, node) sets node named name. =end def []=(name, node) raise "parameter error" if node.nodeName != name @nodes[name] = node end =begin --- NamedNodeMap#each() iterates over each pair of name and node(name, node) of the namedNodeMap. =end def each @nodes.each do |key, value| yield(value) end end =begin --- NamedNodeMap#size() [DOM] returns the number of nodes in the map. =end ## [DOM] def size @nodes.length end alias length size ## get nodeValues by names ## names ::= name ('|' name)* def _getValues(names) ret = [] names.split('|').each do |name| if !@nodes[name].nil? ret.push(@nodes[name].nodeValue) end end ret end end =begin == Class XML::DOM::NodeList =end class NodeList =begin === Class Methods --- NodeList.new(nodes = nil) creates a new NodeList. =end def initialize(nodes = nil) if nodes.nil? @nodes = [] elsif nodes.is_a?(Array) @nodes = nodes else raise "parameter error" end end =begin === Methods --- NodeList#item(index) [DOM] return the indexth item in the NodeList. =end ## [DOM] def item(index) @nodes[index] end =begin --- NodeList#size() return size of NodeList. =end def size @nodes.length end alias length size =begin --- NodeList#[](index) return indexth node of the NodeList. =end def [](index) @nodes[index] end =begin --- NodeList#[]=(*p) set node of indexth node of the NodeList. =end def []=(*p) if p.length == 2 @nodes[p[0]] = p[1] elsif p.length == 3 @nodes[p[0], p[1]] = p[2] end end =begin --- NodeList#each iterates over each node of the NodeList. =end def each @nodes.each do |value| yield(value) end end =begin --- NodeList#reversible_each(reverse = false) iterates over each node of the reversed NodeList. =end ## [Masaki Fukushima] def reversible_each(reverse = false) if !reverse @nodes.each do |value| yield(value) end else @nodes.reverse_each do |value| yield(value) end end end =begin --- NodeList#push(*nodes) adds nodes into the NodeList. =end def push(*nodes) nodes.each do |node| if node.is_a?(Array) self.push(*node) elsif node.is_a?(NodeList) @nodes.concat(node.to_a) elsif node.is_a?(Node) @nodes << node else raise "parameter error" end end self end =begin --- NodeList#concat(*nodes) alias of NodeList#push. =end alias concat push =begin --- NodeList#pop pops and returns the last node of the NodeList. =end def pop @nodes.pop end =begin --- NodeList#shift removes and returns the first node of the NodeList. =end def shift @nodes.shift end =begin --- NodeList#to_s returns the string representation of the NodeList. =end def to_s @nodes.to_s end =begin --- NodeList#reverse returns the reversed NodeList. =end def reverse @nodes.reverse end =begin --- NodeList#to_a converts the NodeList into an array. =end def to_a @nodes end =begin --- NodeList#+(nodes) return the newly created concatenated NodeList. =end def +(nodes) if nodes.nil? NodeList.new(@nodes) elsif nodes.is_a?(Array) NodeList.new(@nodes + nodes) elsif nodes.is_a?(NodeList) NodeList.new(@nodes + nodes.to_a) elsif nodes.is_a?(Node) NodeList.new(@nodes + [nodes]) else raise "parameter error" end end =begin --- NodeList#<<(nodes) appends nodes to the NodeList. =end ## modified by Masaki Fukushima def <<(nodes) if nodes.nil? ## no change elsif nodes.is_a?(Array) @nodes.concat(nodes) elsif nodes.is_a?(NodeList) @nodes.concat(nodes.to_a) elsif nodes.is_a?(Node) @nodes << nodes else raise "parameter error" end self end ## get nodeValues by names ## names ::= name ('|' name)* def _getValues(names) ret = [] names.split('|').each do |name| if !@nodes[name].nil? ret.push(@nodes[name].nodeValue) end end ret end end =begin == Class XML::DOM::DocumentFragment === superclass Node =end class DocumentFragment'id'} if @idattrs.nil? @idattrs end ## [DOM] def implementation return @implemantation if @implemantation ## singleton @implemantation = DOMImplementation.instance end def implementation=(impl) @implemantation = impl end def _checkNode(node) unless node.nodeType == ELEMENT_NODE || node.nodeType == PROCESSING_INSTRUCTION_NODE || node.nodeType == COMMENT_NODE || node.nodeType == DOCUMENT_TYPE_NODE raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR) end if node.nodeType == ELEMENT_NODE @children.each do |n| if n.nodeType == ELEMENT_NODE raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR) end end end if node.nodeType == DOCUMENT_TYPE_NODE @children.each do |n| if n.nodeType == DOCUMENT_TYPE_NODE raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR) end end end end end =begin == Class XML::DOM::Attr === superclass Node =end class Attr @value.length || count < 0 raise DOMException.new(DOMException::INDEX_SIZE_ERR) end ## if the sum of start and count > length, ## return all characters to the end of the value. @value[start, count] end =begin --- CharacterData#appendData(str) [DOM] append the string to the end of the character data. =end ## [DOM] def appendData(str) @value << str end =begin --- CharacterData#insertData(offset, str) [DOM] insert a string at the specified character offset. =end ## [DOM] def insertData(offset, str) if offset < 0 || offset > @value.length raise DOMException.new(DOMException::INDEX_SIZE_ERR) end @value[offset, 0] = str end =begin --- CharacterData#deleteData(offset, count) [DOM] removes a range of characters from the node. =end ## [DOM] def deleteData(offset, count) if offset < 0 || offset > @value.length || count < 0 raise DOMException.new(DOMException::INDEX_SIZE_ERR) end @value[offset, count] = '' end =begin --- CharacterData#replaceData(offset, count, str) [DOM] replaces the characters starting at the specified character offset with specified string. =end ## [DOM] def replaceData(offset, count, str) if offset < 0 || offset > @value.length || count < 0 raise DOMException.new(DOMException::INDEX_SIZE_ERR) end @value[offset, count] = str end =begin --- CharacterData#cloneData(deep = true) [DOM] returns the copy of the CharacterData. =end ## [DOM] def cloneNode(deep = true) super(deep, @value.dup) end =begin --- Text#nodeValue [DOM] return nodevalue. =end ## [DOM] def nodeValue @value end =begin --- CharacterData#nodeValue=(p) [DOM] set nodevalue as p. =end ## [DOM] def nodeValue=(p) @value = p end end =begin == Class XML::DOM::Text === superclass Node =end class Text ret << ">" else ret << code end end ret end =begin --- Text#dump(depth = 0) dumps the Text. =end def dump(depth = 0) print ' ' * depth * 2 print "#{@value.inspect}\n" end def _getMyLocation(parent) index = 1 parent.childNodes do |child| if child == self return "child(#{index},#text)" end if child.nodeType == TEXT_NODE index += 1 end end nil end =begin --- Text#splitText(offset) [DOM] breaks this Text node into two Text nodes at the specified offset. =end ## [DOM] def splitText(offset) if offset > @value.length || offset < 0 raise DOMException.new(DOMException::INDEX_SIZE_ERR) end newText = @value[offset, @value.length] newNode = Text.new(newText) if !self.parentNode.nil? self.parentNode.insertAfter(newNode, self) end @value[offset, @value.length] = "" newNode end =begin --- Text#trim(preserve = false) trim extra whitespaces. =end def trim(preserve = false) if !preserve @value.sub!(/\A\s*([\s\S]*?)\s*\Z/, "\\1") return @value end nil end end =begin == Class XML::DOM::Comment === superclass CharacterData =end class Comment\n" end def _getMyLocation(parent) index = 1 parent.childNodes do |child| if child == self return "child(#{index},#comment)" end if child.nodeType == COMMENT_NODE index += 1 end end nil end end ## Extended Interfaces =begin == Class XML::DOM::CDATASection === superclass Text =end class CDATASection" end =begin --- CDATASection#dump(depth = 0) dumps the CDATASection. =end def dump(depth = 0) print ' ' * depth * 2 print "\n" end def _getMyLocation(parent) index = 1 parent.childNodes do |child| if child == self return "child(#{index},#cdata)" end if child.nodeType == CDATA_SECTION_NODE index += 1 end end nil end end =begin == Class XML::DOM::DocumentType === superclass Node =end class DocumentType 0 ret <<= " [\n" @children.each do |child| if child.nodeType == PROCESSING_INSTRUCTION_NODE || child.nodeType == COMMENT_NODE ret <<= child.to_s + "\n" else ret <<= child.nodeValue + "\n" end end ret <<= "]" end ret <<= ">" end =begin --- DocumentType#dump(depth = 0) dumps the DocumentType. =end def dump(depth = 0) print ' ' * depth * 2 print "\n" end =begin --- DocumentType#cloneNode(deep = true) [DOM] returns the copy of the DocumentType. =end ## [DOM] def cloneNode(deep = true) super(deep, @name, @value) end ## [DOM] ## def entities; @entities; end ## def notations; @notations; end end =begin == Class XML::DOM::Notation === superclass Node =end class Notation\n" end def _getMyLocation(parent) index = 1 parent.childNodes do |child| if child == self return "child(#{index},#pi)" end if child.nodeType == PROCESSING_INSTRUCTION_NODE index += 1 end end nil end =begin --- ProcessingInstruction#cloneNode(deep = true) [DOM] returns the copy of the ProcessingInstruction. =end ## [DOM] def cloneNode(deep = true) super(deep, @target.dup, @data.dup) end end end SimpleTree = DOM end xmlparser/lib/xml/dom/builder.rb0000644000076400007640000001717107633552741017442 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM::Builder ## 1999 by yoshidam require 'xml/parser' require 'xml/dom/core' =begin = XML::DOM::Builder == Module XML =end module XML module DOM =begin == Class XML::DOM::Builder (XML::SimpleTreeBuilder) === superclass XML::Parser =end class Builder 0 @createCDATASection = true @createEntityReference = true def self.default(data); defaultHandler(data); end end end =begin === Methods --- Builder#nameConverter(str) User redefinable name encoding converter =end ## User redefinable name encoding converter def nameConverter(str) str end =begin --- Builder#cdataConverter(str) User redefinable cdata encoding converter =end ## User redefinable cdata encoding converter def cdataConverter(str) str end =begin === Methods --- Builder#parse(xml, parse_ext = false) parse string or stream of XML contents. xml: string or stream of XML contents parse_ext: flag whether parse external entities or not ex. doctree = parser.parse(xml, parse_ext) =end ## Parse ## doctree = parser.parse(xml, parse_ext) ## xml: string or stream of XML contents ## parse_ext: flag whether parse external entities or not def parse(xml, parse_ext = false) if @external @tree = @document.createDocumentFragment else @tree = @document end @parse_ext = parse_ext @current = @tree @inDocDecl = 0 @decl = "" @inDecl = 0 @idRest = 0 @extID = nil @cdata_f = false @cdata_buf = '' super(xml) @tree end def text return if @cdata_buf == '' textnode = @document.createTextNode(cdataConverter(@cdata_buf)) @current.appendChild(textnode) @cdata_buf = '' end def startElement(name, data) text elem = @document.createElement(nameConverter(name)) data.each do |key, value| attr = @document.createAttribute(nameConverter(key)) attr.appendChild(@document.createTextNode(cdataConverter(value))) elem.setAttributeNode(attr) end @current.appendChild(elem) @current = elem end def endElement(name) text @current = @current.parentNode end def character(data) @cdata_buf << data end def processingInstruction(name, data) text pi = @document.createProcessingInstruction(nameConverter(name), cdataConverter(data)) ## PI data should not be converted @current.appendChild(pi) end def externalEntityRef(context, base, systemId, publicId) text tree = nil if @parse_ext extp = self.class.new(@level, self, context) extp.setBase(base) if base file = systemId if systemId !~ /^\/|^\.|^http:|^ftp:/ && !base.nil? file = base + systemId end begin tree = extp.parse(open(file).read, @parse_ext) rescue XML::ParserError raise XML::ParserError.new("#{systemId}(#{extp.line}): #{$!}") rescue Errno::ENOENT raise Errno::ENOENT.new("#{$!}") end extp.done end if @createEntityReference entref = @document.createEntityReference(nameConverter(context)) @current.appendChild(entref) entref.appendChild(tree) if tree else @current.appendChild(tree) if tree end end def startCdata return unless @createCDATASection text @cdata_f = true end def endCdata return unless @createCDATASection cdata = @document.createCDATASection(cdataConverter(@cdata_buf)) @current.appendChild(cdata) @cdata_buf = '' @cdata_f = false end def comment(data) text comment = @document.createComment(cdataConverter(data)) ## Comment should not be converted @current.appendChild(comment) end def defaultHandler(data) if data =~ /^\&(.+);$/ eref = @document.createEntityReference(nameConverter($1)) @current.appendChild(eref) elsif data =~ /^<\?xml\s*([\s\S]*)\?>$/ ## XML declaration should not be a PI. pi = @document.createProcessingInstruction("xml", cdataConverter($1)) @current.appendChild(pi) elsif @inDocDecl == 0 && data =~ /^<\!DOCTYPE$/ @inDocDecl = 1 @inDecl = 0 @idRest = 0 @extID = nil elsif @inDocDecl == 1 if data == "[" @inDocDecl = 2 elsif data == ">" if !@extID.nil? ## @current.nodeValue = @extID end @inDocDecl = 0 ## @current = @current.parentNode elsif data == "SYSTEM" @idRest = 1 @extID = data elsif data == "PUBLIC" @idRest = 2 @extID = data elsif data !~ /^\s+$/ if @idRest > 0 ## SysID or PubID @extID <<= " " + data @idRest -= 1 else ## Root Element Type docType = data ## doctype = DocumentType.new(nameConverter(docType)) ## @current.appendChild(doctype) ## @current = doctype end end elsif @inDocDecl == 2 if @inDecl == 0 if data == "]" @inDocDecl = 1 elsif data =~ /^<\!/ @decl = data @inDecl = 1 elsif data =~ /^%(.+);$/ ## PERef ## cdata = @document.createTextNode(nameConverter(data)) ## @current.appendChild(cdata) else ## WHITESPCAE end else ## inDecl == 1 if data == ">" @decl <<= data @inDecl = 0 ## Markup Decl ## cdata = @document.createTextNode(cdataConverter(@decl)) ## Markup decl should not be converted ## @current.appendChild(cdata) elsif data =~ /^\s+$/ ## WHITESPACE @decl << " " else @decl << data end end else ## maybe WHITESPACE ## cdata = @document.createTextNode(cdataConverter(data)) ## @current.appendChild(cdata) end end end end SimpleTreeBuilder = DOM::Builder end xmlparser/lib/xml/dom/visitor.rb0000644000076400007640000000664607633552741017520 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM::Visitor ## 1998 by yoshidam ## ## Oct 23, 1998 yoshidam Fix each ## =begin = XML::DOM::Visitor == Module XML =end module XML =begin == Module XML::DOM (XML::SimpleTree) =end module DOM =begin == Class XML::DOM::Visitor Skelton class of Visitor. You can override the following methods and implement the other "visit_TYPE" methods. You should implement some "visit_name_NAME" methods and "method_missing" method for accept_name. =end ## Skeleton visitor class Visitor ## You can override the following methods and implement the other ## "visit_TYPE" methods. ## You should implement some "visit_name_NAME" methods and ## "method_missing" method for accept_name. =begin === Methods --- Visitor#visit_Document(grove, *rest) callback method. =end def visit_Document(grove, *rest) grove.children_accept(self, *rest) end =begin --- Visitor#visit_Element(element, *rest) callback method. =end def visit_Element(element, *rest) element.children_accept(self, *rest) end =begin --- Visitor#visit_Text(text, *rest) callback method. =end def visit_Text(text, *rest) end =begin --- Visitor#visit_CDATASection(text, *rest) callback method. =end def visit_CDATASection(text, *rest) end =begin --- Visitor#visit_Comment(comment, *rest) callback method. =end def visit_Comment(comment, *rest) end =begin --- Visitor#visit_ProcessingInstruction(pi, *rest) callback method. =end def visit_ProcessingInstruction(pi, *rest) end end =begin == Class XML::DOM::Node XML::Grove::Visitor like interfaces. =end class Node =begin --- Node#accept(visitor, *rest) call back visit_* method. =end ## XML::Grove::Visitor like interfaces def accept(visitor, *rest) typename = self.class.to_s.sub(/.*?([^:]+)$/, '\1') visitor.send("visit_" + typename, self, *rest) end =begin --- Node#accept_name(visitor, *rest) call back visit_name_* method. =end def accept_name(visitor, *rest) if nodeType == ELEMENT_NODE name_method = "visit_name_" + nodeName visitor.send(name_method, self, *rest) else self.accept(visitor, *rest) end end =begin --- Node#children_accept(visitor, *rest) for each children, call back visit_* methods. =end def children_accept(visitor, *rest) ret = [] @children && @children.each { |node| ret.push(node.accept(visitor, *rest)) } ret end =begin --- Node#children_accept_name(visitor, *rest) for each children, call back visit_name_* method. =end def children_accept_name(visitor, *rest) ret = [] @children && @children.each { |node| ret.push(node.accept_name(visitor, *rest)) } ret end =begin --- Node#each iterator interface. =end ## Iterator interface include Enumerable def each sibstack = [] siblings = [ self ] while true if siblings.length == 0 break if sibstack.length == 0 siblings = sibstack.pop next end node = siblings.shift yield(node) children = node.childNodes if !children.nil? sibstack.push(siblings) siblings = children.to_a.dup end end end end end end xmlparser/lib/xml/dom/digest.rb0000644000076400007640000000566211503775412017266 0ustar yoshidamyoshidam## -*- Ruby -*- ## DOMHASH test implementation ## 1999 by yoshidam ## ## Apr 20, 1999 Change for draft-hiroshi-dom-hash-01.txt ## require 'xml/dom/core' require 'digest/md5' module XML module DOM def self.tou16(str) if defined?(::Encoding) str.encode(::Encoding::UTF_16BE).force_encoding(::Encoding::ASCII_8BIT) else str.unpack("U*").map {|v| if v >= 0x10000 && v <= 0x10ffff ## surrogate pair hi = ((v - 0x10000) >> 10) | 0xd800 low = (v & 1023) | 0xdc00 [hi, low].pack("n*") else [v].pack("n*") end }.join end end class Node def getDigest(algorithm = Digest::MD5, force = false) nil end end class Text def getDigest(algorithm = Digest::MD5, force = false) (!force && @digest) || @digest = algorithm.digest([TEXT_NODE].pack("N") + DOM.tou16(nodeValue)) @digest end end ## class Comment ## def getDigest(algorithm = Digest::MD5, force = false) ## (!force && @digest) || ## @digest = algorithm.digest([COMMENT_NODE].pack("N") + DOM.tou16(data)).digest ## end ## end class ProcessingInstruction def getDigest(algorithm = Digest::MD5, force = false) (!force && @digest) || @digest = algorithm.digest([PROCESSING_INSTRUCTION_NODE].pack("N") + DOM.tou16(target) + "\0\0" + DOM.tou16(data)) end end class Attr def getDigest(algorithm = Digest::MD5, force = false) (!force && @digest) || @digest = algorithm.digest([ATTRIBUTE_NODE].pack("N") + DOM.tou16(nodeName) + "\0\0" + DOM.tou16(nodeValue)) end end class NamedNodeMap include Enumerable end class NodeList include Enumerable end class Element def getDigest(algorithm = Digest::MD5, force = false) return @digest if (!force && @digest) attr = attributes children = childNodes attr_digests = "" children_digests = "" if attr attr_array = attr.sort {|a, b| DOM.tou16(a.nodeName) <=> DOM.tou16(b.nodeName)} attr_array.each {|a| attr_digests << a.getDigest(algorithm, force) } end children_num = 0 children.each {|c| next if c.nodeType == COMMENT_NODE children_num += 1 children_digests << c.getDigest(algorithm, force) } @digest = algorithm.digest([ELEMENT_NODE].pack("N") + DOM.tou16(nodeName) + "\0\0" + [attr.length].pack("N") + attr_digests + [children_num].pack("N") + children_digests) end end end end xmlparser/lib/xml/sax.rb0000644000076400007640000001642207633552735016031 0ustar yoshidamyoshidam## -*- Ruby -*- ## SAX (Simple API for XML) 1.0 for Ruby (experimental) ## 1999 by yoshidam ## ## SAX information: http://www.megginson.com/SAX/ ## module XML module SAX module AttributeList def getLength raise "not implemented" end def getName(pos) raise "not implemented" end def getType(pos_or_name) raise "not implemented" end def getValue(pos_or_name) raise "not implemented" end end module DTDHandler def notationDecl(name, pubid, sysid) raise "not implemented" end def unparsedEntityDecl(name, pubid, sysid, notation) raise "not implemented" end end module DocumentHandler def setDocumentLocator(locator) raise "not implemented" end def startDocument raise "not implemented" end def endDocument() raise "not implemented" end def startElement(name, atts) raise "not implemented" end def endElement(name) raise "not implemented" end def characters(ch, start, length) raise "not implemented" end def ignorableWhitespace(ch, start, length) raise "not implemented" end def processingInstruction(target, data) raise "not implemented" end end module EntityResolver def resolveEntity(pubid, sysid) raise "not implemented" end end module ErrorHandler def warning(e) raise "not implemented" end def error(e) raise "not implemented" end def fatalError(e) raise "not implemented" end end module Locator def getPublicId raise "not implemented" end def getSystemId raise "not implemented" end def getLineNumber raise "not implemented" end def getColumnNumber raise "not implemented" end end module Parser def setLocale(locale) raise "not implemented" end def setEntityResolver(resolver) raise "not implemented" end def setDTDHandler(handler) raise "not implemented" end def setDocumentHandler(handler) raise "not implemented" end def setErrorHandler raise "not implemented" end def parse(source_or_sysid) raise "not implemented" end end class HandlerBase include EntityResolver include DTDHandler include DocumentHandler include ErrorHandler def resolveEntity(pubid, sysid) nil end def notationDecl(name, pubid, sysid) end def unparsedEntityDecl(name, pubid, sysid, natation) end def setDocumentLocator(locator) end def startDocument end def endDocument end def startElement(name, atts) end def endElement(name) end def characters(ch, start, length) end def ignorableWhitespace(ch, sart, length) end def processingInstruction(target, data) end def warning(e) end def error(e) end def fatalError(e) raise e end end class InputSource def initialize(sysid) @publicId = nil @systemId = nil @stream = nil @encoding = nil if sysid.kind_of?(String) setSystemId(sysid) elsif !sysid.nil? setByteStream(sysid) end end def setPublicId(pubid) @publicId = pubid end def getPublicId @publicId end def setSystemId(sysid) @systemId = sysid end def getSystemId @systemId end def setByteStream(stream) @stream = stream end def getByteStream @stream end def setEncoding(encoding) @encoding = encoding end def getEncoding @encoding end def setCharacterStream(stream) raise "not implemented" end def getCharacterStream raise "not implemented" end end class SAXException < Exception ## initialize(String) ## initialize(Exception) ## initialize(String, Exception) def initialize(message, e = nil) @message = nil @exception = nil if message.kind_of?(String) && e.nil? @message = message elsif message.kind_of?(Exception) && e.nil? @exception = e elsif message.kind_of?(String) && e.kind_of?(Exception) @message = message @exception = e else raise TypeError.new("parameter error") end end def getMessage if @message.nil? && !@exception.nil? return @exception.to_s end @message end def getException @exception end def toString getMessage end alias to_s toString end class SAXParseException < SAXException ## initialize(String, Locator) ## initialize(String, Locator, Exception) ## initialize(String, String, String, Fixnum, Fixnum) ## initialize(String, String, String, Fixnum, Fixnum, Exception) def initialize(message, pubid = nil, sysid = nil, line = nil, column = nil, e = nil) @publicId = nil @systemiId = nil @lineNumber = nil @columnNumber = nil if message.kind_of?(String) && pubid.kind_of?(Locator) && sysid.nil? && line.nil? && column.nil? && e.nil? super(message) @publicId = pubid.getPublicId @systemId = pubid.getSystemId @lineNumber = pubid.getLineNumber @columnNumber = pubid.getColumnNumber elsif message.kind_of?(String) && pubid.kind_of?(Locator) && sysid.kind_of?(Exception) && line.nil? && column.nil? && e.nil? super(message, sysid) @publicId = pubid.getPublicId @systemId = pubid.getSystemId @lineNumber = pubid.getLineNumber @columnNumber = pubid.getColumnNumber elsif message.kind_of?(String) && pubid.kind_of?(String) && sysid.kind_of?(String) && line.kind_of?(Fixnum) && column.kind_of?(Fixnum) && e.nil? super(message) @publicId = pubid @systemId = sysid @lineNumber = line @columnNumber = column elsif message.kind_of?(String) && pubid.kind_of?(String) && sysid.kind_of?(String) && line.kind_of?(Fixnum) && column.kind_of?(Fixnum) && e.kind_of?(Exception) super(message, e) @publicId = pubid @systemId = sysid @lineNumber = line @columnNumber = column else raise TypeError.new("parameter error") end end def getPublicId @publicId end def getSystemId @systemId end def getLineNumber @lineNumber end def getColumnNumber @columnNumber end end module Helpers module ParserFactory def ParserFactory::makeParser(klass) if klass.kind_of?(Class) klass.new elsif klass.kind_of?(String) eval(klass).new end end end end end end xmlparser/lib/xml/saxdriver.rb0000644000076400007640000002322710614367202017230 0ustar yoshidamyoshidam## -*- Ruby -*- ## SAX Driver for XML::Parser (experimental) ## 1999 by yoshidam ## ## Limitation: ## * AttributeList#getType always returns 'CDATA'. ## * DocumentHandler#ignorableWhitespace is never called. ## * ErrorHandler#warning and ErrorHandler#error are never called. ## * Locator#getLineNumber and Locator#getColumnNumber do not ## return the proper value in DocumentHandler#characters method. ## * Parser#setLocale is not implemented. ## * Parser cannot parse non-local file. require 'xml/parser' require 'xml/sax' module XML class Parser class SAXDriver include XML::SAX::Parser include XML::SAX::AttributeList include XML::SAX::Locator ## very simple URL parser class URL attr :scheme attr :login attr :urlpath def initialize(url, url2 = nil) @scheme = '' @login = '' @urlpath = '' if url.kind_of?(String) && url2.nil? if url =~ /^([a-z0-9\+\-\.]+):\/\/([^\/]+)(\/.*)$/ @scheme, @login, @urlpath = $1, $2, $3 else url = File::expand_path(url) @scheme, @login, @urlpath = "file", "localhost", url end elsif url.kind_of?(URL) && url2.kind_of?(String) if url2 =~ /^([a-z0-9\+\-\.]+):\/\/([^\/]+)(\/.*)$/ @scheme, @login, @urlpath = $1, $2, $3 else @scheme = url.scheme @login = url.login if url2 =~ /^\// @urlpath = url2 else path = url.urlpath path =~ /^([^\#]+)\#?(.*)$/ path = $1 path =~ /^([^\?]+)\??(.*)$/ path = $1 path =~ /^(.+)\/(.*)/ path = $1 @urlpath = File.expand_path(path + '/' + url2) end end end end def to_s @scheme + "://" + @login + @urlpath end end ## All parser events are delegated to SAXDriver class SAXParser < XML::Parser include XML::SAX::Locator def SAXParser.new(saxdriver, *rest) obj = super(*rest) obj.setDriver(saxdriver) obj end def initialize(*args) super(*args) @publicId = nil @systemId = nil if self.respond_to?(:setParamEntityParsing) self.setParamEntityParsing(PARAM_ENTITY_PARSING_UNLESS_STANDALONE) end end def setDriver(saxdriver) @saxdriver = saxdriver end def parse(inputSource) @systemId = inputSource.getSystemId @saxdriver.pushLocator(self) setBase(@systemId) super(inputSource.getByteStream.read) @saxdriver.popLocator end def getPublicId @publicId end def getSystemId @systemId end def getLineNumber self.line end def getColumnNumber self.column end def startElement(name, attr) @saxdriver.startElement(name, attr) end def endElement(name) @saxdriver.endElement(name) end def character(data) @saxdriver.character(data) end def processingInstruction(target, data) @saxdriver.processingInstruction(target, data) end def notationDecl(name, base, sysid, pubid) @saxdriver.notationDecl(name, base, sysid, pubid) end def unparsedEntityDecl(name, base, sysid, pubid, notation) @saxdriver.unparsedEntityDecl(name, base, sysid, pubid, notation) end def comment(data) end def externalEntityRef(context, base, systemId, publicId) inputSource = @saxdriver.xmlOpen(base, systemId, publicId) encoding = inputSource.getEncoding if encoding parser = SAXParser.new(@saxdriver, self, context, encoding) else parser = SAXParser.new(@saxdriver, self, context) end parser.parse(inputSource) parser.done end end class DummyLocator include XML::SAX::Locator def initialize(systemId) @systemId = systemId end def getPublicId; nil end def getSystemId; @systemId end def getLineNumber; 1 end def getColumnNumber; 1 end end ## open stream if it is not opened def openInputStream(stream) if stream.getByteStream return stream else stream.getSystemId url = URL.new(stream.getSystemId) if url.scheme == 'file' && url.login == 'localhost' s = open(url.urlpath) stream.setByteStream(s) return stream end end return nil end private :openInputStream def xmlOpen(base, systemId, publicId) if base.nil? || base == "" file = URL.new(systemId) else file = URL.new(URL.new(base), systemId) end if !@entityResolver.nil? stream = @entityResolver.resolveEntity(file.to_s, publicId) return openInputStream(stream) if stream end if file.scheme == 'file' && file.login == 'localhost' stream = open(file.urlpath) is = XML::SAX::InputSource.new(stream) is.setSystemId(file.to_s) is.setPublicId(publicId) return is end end def initialize handler = XML::SAX::HandlerBase.new @attributes = nil @documentHandler = handler @dtdHandler = handler @errorHandler = handler @entityResolver = handler @dataBuf = '' @locators = [] end ## implementation of Parser def setEntityResolver(handler) if !handler.kind_of?(XML::SAX::EntityResolver) raise TypeError.new("parameter error") end @entityResolver = handler end ## implementation of Parser def setDocumentHandler(handler) if !handler.kind_of?(XML::SAX::DocumentHandler) raise TypeError.new("parameter error") end @documentHandler = handler end ## implementation of Parser def setDTDHandler(handler) if !handler.kind_of?(XML::SAX::DTDHandler) raise TypeError.new("parameter error") end @dtdHandler = handler end ## implementation of Parser def setErrorHandler(handler) if !handler.kind_of?(XML::SAX::ErrorHandler) raise TypeError.new("parameter error") end @errorHandler = handler end ## implementation of Parser def setLocale(locale) raise SAXException.new("locale not supported") end def flushData if @dataBuf.length > 0 @documentHandler.characters(@dataBuf, 0, @dataBuf.length) @dataBuf = '' end end private :flushData def startElement(name, attrs) flushData; @attributes = attrs @documentHandler.startElement(name, self) end def character(data) @dataBuf << data end def endElement(name) flushData; @documentHandler.endElement(name) end def processingInstruction(target, data) flushData; @documentHandler.processingInstruction(target, data) end def notationDecl(name, base, sysid, pubid) @dtdHandler.notationDecl(name, pubid, sysid) end def unparsedEntityDecl(name, base, sysid, pubid, notation) @dtdHandler.unparsedEntityDecl(name, pubid, sysid, notation) end ## implementation of AttributeList def getLength @attributes.length end ## implementation of AttributeList def getName(pos) @attributes.keys[pos] end ## implementation of AttributeList def getValue(pos) if pos.kind_of?(String) @attributes[pos] else @attributes.values[pos] end end ## implementation of AttributeList def getType(pos) ## expat cannot get attribyte type return "CDATA" end ## locator is DummyLoacator or SAXParser def pushLocator(locator) @locators.push(locator) end def popLocator @locators.pop end ## implementation of Locator def getPublicId @locators[-1].getPublicId end ## implementation of Locator def getSystemId @locators[-1].getSystemId end ## implementation of Locator def getLineNumber @locators[-1].getLineNumber end ## implementation of Locator def getColumnNumber @locators[-1].getColumnNumber end ## implementation of Parser def parse(sysid) @documentHandler.setDocumentLocator(self) if sysid.kind_of?(XML::SAX::InputSource) inputSource = openInputStream(sysid.dup) else inputSource = openInputStream(XML::SAX::InputSource.new(sysid)) end encoding = inputSource.getEncoding if encoding parser = SAXParser.new(self, encoding) else parser = SAXParser.new(self) end pushLocator(DummyLocator.new(inputSource.getSystemId)) begin @documentHandler.startDocument parser.parse(inputSource) @documentHandler.endDocument rescue XML::Parser::Error @errorHandler.fatalError(XML::SAX::SAXParseException.new($!.to_s, self)) rescue @errorHandler.fatalError($!) end end end end end xmlparser/lib/xml/parser.rb0000644000076400007640000000032507633545642016524 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::Parser (alias of XMLParser) ## 1998 by yoshidam require 'xmlparser.so' #module XML # Parser = XMLParser # class Parser # Error = XMLParserError # end # Encoding = XMLEncoding #end xmlparser/lib/xml/dom2/document.rb0000644000076400007640000001442207633546105017705 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/node' require 'xml/dom2/nodelist' require 'xml/dom2/domexception' require 'xml/dom2/documentfragment' require 'xml/dom2/attr' require 'xml/dom2/element' require 'xml/dom2/text' require 'xml/dom2/comment' require 'xml/dom2/cdatasection' require 'xml/dom2/entityreference' require 'xml/dom2/processinginstruction' require 'xml/dom2/domimplementation' module XML module DOM =begin == Class XML::DOM::Document === superclass Node =end class Document nil } end end end end xmlparser/lib/xml/dom2/node.rb0000644000076400007640000002712007662567675017034 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/domexception' require 'xml/dom2/nodelist' module XML module DOM =begin == Class XML::DOM::Node =end class Node ## [DOM] NODE_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 ## non-DOM # NODE = 0 # ELEMENT = 1 # ATTRIBUTE = 2 # TEXT = 3 # CDATA_SECTION = 4 # ENTITY_REFERENCE = 5 # ENTITY = 6 # PI = 7 # PROCESSING_INSTRUCTION = 7 # COMMENT = 8 # DOCUMENT = 9 # DOCUMENT_TYPE = 10 # DOCUMENT_FRAGMENT = 11 # NOTATION = 12 =begin === Class Methods --- Node.new(*children) make a Node. children is a Array of child, or sequence of child. child is a String or Node. =end ## new([child1, child2, ...]) or ## new(child1, child2, ...) ## child?: String or Node def initialize(*children) @ownerDocument = nil @parent = nil @children = nil self.childNodes = children if children.length > 0 end =begin === Methods --- Node#parentNode [DOM] return parent node. =end ## [DOM] def parentNode @parent end =begin --- Node#parentNode=(p) set node p as parent. =end def parentNode=(p) @parent = p end =begin --- Node#nodeType [DOM] return nodetype. =end ## [DOM] def nodeType NODE_NODE end =begin --- Node#nodeName [DOM] return nodename. =end ## [DOM] def nodeName "#node" end # def nodeName=(p) # @name = p # end =begin --- Node#nodeValue [DOM] return nodevalue. =end ## [DOM] def nodeValue; nil; end =begin --- Node#nodeValue=(p) [DOM] set nodevalue as p. =end ## [DOM] def nodeValue=(p) ## no effect end =begin --- Node#childNodes() [DOM] if method has block, apply block for children nodes. without block, return children nodelist. =end ## [DOM] def childNodes if iterator? @children.each do |child| yield(child) end if @children else return @children if !@children.nil? @children = NodeList.new end end def childNodes=(p) if p.nil? || (p.is_a?(Array) && p.length == 0) return end if @children.nil? @children = NodeList.new else @children.to_a.clear end p.flatten! p.each do |child| if child.is_a?(String) c = Text.new(child) @children.push(c) c.parentNode = self elsif child.is_a?(Node) @children.push(child) child.parentNode = self else raise "parameter error" end end if p end =begin --- Node#attributes [DOM] return attributes of node(but always return nil?). =end ## [DOM] def attributes nil end ## proper parameter type? # def attributes=(p) # end =begin --- Node#[]=(index, nodes) set children node as nodes with []-style. =end def []=(index, nodes) @children[index..index] = nodes @children.each do |child| child.parentNode = self end if @children end =begin --- Node#[](index) get children node with []-style. =end def [](index) @children[index] end =begin --- Node#+(node) concat node to Node. =end def +(node) [self, node] end =begin --- Node#to_s returns the string representation of the Node. =end def to_s @children.to_s end =begin --- Node#dump(depth = 0) dump the Node. =end def dump(depth = 0) print ' ' * depth * 2 print nodeName + "\n" @children.each do |child| child.dump(depth + 1) end if @children end =begin --- Node#inspect() returns the human-readable string representation. =end def inspect "#<#{self.class}: #{self.nodeName}>" end =begin --- Node#firstChild() [DOM] return the first child node. =end ## [DOM] def firstChild return nil if !@children || @children.length == 0 return @children[0] end =begin --- Node#lastChild() [DOM] return the last child node. =end ## [DOM] def lastChild return nil if !@children || @children.length == 0 return @children[-1] end =begin --- Node#previousSibling() [DOM] return the previous sibling node. =end ## [DOM] def previousSibling return nil if !@parent prev = nil @parent.childNodes do |child| return prev if child == self prev = child end nil end =begin --- Node#nextSibling() [DOM] return the next sibling node. =end ## [DOM] def nextSibling return nil if !@parent nexts = nil @parent.childNodes.reverse.each do |child| return nexts if child == self nexts = child end nil end def _getChildIndex(node) index = 0 @children.each do |child| if child == node return index end index += 1 end nil end def _removeFromTree parent = parentNode if parent parent.removeChild(self) end end def _checkNode(node) raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR) end def _insertNodes(index, node) if node.nodeType == DOCUMENT_FRAGMENT_NODE node.childNodes.to_a.each_with_index do |n, i| if index == -1 _insertNodes(-1, n) else _insertNodes(index + i, n) end end elsif node.is_a?(Node) ## to be checked _checkNode(node) node._removeFromTree if index == -1 @children.push(node) else @children[index, 0] = node end node.parentNode = self else raise ArgumentError, "invalid value for Node" end end def _removeNode(index, node) @children[index, 1] = nil node.parentNode = nil end # =begin # --- Node#insertAfter(newChild, refChild) # # insert newChild into the node after refChild. # =end # def insertAfter(newChild, refChild) # if @children.nil? || @children.length == 0 # raise DOMException.new(DOMException::NOT_FOUND_ERR) # end # index = _getChildIndex(refChild) # raise DOMException.new(DOMException::NOT_FOUND_ERR) if index.nil? # _insertNodes(index + 1, newChild) # end =begin --- Node#insertBefore(newChild, refChild) [DOM] insert newChild into the node before refChild. =end ## [DOM] def insertBefore(newChild, refChild) if @children.nil? || @children.length == 0 raise DOMException.new(DOMException::NOT_FOUND_ERR) end index = _getChildIndex(refChild) raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index _insertNodes(index, newChild) end =begin --- Node#replaceChild(newChild, oldChild) [DOM] replace the child node oldChild with newChild. =end ## [DOM] def replaceChild(newChild, oldChild) if @children.nil? || @children.length == 0 raise DOMException.new(DOMException::NOT_FOUND_ERR) end index = _getChildIndex(oldChild) raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index _removeNode(index, oldChild) _insertNodes(index, newChild) end =begin --- Node#removeChild(oldChild) [DOM] remove the children node oldChild. =end ## [DOM] def removeChild(oldChild) if @children.nil? || @children.length == 0 raise DOMException.new(DOMException::NOT_FOUND_ERR) end index = _getChildIndex(oldChild) raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index _removeNode(index, oldChild) oldChild end =begin --- Node#appendChild(newChild) [DOM] adds the node newChild to the end of the list of children of this node. =end ## [DOM] def appendChild(newChild) @children = NodeList.new if !@children _insertNodes(-1, newChild) end =begin --- Node#hasChildNodes() [DOM] returns true if node has children, or return false if node has no children. =end ## [DOM] def hasChildNodes !@children.nil? && @children.length > 0 end =begin --- Node#ownerDocument() [DOM] Document object associated with this node. =end ## [DOM] def ownerDocument; @ownerDocument; end def ownerDocument=(document); @ownerDocument = document; end =begin --- Node#cloneNode() [DOM] return the copy of the Node. =end ## [DOM] def cloneNode(deep = true, *args) ret = self.class.new(*args) if (deep) @children.each do |child| ret.appendChild(child.cloneNode(true)) end end if @children ret end =begin --- Node#trim(preserve = false) trim extra whitespaces. =end ## trim extra whitespaces def trim(preserve = false) return nil if @children.nil? children = @children.to_a.dup children.each do |child| if !preserve && (child.nodeType == TEXT_NODE || child.nodeType == CDATA_SECTION_NODE) if child.trim == "" self.removeChild(child) end else child.trim(preserve) end end nil end ## [DOM2] def isSupported(feature, version) if (feature =~ /^XML$/i || feature =~ /^Core$/i) && (version.nil? || version == "1.0" || version == "2.0") return true end false end ## [DOM2] def namespaceURI; nil; end ## [DOM2] def prefix; nil; end ## [DOM2] def prefix=(prefix); ## no effect end ## [DOM2] def localname; nil; end ## [DOM2] def hasAttributes(); false; end include Enumerable def each sibstack = [] siblings = [ self ] while true if siblings.length == 0 break if sibstack.length == 0 siblings = sibstack.pop next end node = siblings.shift yield(node) children = node.childNodes if !children.nil? sibstack.push(siblings) siblings = children.to_a.dup end end end include Comparable def ==(node) equal?(node) end def <=>(node) ancestors1 = [self] ancestors2 = [node] p = self while p = p.parentNode ancestors1.unshift(p) end p = node while p = p.parentNode ancestors2.unshift(p) end raise "different document" unless ancestors1[0].equal?(ancestors2[0]) ret = 0 i = 0 for i in 1...ancestors1.size next if ancestors1[i].equal?(ancestors2[i]) return 1 if ancestors2[i].nil? children = ancestors1[i - 1].childNodes.to_a return children.index(ancestors1[i]) - children.index(ancestors2[i]) end return -1 if ancestors2.size > i + 1 0 end end end end xmlparser/lib/xml/dom2/namednodemap.rb0000644000076400007640000000443507633545643020530 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## module XML module DOM =begin == Class XML::DOM::NamedNodeMap =end class NamedNodeMap =begin === Class Methods --- NamedNodeMap.new(nodes = nil) creates a new NamedNodeMap. =end def initialize(nodes = nil) @nodes = {} nodes.each do |node| @nodes[node.nodeName] = node end if nodes end =begin === Methods --- NamedNodeMap#getNamedItem(name) [DOM] retrieves a node specified by name. =end ## [DOM] def getNamedItem(name) @nodes[name] end =begin --- NamedNodeMap#setNamedItem(node) [DOM] adds a node using its nodeName attribute. =end ## [DOM] def setNamedItem(node) @nodes[node.nodeName] = node end =begin --- NamedNodeMap#removeNamedItem(name) [DOM] removes a node specified by name. =end ## [DOM] def removeNamedItem(name) ret = @nodes[name] @nodes.delete(name) ret end =begin --- NamedNodeMap#item(index) [DOM] returns the index item in the map. =end ## [DOM] def item(index) v = @nodes.to_a[index] return v[1] if v nil end =begin --- NamedNodeMap#[](name) returns nodes associated to name. =end def [](name) @nodes[name] end =begin --- NamedNodeMap#[]=(name, node) sets node named name. =end def []=(name, node) raise "parameter error" if node.nodeName != name @nodes[name] = node end =begin --- NamedNodeMap#each() iterates over each pair of name and node(name, node) of the namedNodeMap. =end def each @nodes.each do |key, value| yield(value) end end =begin --- NamedNodeMap#size() [DOM] returns the number of nodes in the map. =end ## [DOM] def size @nodes.length end alias length size ## get nodeValues by names ## names ::= name ('|' name)* def _getValues(names) ret = [] names.split('|').each do |name| if !@nodes[name].nil? ret.push(@nodes[name].nodeValue) end end ret end ## [DOM2] ## def getNamedItemNS(nsuri, localname); end ## def removeNamedItemNS(nsuri, localname); end end end end xmlparser/lib/xml/dom2/documentfragment.rb0000644000076400007640000000263707633545643021444 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/node' require 'xml/dom2/domexception' module XML module DOM =begin == Class XML::DOM::DocumentFragment === superclass Node =end class DocumentFragment" end =begin --- CDATASection#dump(depth = 0) dumps the CDATASection. =end def dump(depth = 0) print ' ' * depth * 2 print "\n" end end end end xmlparser/lib/xml/dom2/documenttype.rb0000644000076400007640000000306507633545643020616 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/node' module XML module DOM =begin == Class XML::DOM::DocumentType === superclass Node =end class DocumentType\n" end =begin --- DocumentType#cloneNode(deep = true) [DOM] returns the copy of the DocumentType. =end ## [DOM] def cloneNode(deep = true) super(deep, @name, @pubid, @sysid) end ## [DOM] ## def entities; @entities; end ## def notations; @notations; end ## [DOM2] def publicId; @pubid; end ## [DOM2] def systemId; @sysid; end ## [DOM2] def internalSubset; end end end end xmlparser/lib/xml/dom2/element.rb0000644000076400007640000003045707662573517017537 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/node' require 'xml/dom2/domexception' require 'xml/dom2/nodelist' require 'xml/dom2/namednodemap' module XML module DOM =begin == Class XML::DOM::Element === superclass Node =end class Element 0 end ## [DOM2] def getAttributeNS(nsuri, localname) attr = getAttributeNodeNS(nsuri, localname) if attr.nil? "" else attr.nodeValue end end ## [DOM2] def setAttributeNS(nsuri, qname, value) if qname.index(':') prefix, localname = qname.split(':') raise DOMException.new(DOMException::NAMESPACE_ERR) if nsuri.nil? or (prefix == 'xml' and nsuri != 'http://www.w3.org/XML/1998/namespace') else raise DOMException.new(DOMException::NAMESPACE_ERR) if qname == 'xmlns' and nsuri != 'http://www.w3.org/2000/xmlns/' end attr = @ownerDocument.createAttributeNS(nsuri, qname) attr.appendChild(@ownerDocument.createTextNode(value)) setAttributeNodeNS(attr) end ## [DOM2] def removeAttributeNS(nsuri, localname) ret = getAttributeNodeNS(nsuri, localname) removeAttributeNode(ret) if ret end ## [DOM2] def getAttributeNodeNS(nsuri, localname) attributes.each do |attr| return attr if attr.namespaceURI == nsuri && attr.localname == localname end nil end ## [DOM2] def setAttributeNodeNS(newAttr) ret = getAttributeNodeNS(newAttr.namespaceURI, newAttr.localname) removeAttributeNode(ret) if ret setAttributeNode(newAttr) ret end ## [DOM2] def getElementsByTagNameNS(nsuri, localname) ret = NodeList.new @children.each do |node| if node.nodeType == ELEMENT_NODE if (localname == '*' || node.localname == localname) and (nsuri == '*' || node.namespaceURI == nsuri) ret << node end ret << node.getElementsByTagNameNS(nsuri, localname) end end if @children ret end ## [DOM2] def hasAttribute(name) !getAttributeNode(name).nil? end ## [DOM2] def hasAttributeNS(nsuri, localname) !getAttributeNodeNS(nsuri, localname).nil? end def idAttribute; @idAttribute; end def idAttribute=(name); @idAttribute = name; end def _checkNode(node) unless node.nodeType == ELEMENT_NODE || node.nodeType == TEXT_NODE || node.nodeType == COMMENT_NODE || node.nodeType == PROCESSING_INSTRUCTION_NODE || node.nodeType == CDATA_SECTION_NODE || node.nodeType == ENTITY_REFERENCE_NODE raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR) end end end end end xmlparser/lib/xml/dom2/attr.rb0000644000076400007640000000750507633545642017052 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/node' require 'xml/dom2/domexception' module XML module DOM =begin == Class XML::DOM::Attr === superclass Node =end class Attr\n" end end end end xmlparser/lib/xml/dom2/characterdata.rb0000644000076400007640000000612407633545643020663 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/node' require 'xml/dom2/domexception' module XML module DOM =begin == Class XML::DOM::CharacterData === superclass Node =end class CharacterData @value.length || count < 0 raise DOMException.new(DOMException::INDEX_SIZE_ERR) end ## if the sum of start and count > length, ## return all characters to the end of the value. @value[start, count] end =begin --- CharacterData#appendData(str) [DOM] append the string to the end of the character data. =end ## [DOM] def appendData(str) @value << str end =begin --- CharacterData#insertData(offset, str) [DOM] insert a string at the specified character offset. =end ## [DOM] def insertData(offset, str) if offset < 0 || offset > @value.length raise DOMException.new(DOMException::INDEX_SIZE_ERR) end @value[offset, 0] = str end =begin --- CharacterData#deleteData(offset, count) [DOM] removes a range of characters from the node. =end ## [DOM] def deleteData(offset, count) if offset < 0 || offset > @value.length || count < 0 raise DOMException.new(DOMException::INDEX_SIZE_ERR) end @value[offset, count] = '' end =begin --- CharacterData#replaceData(offset, count, str) [DOM] replaces the characters starting at the specified character offset with specified string. =end ## [DOM] def replaceData(offset, count, str) if offset < 0 || offset > @value.length || count < 0 raise DOMException.new(DOMException::INDEX_SIZE_ERR) end @value[offset, count] = str end =begin --- CharacterData#cloneData(deep = true) [DOM] returns the copy of the CharacterData. =end ## [DOM] def cloneNode(deep = true) super(deep, @value.dup) end =begin --- CharacterData#nodeValue [DOM] return nodevalue. =end ## [DOM] def nodeValue @value end =begin --- CharacterData#nodeValue=(p) [DOM] set nodevalue as p. =end ## [DOM] def nodeValue=(p) @value = p end end end end xmlparser/lib/xml/dom2/notation.rb0000644000076400007640000000222607633545643017727 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/node' module XML module DOM =begin == Class XML::DOM::Notation === superclass Node =end class Notation" ret << ">" else ret << c end end ret ## XML.charRef(@value) end =begin --- Text#dump(depth = 0) dumps the Text. =end def dump(depth = 0) print ' ' * depth * 2 print "#{@value.inspect}\n" end =begin --- Text#splitText(offset) [DOM] breaks this Text node into two Text nodes at the specified offset. =end ## [DOM] def splitText(offset) if offset > @value.length || offset < 0 raise DOMException.new(DOMException::INDEX_SIZE_ERR) end newText = @value[offset, @value.length] newNode = Text.new(newText) if !self.parentNode.nil? self.parentNode.insertAfter(newNode, self) end @value[offset, @value.length] = "" newNode end =begin --- Text#trim(preserve = false) trim extra whitespaces. =end def trim(preserve = false) if !preserve @value.sub!(/\A\s*([\s\S]*?)\s*\Z/, "\\1") return @value end nil end end end end xmlparser/lib/xml/dom2/processinginstruction.rb0000644000076400007640000000516307633545643022555 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## require 'xml/dom2/node' module XML module DOM =begin == Class XML::DOM::ProcessingInstruction === superclass Node =end class ProcessingInstruction\n" end =begin --- ProcessingInstruction#cloneNode(deep = true) [DOM] returns the copy of the ProcessingInstruction. =end ## [DOM] def cloneNode(deep = true) super(deep, @target, @data) end end end end xmlparser/lib/xml/dom2/domexception.rb0000644000076400007640000000301607633545643020570 0ustar yoshidamyoshidam## -*- Ruby -*- ## XML::DOM ## 1998-2001 by yoshidam ## module XML module DOM =begin == Class XML::DOM::DOMException === superclass Exception DOM exception. =end class DOMException' '<=' '>=' left '=' '!=' left 'and' left 'or' preclow options no_result_var rule xPath: # none # { [] } | expr { expr = val[0].expr('.to_ruby') expr.collect! { |i| i or @context } expr } | PATTERN pattern # for XSLT { expr = val[0].expr('.to_ruby') expr.collect! { |i| i or @context } expr } pattern: locationPath | pattern '|' locationPath { val[0] ** val[2] } expr: expr 'or' expr { val[0].logical_or val[2] } | expr 'and' expr { val[0].logical_and val[2] } | expr '=' expr { val[0].eq val[2] } | expr '!=' expr { val[0].neq val[2] } | expr '<' expr { val[0].lt val[2] } | expr '>' expr { val[0].gt val[2] } | expr '<=' expr { val[0].le val[2] } | expr '>=' expr { val[0].ge val[2] } | expr '+' expr { val[0] + val[2] } | expr '-' expr { val[0] - val[2] } | '-' expr =NEG { -val[1] } | expr MUL expr { val[0] * val[2] } | expr 'div' expr { val[0] / val[2] } | expr 'mod' expr { val[0] % val[2] } | expr '|' expr { # Why `**' is used for unionizing node-sets is that its # precedence is higher than any other binary operators # in Ruby. val[0] ** val[2] } | locationPath | filterExpr | filterExpr '/' relPath { val[0] << val[2] } | filterExpr '//' relPath { val[0].add_step('descendant-or-self') << val[2] } filterExpr: Variable { Expression.new [ nil,'.get_variable(',val[0].dump,')' ] } | '(' expr ')' { val[1].unarize } | Literal { Expression.new StringConstant.new(val[0]) } | Number { Expression.new NumberConstant.new(val[0]) } | functionCall { Expression.new val[0] } | filterExpr predicate { val[0].add_predicate val[1] } functionCall: FuncName '(' arguments ')' { val[2][0,0] = [ nil, ".funcall(#{val[0].dump}" ] val[2].push(')') } arguments: # none # { [] } | expr { val[0].expr.unshift ', ' } | arguments ',' expr { val[0].push(', ').concat(val[2].expr) } predicate: '[' { c = @context @context = c.succ c } expr { c = @context @context = _values[-2] c } ']' { expr = val[2] valuetype = expr.value_type value = expr.value if valuetype == :number then if value then f = value.to_f if f > 0 and f.truncate == f then [ ".at(#{f.to_i})" ] else [ '.at(0)' ] # clear end else expr.expr('.to_f'). unshift('.at(').push(')') end elsif value then if value.true? then [] else [ '.at(0)' ] # clear end else c = val[3] if valuetype == :ruby_boolean then conv = '.true?' else conv = '.to_predicate' end a = expr.expr(conv) a.collect! { |i| i or c } a.unshift(".predicate { |#{c}| ").push(' }') end } locationPath: '/' { LocationPath.new.absolute! } | '/' relPath { val[1].absolute! } | '//' relPath { path = LocationPath.new path.absolute! path.add_step('descendant-or-self') << val[1] } | relPath relPath: step { LocationPath.new.add_step(*val[0]) } | relPath '/' step { val[0].add_step(*val[2]) } | relPath '//' step { val[0].add_step('descendant-or-self').add_step(*val[2]) } # XPath does not permit functions here, but XPointer does. | relPath '/' FuncName '(' { c = @context @context = c.succ c } arguments { c = @context @context = _values[-2] c } ')' { on_error unless is_xpointer? args = val[5] c = val[6] args.collect! { |i| i or c } args[0] = ".funcall(#{val[2].dump}) { |#{c}| [" args.push '] }' val[0].add_predicate args } step: '.' { [ 'self', false, false, false, nil ] } | '..' { [ 'parent', false, false, false, nil ] } | axisSpec nodeTest predicates { nodetest = val[1] unless nodetest[0] then axis = val[0] if axis != 'attribute' and axis != 'namespace' then nodetest[0] = 'element' end end nodetest[0] = false if nodetest[0] == 'node' nodetest.unshift(val[0]).push(val[2]) } predicates: # none # | predicates predicate { (val[0] || []).concat val[1] } nodeTest: '*' { [ false, false, false ] } | Name { if /:/ =~ val[0] then [ false, $', $` ] #' <= for racc else [ false, val[0], nil ] end } | Name ':' '*' { on_error if /:/ =~ val[0] [ false, false, val[0] ] } | NodeType '(' nodeTestArg ')' { nodetype = val[0] arg = val[2] if arg and nodetype != 'processing-instruction' then raise CompileError, "nodetest #{nodetype}() requires no argument" end [ nodetype, arg || false, false ] } nodeTestArg: # none # | Literal axisSpec: # none # { 'child' } | '@' { 'attribute' } | AxisName '::' end ---- inner ---- module CompilePhaseObject def invoke_conv(expr, conv_method) return unless conv_method if conv_method == '.to_number' or conv_method == '.to_string' or conv_method == '.to_boolean' then expr.push conv_method, '(', nil, ')' else expr.push conv_method end end private :invoke_conv end module ConstantObject include CompilePhaseObject def to_string StringConstant.new to_str end def to_number NumberConstant.new self end def to_boolean if true? then ConstantTrue else ConstantFalse end end end module BooleanConstant include ConstantObject def value_type :boolean end def expr(conv_method = nil) if conv_method == '.to_ruby' or conv_method == '.true?' then [ true?.to_s ] else ret = [ nil, '.make_boolean(', true?.to_s, ')' ] invoke_conv ret, conv_method unless conv_method == '.to_boolean' ret end end end class ConstantTrueClass < XPathTrueClass include BooleanConstant @instance = new end class ConstantFalseClass < XPathFalseClass include BooleanConstant @instance = new end ConstantTrue = ConstantTrueClass.instance ConstantFalse = ConstantFalseClass.instance class NumberConstant < XPathNumber include ConstantObject def value_type :number end def initialize(src) f = src.to_f if src.is_a? ConstantObject and s = dump_float(f) then src = s end @src = [ src ] @precedence = 1 super f end attr_reader :precedence protected :precedence def to_number self end def expr(conv_method = nil) @src.collect! { |i| if i.is_a? ConstantObject then i.expr '.to_f' else i end } expr = @src expr.flatten! @src = :draff # for debug unless conv_method == '.to_ruby' or conv_method == '.to_f' then expr[0, 0] = [ nil, '.make_number(' ] expr.push(')') invoke_conv expr, conv_method unless conv_method == '.to_number' end expr end private def dump_float(f) if f.finite? and f == eval(s = f.to_s) then s elsif f.infinite? then if f > 0 then '(1.0 / 0.0)' else '(-1.0 / 0.0)' end elsif f.nan? then '(0.0 / 0.0)' else nil end end def concat(op, other, prec) @src.unshift('(').push(')') if @precedence < prec if other.precedence < prec then @src.push(op).push('(').concat(other.expr('.to_f')).push(')') else @src.push(op).concat(other.expr('.to_f')) end @precedence = prec end public def self.def_arithmetic_operator(op, precedence) module_eval <<_, __FILE__, __LINE__ + 1 def #{op}(other) super other if s = dump_float(@value) then @src.clear @src.push s else concat ' #{op} ', other, #{precedence} end self end _ end def_arithmetic_operator '+', 0 def_arithmetic_operator '-', 0 def_arithmetic_operator '*', 1 def_arithmetic_operator '/', 1 class << self undef def_arithmetic_operator end def %(other) orig = @value super other if s = dump_float(@value) then @src.clear @src.push s else f = other.to_f other = -other if orig % f == -@value concat ' % ', other, 1 end self end def -@ super if s = dump_float(@value) then @src.clear @src.push s else if @src.size == 1 then @src.unshift '-' else @src.unshift('-(').push(')') end @precedence = 1 end self end end class StringConstant < XPathString include ConstantObject def value_type :string end def to_string self end def expr(conv_method = nil) if conv_method == '.to_ruby' or conv_method == '.to_str' then [ @value.dump ] else ret = [ nil, '.make_string(', @value.dump, ')' ] invoke_conv ret, conv_method unless conv_method == '.to_string' ret end end end class Expression include CompilePhaseObject def initialize(expr) if expr.is_a? ConstantObject then @value = expr else raise "BUG" unless expr.is_a? Array @value = nil @valuetype = nil @expr = expr end @unary = true end attr_reader :value def value_type if @value then @value.value_type else @valuetype end end def unarize unless @unary then @expr.unshift('(').push(')') @unary = true end self end def self.def_comparison_operator(name, op) module_eval <<_, __FILE__, __LINE__ + 1 def #{name}(other) if @value and other.value then if @value #{op} other.value then @value = ConstantTrue else @value = ConstantFalse end @unary = true else @expr = expr.push(' #{op} ').concat(other.expr) @valuetype = :ruby_boolean @unary = false end self end _ end def self.def_arithmetic_operator(*ops) ops.each { |op| module_eval <<_, __FILE__, __LINE__ + 1 def #{op}(other) if @value and other.value then @value = @value.to_number #{op} other.value.to_number else @expr = expr('.to_number').push(' #{op} ') # not 'to_number', for a little speed up :-) @expr.concat other.expr('.to_f') @valuetype = :number @unary = false end self end _ } end def_comparison_operator 'eq', '==' def_comparison_operator 'neq', '!=' def_comparison_operator 'lt', '<' def_comparison_operator 'gt', '>' def_comparison_operator 'le', '<=' def_comparison_operator 'ge', '>=' def_arithmetic_operator '+', '-', '*', '/', '%' class << self undef def_comparison_operator undef def_arithmetic_operator end def -@ if @value then @value = -@value.to_number else unarize @expr = expr('.to_number').unshift('-') end self end def logical_or(other) if @value and @value.true? then @value = ConstantTrue @unary = true @expr = @valuetype = nil else @expr = expr('.true?').push(' || ').concat(other.expr('.true?')) @valuetype = :ruby_boolean @unary = false end self end def logical_and(other) if @value and not @value.true? then @value = ConstantFalse @unary = true @expr = @valuetype = nil else @expr = expr('.true?').push(' && ').concat(other.expr('.true?')) @valuetype = :ruby_boolean @unary = false end self end def **(other) @expr = expr.push(' ** ').concat(other.expr) @valuetype = nil @unary = false self end def add_predicate(pred) unarize @expr = expr.concat(pred) @valuetype = nil self end def <<(other) path = other.expr path.shift # nil path.shift # .to_nodeset add_predicate path end def add_step(axis) add_predicate [ ".step(:#{axis.tr('-','_')})" ] end def expr(conv_method = nil) if @value then ret = @value.expr(conv_method) @value = nil elsif @valuetype == :ruby_boolean then ret = @expr unless conv_method == '.to_ruby' or conv_method == '.true?' then ret[0, 0] = [ nil, '.make_boolean(' ] ret.push ')' invoke_conv ret, conv_method unless conv_method == '.to_boolean' end elsif @valuetype == :number and conv_method == '.to_number' then ret = @expr elsif @valuetype == :string and conv_method == '.to_string' then ret = @expr elsif @valuetype == :boolean and conv_method == '.to_boolean' then ret = @expr else if conv_method then unarize invoke_conv @expr, conv_method end ret = @expr end @expr = :draff # for debug ret end end class LocationPath include CompilePhaseObject def initialize @root = false @steps = [] # [ axis, [ tests ], predicates ] end attr_reader :root, :steps protected :root, :steps def absolute! @root = true self end def add_step(axis, nodetype = false, localpart = false, namespace = false, predicate = nil) if nodetype == false and localpart == false and namespace == false then append_step axis, [], predicate else append_step axis, [ [ nodetype, localpart, namespace ] ], predicate end self end def <<(other) raise "BUG" if other.root other = other.steps other.each { |step| if step[0] then append_step(*step) else add_predicate(step[2]) end } self end def add_predicate(pred) @steps.push [ nil, nil, pred ] self end def **(other) unless other.is_a? LocationPath then ret = nil else othersteps = other.steps size = @steps.size unless size == othersteps.size then othersize = othersteps.size if size >= othersize then ret = (@steps[0, othersize] == othersize and self) else ret = (othersteps[0, size] == @steps and other) end else last = @steps.pop otherlast = othersteps.pop if @steps == othersteps and mix_step(last, otherlast) then ret = self else ret = nil end @steps.push last othersteps.push otherlast end end ret or Expression.new(expr) ** other end private UnifiableAxes = { 'descendant' => { 'descendant-or-self' => 'descendant', }, 'descendant-or-self' => { 'child' => 'descendant', 'descendant' => 'descendant', 'descendant-or-self' => 'descendant-or-self', }, 'ancestor' => { 'ancestor-or-self' => 'ancestor', }, 'ancestor-or-self' => { 'parent' => 'ancestor', 'ancestor' => 'ancestor', 'ancestor-or-self' => 'ancestor-or-self', }, 'following-sibling' => { 'following-sibling' => 'following-sibling', }, 'preceding-sibling' => { 'preceding-sibling' => 'preceding-sibling', }, 'following' => { 'following' => 'following', 'following-sibling' => 'following', }, 'preceding' => { 'preceding' => 'preceding', 'preceding-sibling' => 'preceding', }, 'child' => { 'following-sibling' => 'child', 'preceding-sibling' => 'child', }, } UnifiableAxes.default = {} def append_step(axis, test, predicate) lastaxis, lasttest, lastpred = laststep = @steps.last if axis == 'self' and test.empty? then @steps.push [ nil, nil, predicate ] if predicate elsif lastaxis and lasttest.empty? and not lastpred and not predicate and w = UnifiableAxes[lastaxis][axis] then laststep[0] = w laststep[1] = test else @steps.push [ axis, test, predicate ] end end def mix_step(step, other) if step[0] and step[0] == other[0] and step[2] == other[2] then step[1].concat other[1] step else nil end end public def expr(conv_method = nil) if @root then expr = [ nil, '.root_nodeset' ] else expr = [ nil, '.to_nodeset' ] end @steps.each { |axis,test,predicate| if axis.nil? then # predicate only expr.concat predicate elsif test.empty? and not predicate then expr.push ".select_all(:#{axis.tr('-','_')})" else expr.push ".step(:#{axis.tr('-','_')})" if test.empty? then expr.push ' { |n| n.select_all' else expr.push ' { |n| n.select { |i| ' test.each { |nodetype,localpart,namespace| if nodetype then expr.push "i.node_type == :#{nodetype.tr('-','_')}", ' && ' end if localpart then expr.push "i.name_localpart == #{localpart.dump}", ' && ' end if namespace.nil? then expr.push 'i.namespace_uri.nil?', ' && ' elsif namespace then namespace = namespace.dump expr.push('i.namespace_uri == ', nil, ".get_namespace(#{namespace})", ' && ') end expr[-1] = ' or ' } expr[-1] = ' }' end expr.concat predicate if predicate expr.push ' }' end } @steps = :draff # for debug invoke_conv expr, conv_method expr end def value_type nil end def value nil end def unarize self end def self.redirect_to_expr(*ops) ops.each { |op| name = op name = op[1..-1] if op[0] == ?. module_eval <<_, __FILE__, __LINE__ + 1 def #{name}(arg) ; Expression.new(expr) #{op} arg ; end _ } end redirect_to_expr('.eq', '.neq', '.lt', '.gt', '.le', '.ge', '+', '-', '*', '/', '%', '.logical_or', '.logical_and') class << self undef redirect_to_expr end def -@ -Expression.new(expr) end end Delim = '\\s\\(\\)\\[\\]\\.@,\\/\\|\\*\\+"\'=!<>:' Name = "[^-#{Delim}][^#{Delim}]*" Operator = { '@' => true, '::' => true, '(' => true, '[' => true, :MUL => true, 'and' => true, 'or' => true, 'mod' => true, 'div' => true, '/' => true, '//' => true, '|' => true, '+' => true, '-' => true, '=' => true, '!=' => true, '<' => true, '<=' => true, '>' => true, '>=' => true, ':' => false # ':' '*' => '*' must not be a MultiplyOperator # ':' 'and' => 'and' must be a OperatorName } NodeType = { 'comment' => true, 'text' => true, 'processing-instruction' => true, 'node' => true, } private def axis?(s) /\A[-a-zA-Z]+\z/ =~ s end def nodetype?(s) NodeType.key? s end def tokenize(src) token = [] src.scan(/(\.\.?|\/\/?|::?|!=|[<>]=?|[-()\[\].@,|+=*])| ("[^"]*"|'[^']*')|(\d+\.?\d*)| (\$?#{Name}(?::#{Name})?)| \s+|./ox) { |delim,literal,number,name| #/ if delim then if delim == '*' then delim = :MUL if (prev = token[-1]) and not Operator.key? prev[0] elsif delim == '::' then prev = token[-1] if prev and prev[0] == :Name and axis? prev[1] then prev[0] = :AxisName end elsif delim == '(' then if (prev = token[-1]) and prev[0] == :Name then if nodetype? prev[1] then prev[0] = :NodeType else prev[0] = :FuncName end end end token.push [ delim, delim ] elsif name then prev = token[-1] if name[0] == ?$ then name[0,1] = '' token.push [ :Variable, name ] elsif Operator.key? name and (prev = token[-1]) and not Operator[prev[0]] then token.push [ name, name ] else token.push [ :Name, name ] end elsif number then number << '.0' unless number.include? ?. token.push [ :Number, number ] elsif literal then literal.chop! literal[0,1] = '' token.push [ :Literal, literal ] else s = $&.strip token.push [ s, s ] unless s.empty? end } token end public def compile(src, pattern = false) @token = tokenize(src) @token.push [ false, :end ] @token.each { |i| p i } if @yydebug @token.reverse! @token.push [ :PATTERN, nil ] if pattern @context = 'context0' ret = do_parse ret = ret.unshift("proc { |context0| ").push(" }").join print ">>>>\n", ret, "\n<<<<\n" if @yydebug XPathProc.new eval(ret), src end def initialize(debug = false) super() @yydebug = debug end private def next_token @token.pop end def is_xpointer? false end def on_error(*args) # tok, val, values raise CompileError, 'parse error' end ---- header ---- # # xpath.rb : generated by racc # module XPath class Error < StandardError ; end class CompileError < Error ; end class TypeError < Error ; end class NameError < Error ; end class ArgumentError < Error ; end class InvalidOperation < Error ; end class XPathProc def initialize(proc, source) @proc = proc @source = source end attr_reader :source def call(context) @proc.call context end end def self.compile(src, pattern = false) @compiler = Compiler.new unless defined? @compiler @compiler.compile src, pattern end module XPathObject def _type type.name.sub(/\A.*::(?:XPath)?(?=[^:]+\z)/, '') end private :_type def type_error(into) raise XPath::TypeError, "failed to convert #{_type} into #{into}" end private :type_error def to_str # => to Ruby String type_error 'String' end def to_f # => to Ruby Float type_error 'Float' end def true? # => to Ruby Boolean type_error 'Boolean' end def to_ruby # => to Ruby Object self end def to_predicate # => to Ruby Float, true or false. shouldn't override. true? end def to_string(context) # => to XPath String. shouldn't override. context.make_string to_str end def to_number(context) # => to XPath Number. shouldn't override. context.make_number to_f end def to_boolean(context) # => to XPath Boolean. shouldn't override. context.make_boolean true? end public # called from compiled XPath expression def ==(other) if other.is_a? XPathNodeSet or other.is_a? XPathBoolean or other.is_a? XPathNumber then other == self else to_str == other.to_str end end def <(other) if other.is_a? XPathNodeSet then other > self else to_f < other.to_f end end def >(other) if other.is_a? XPathNodeSet then other < self else to_f > other.to_f end end def <=(other) if other.is_a? XPathNodeSet then other >= self else to_f <= other.to_f end end def >=(other) if other.is_a? XPathNodeSet then other <= self else to_f >= other.to_f end end def **(other) type_error 'NodeSet' end def predicate(&block) type_error 'NodeSet' end def at(pos) type_error 'NodeSet' end def funcall(name) # for XPointer raise XPath::NameError, "undefined function `#{name}' for #{_type}" end end class XPathBoolean include XPathObject class << self attr_reader :instance private :new end def to_str true?.to_s end # def to_f # def true? def to_ruby true? end def to_boolean(context) self end def ==(other) true? == other.true? end end class XPathTrueClass < XPathBoolean @instance = new def to_f 1.0 end def true? true end end class XPathFalseClass < XPathBoolean @instance = new def to_f 0.0 end def true? false end end XPathTrue = XPathTrueClass.instance XPathFalse = XPathFalseClass.instance class XPathNumber include XPathObject def initialize(num) raise ::TypeError, "must be a Float" unless num.is_a? Float @value = num end def to_str if @value.nan? then 'NaN' elsif @value.infinite? then if @value < 0 then '-Infinity' else 'Infinity' end else sprintf("%.100f", @value).gsub(/\.?0+\z/, '') # enough? end end def to_f @value end def true? @value != 0.0 and not @value.nan? end def to_ruby to_f end def to_predicate to_f end def to_number(context) self end def ==(other) if other.is_a? XPathNodeSet or other.is_a? XPathBoolean then other == self else @value == other.to_f end end def +(other) @value += other.to_f self end def -(other) @value -= other.to_f self end def *(other) @value *= other.to_f self end def /(other) @value /= other.to_f self end def %(other) n = other.to_f f = @value % n f = -f if @value < 0 f = -f if n < 0 @value = f self end def -@ @value = -@value self end def floor @value = @value.floor.to_f self end def ceil @value = @value.ceil.to_f self end def round f = @value unless f.nan? or f.infinite? then if f >= 0.0 then @value = f.round.to_f elsif f - f.truncate >= -0.5 then @value = f.ceil.to_f else @value = f.floor.to_f end end self end end class XPathString include XPathObject def initialize(str) raise ::TypeError, "must be a String" unless str.is_a? String @value = str end def to_str @value end def to_f if /\A\s*(-?\d+\.?\d*)(?:\s|\z)/ =~ @value then $1.to_f else 0.0 / 0.0 # NaN end end def true? not @value.empty? end def to_ruby to_str end def to_string(context) self end def concat(s) @value = @value + s self end def start_with?(s) /\A#{Regexp.quote(s)}/ =~ @value end def contain?(s) /#{Regexp.quote(s)}/ =~ @value end def substring_before(s) if /#{Regexp.quote(s)}/ =~ @value then @value = $` else @value = '' end self end def substring_after(s) if /#{Regexp.quote(s)}/ =~ @value then @value = $' else @value = '' end self end def substring(start, len) start = start.round.to_f if start.infinite? or start.nan? then @value = '' elsif len then len = len.round.to_f maxlen = start + len len = maxlen - 1.0 if len >= maxlen if start <= 1.0 then start = 0 else start = start.to_i - 1 end if len.nan? or len < 1.0 then @value = '' elsif len.infinite? then # @value = @value[start..-1] /\A[\W\w]{0,#{start}}/ =~ @value @value = $' else # @value = @value[start, len.to_i] /\A[\W\w]{0,#{start}}([\W\w]{0,#{len.to_i}})/ =~ @value @value = $1 end elsif start > 1.0 then # @value = @value[(start-1)..-1] /\A[\W\w]{0,#{start.to_i-1}}/ =~ @value @value = $' end raise "BUG" unless @value self end def size @value.gsub(/[^\Wa-zA-Z_\d]/, ' ').size end def normalize_space @value = @value.strip @value.gsub!(/\s+/, ' ') self end def translate(from, to) to = to.split(//) h = {} from.split(//).each_with_index { |i,n| h[i] = to[n] unless h.key? i } @value = @value.gsub(/[#{Regexp.quote(h.keys.join)}]/) { |s| h[s] } self end def replace(str) @value = str self end end ---- footer ---- # # Client NodeVisitor a NodeAdapter a Node # | | | | # |=| | | | # | |--{visit(node)}-->|=| | | # | | | |---{accept(self)}----------------->|=| # | | |=| | | | # | | | | | | # | | |=|<------------------{on_**(self)}---|=| # | | | | | | # | | | |--{wrap(node)}-->|=| | # | | | | | | | # | | | | |=| | # | |<--[NodeAdapter]--|=| | | # | | | | | # | |-----{request}----------------------->|=| | # | | | | |--{request}--->|=| # | | | | | | | # | | | | |<-----[Data]---|=| # | |<--------------------------[Data]-----|=| | # | | | | | # |=| | | | # | | | | # class TransparentNodeVisitor def visit(node) node end end class NullNodeAdapter def node self end def root nil end def parent nil end def children [] end def each_following_siblings end def each_preceding_siblings end def attributes [] end def namespaces [] end def index 0 end def node_type nil end def name_localpart nil end def qualified_name name_localpart end def namespace_uri nil end def string_value '' end def lang nil end def select_id(*ids) raise XPath::Error, "selection by ID is not supported" end end class AxisIterator def reverse_order? false end end class ReverseAxisIterator < AxisIterator def reverse_order? true end end class SelfIterator < AxisIterator def each(node, visitor) yield visitor.visit(node) end end class ChildIterator < AxisIterator def each(node, visitor, &block) visitor.visit(node).children.each { |i| yield visitor.visit(i) } end end class ParentIterator < AxisIterator def each(node, visitor) parent = visitor.visit(node).parent yield visitor.visit(parent) if parent end end class AncestorIterator < ReverseAxisIterator def each(node, visitor) node = visitor.visit(node).parent while node i = visitor.visit(node) parent = i.parent yield i node = parent end end end class AncestorOrSelfIterator < AncestorIterator def each(node, visitor) yield visitor.visit(node) super end end class DescendantIterator < AxisIterator def each(node, visitor) stack = visitor.visit(node).children.reverse while node = stack.pop i = visitor.visit(node) stack.concat i.children.reverse yield i end end end class DescendantOrSelfIterator < DescendantIterator def each(node, visitor) yield visitor.visit(node) super end end class FollowingSiblingIterator < AxisIterator def each(node, visitor) visitor.visit(node).each_following_siblings { |i| yield visitor.visit(i) } end end class PrecedingSiblingIterator < ReverseAxisIterator def each(node, visitor) visitor.visit(node).each_preceding_siblings { |i| yield visitor.visit(i) } end end class FollowingIterator < DescendantOrSelfIterator def each(node, visitor) while parent = (a = visitor.visit(node)).parent a.each_following_siblings { |i| super i, visitor } node = parent end end end class PrecedingIterator < ReverseAxisIterator def each(node, visitor) while parent = (adaptor = visitor.visit(node)).parent adaptor.each_preceding_siblings { |i| stack = visitor.visit(i).children.dup while node = stack.pop a = visitor.visit(node) stack.concat a.children yield a end yield visitor.visit(i) } node = parent end end end class AttributeIterator < AxisIterator def each(node, visitor) visitor.visit(node).attributes.each { |i| yield visitor.visit(i) } end end class NamespaceIterator < AxisIterator def each(node, visitor) visitor.visit(node).namespaces.each { |i| yield visitor.visit(i) } end end class XPathNodeSet class LocationStep < XPathNodeSet def initialize(context) @context = context @visitor = context.visitor @nodes = [] end def set_iterator(iterator) @iterator = iterator end def reuse(node) @node = node @nodes.clear end def select @iterator.each(@node, @visitor) { |i| node = i.node @nodes.push node if yield(i) } self end def select_all @iterator.each(@node, @visitor) { |i| @nodes.push i.node } self end end include XPathObject def initialize(context, *nodes) @context = context.dup @visitor = context.visitor nodes.sort! { |a,b| compare_position a, b } @nodes = nodes end attr_reader :nodes protected :nodes def to_str if @nodes.empty? then '' else @visitor.visit(@nodes[0]).string_value end end def to_f to_string(@context).to_f end def true? not @nodes.empty? end def to_ruby @nodes end def self.def_comparison_operator(*ops) ops.each { |op| module_eval <<_, __FILE__, __LINE__ + 1 def #{op}(other) if other.is_a? XPathBoolean then other #{op} self.to_boolean else visitor = @visitor str = @context.make_string('') ret = false @nodes.each { |node| str.replace visitor.visit(node).string_value break if ret = (other #{op} str) } ret end end _ } end def_comparison_operator '==', '<', '>', '<=', '>=' class << self undef def_comparison_operator end def **(other) super unless other.is_a? XPathNodeSet merge other.nodes self end def count @nodes.size end def first @nodes[0] end def each(&block) @nodes.each(&block) end def funcall(name) # for XPointer raise "BUG" unless block_given? func = ('f_' + name.tr('-', '_')).intern super unless respond_to? func, true size = @nodes.size pos = 1 c = @context.dup begin @nodes.collect! { |node| c.reuse node, pos, size pos += 1 args = yield(c) send(func, node, *args) } rescue Object::ArgumentError if $@[1] == "#{__FILE__}:#{__LINE__-3}:in `send'" then raise XPath::ArgumentError, "#{$!} for `#{name}'" end raise end self end private def compare_position(node1, node2) visitor = @visitor ancestors1 = [] ancestors2 = [] p1 = visitor.visit(node1).parent while p1 ancestors1.push node1 p1 = visitor.visit(node1 = p1).parent end p2 = visitor.visit(node2).parent while p2 ancestors2.push node2 p2 = visitor.visit(node2 = p2).parent end unless node1 == node2 then raise XPath::Error, "can't compare the positions of given two nodes" end n = -1 ancestors1.reverse_each { |node1| node2 = ancestors2[n] unless node1 == node2 then break unless node2 return visitor.visit(node1).index - visitor.visit(node2).index end n -= 1 } ancestors1.size - ancestors2.size end def merge(other) if @nodes.empty? or other.empty? then @nodes.concat other elsif (n = compare_position(@nodes.last, other.first)) <= 0 then @nodes.pop if n == 0 @nodes.concat other elsif (n = compare_position(other.last, @nodes.first)) <= 0 then other.pop if n == 0 @nodes = other.concat(@nodes) else newnodes = [] nodes = @nodes until nodes.empty? or other.empty? n = compare_position(nodes.last, other.last) if n > 0 then newnodes.push nodes.pop elsif n < 0 then newnodes.push other.pop else newnodes.push nodes.pop other.pop end end newnodes.reverse! @nodes.concat(other).concat(newnodes) end end IteratorForAxis = { :self => SelfIterator.new, :child => ChildIterator.new, :parent => ParentIterator.new, :ancestor => AncestorIterator.new, :ancestor_or_self => AncestorOrSelfIterator.new, :descendant => DescendantIterator.new, :descendant_or_self => DescendantOrSelfIterator.new, :following => FollowingIterator.new, :preceding => PrecedingIterator.new, :following_sibling => FollowingSiblingIterator.new, :preceding_sibling => PrecedingSiblingIterator.new, :attribute => AttributeIterator.new, :namespace => NamespaceIterator.new, } def get_iterator(axis) ret = IteratorForAxis[axis] unless ret then raise XPath::NameError, "invalid axis `#{axis.id2name.tr('_','-')}'" end ret end def make_location_step if defined? @__lstep__ then @__lstep__ else @__lstep__ = LocationStep.new(@context) end end public def step(axis) iterator = get_iterator(axis) lstep = make_location_step lstep.set_iterator iterator oldnodes = @nodes @nodes = [] oldnodes.each { |node| lstep.reuse node nodes = yield(lstep).nodes nodes.reverse! if iterator.reverse_order? merge nodes } self end def select_all(axis) iterator = get_iterator(axis) visitor = @visitor oldnodes = @nodes @nodes = [] oldnodes.each { |start| nodes = [] iterator.each(start, visitor) { |i| nodes.push i.node } nodes.reverse! if iterator.reverse_order? merge nodes } self end def predicate context = @context size = @nodes.size pos = 1 result = nil newnodes = @nodes.reject { |node| context.reuse node, pos, size pos += 1 result = yield(context) break if result.is_a? Numeric not result } if result.is_a? Numeric then at result else @nodes = newnodes end self end def at(pos) n = pos.to_i if n != pos or n <= 0 then node = nil else node = @nodes[n - 1] end @nodes.clear @nodes.push node if node self end end class Context def initialize(node, namespace = nil, variable = nil, visitor = nil) visitor = TransparentNodeVisitor.new unless visitor @visitor = visitor @node = node @context_position = 1 @context_size = 1 @variables = variable @namespaces = namespace || {} end attr_reader :visitor, :node, :context_position, :context_size def reuse(node, pos = 1, size = 1) @variables = nil @node, @context_position, @context_size = node, pos, size end def get_variable(name) value = @variables && @variables[name] # value should be a XPathObjcect. raise XPath::NameError, "undefined variable `#{name}'" unless value value end PredefinedNamespace = { 'xml' => 'http://www.w3.org/XML/1998/namespace', } def get_namespace(prefix) ret = @namespaces[prefix] || PredefinedNamespace[prefix] raise XPath::Error, "undeclared namespace `#{prefix}'" unless ret ret end def make_string(str) XPathString.new str end def make_number(num) XPathNumber.new num end def make_boolean(f) if f then XPathTrue else XPathFalse end end def make_nodeset(*nodes) XPathNodeSet.new(self, *nodes) end def to_nodeset make_nodeset @node end def root_nodeset make_nodeset @visitor.visit(@node).root end def funcall(name, *args) begin send('f_' + name.tr('-', '_'), *args) rescue Object::NameError if $@[0] == "#{__FILE__}:#{__LINE__-2}:in `send'" then raise XPath::NameError, "undefined function `#{name}'" end raise rescue Object::ArgumentError if $@[1] == "#{__FILE__}:#{__LINE__-7}:in `send'" then raise XPath::ArgumentError, "#{$!} for `#{name}'" end raise end end private def must(type, *args) args.each { |i| unless i.is_a? type then s = type.name.sub(/\A.*::(?:XPath)?(?=[^:]+\z)/, '') raise XPath::TypeError, "argument must be #{s}" end } end def must_be_nodeset(*args) must XPathNodeSet, *args end def f_last make_number @context_size.to_f end def f_position make_number @context_position.to_f end def f_count(nodeset) must_be_nodeset nodeset make_number nodeset.count.to_f end def f_id(obj) unless obj.is_a? XPathNodeSet then ids = obj.to_str.strip.split(/\s+/) else ids = [] obj.each { |node| ids.push @visitor.visit(node).string_value } end root = @visitor.visit(@node).root make_nodeset(*@visitor.visit(root).select_id(*ids)) end def f_local_name(nodeset = nil) unless nodeset then n = @node else must_be_nodeset nodeset n = nodeset.first end n = @visitor.visit(n) if n n = n.name_localpart if n n = '' unless n make_string n end def f_namespace_uri(nodeset = nil) unless nodeset then n = @node else must_be_nodeset nodeset n = nodeset.first end n = @visitor.visit(n) if n n = n.namespace_uri if n n = '' unless n make_string n end def f_name(nodeset = nil) unless nodeset then n = @node else must_be_nodeset nodeset n = nodeset.first end n = @visitor.visit(n) if n n = n.qualified_name if n n = '' unless n make_string n end def f_string(obj = nil) obj = to_nodeset unless obj obj.to_string self end def f_concat(str, str2, *strs) s = str2.to_str.dup strs.each { |i| s << i.to_str } str.to_string(self).concat(s) end def f_starts_with(str, sub) make_boolean str.to_string(self).start_with?(sub.to_str) end def f_contains(str, sub) make_boolean str.to_string(self).contain?(sub.to_str) end def f_substring_before(str, sub) str.to_string(self).substring_before sub.to_str end def f_substring_after(str, sub) str.to_string(self).substring_after sub.to_str end def f_substring(str, start, len = nil) len = len.to_number(self) if len str.to_string(self).substring start.to_number(self), len end def f_string_length(str = nil) if str then str = str.to_string(self) else str = make_string(@node.string_value) end make_number str.size.to_f end def f_normalize_space(str = nil) if str then str = str.to_string(self) else str = make_string(@node.string_value) end str.normalize_space end def f_translate(str, from, to) str.to_string(self).translate from.to_str, to.to_str end def f_boolean(obj) obj.to_boolean self end def f_not(bool) make_boolean(!bool.true?) end def f_true make_boolean true end def f_false make_boolean false end def f_lang(str) lang = @visitor.visit(@node).lang make_boolean(lang && /\A#{Regexp.quote(str.to_str)}(?:-|\z)/i =~ lang) end def f_number(obj = nil) obj = to_nodeset unless obj obj.to_number self end def f_sum(nodeset) must_be_nodeset nodeset sum = 0.0 nodeset.each { |node| sum += make_string(@visitor.visit(node).string_value).to_f } make_number sum end def f_floor(num) num.to_number(self).floor end def f_ceiling(num) num.to_number(self).ceil end def f_round(num) num.to_number(self).round end end end xmlparser/lib/xml/xpath.rb0000644000076400007640000022744507633546105016365 0ustar yoshidamyoshidam# # xpath.rb: generated by racc (runtime embedded) # ###### racc/parser.rb unless $".index 'racc/parser.rb' then $".push 'racc/parser.rb' type.module_eval <<'..end /home/katsu/local/lib/site_ruby/racc/parser.rb modeval..id92db944ac5', '/home/katsu/local/lib/site_ruby/racc/parser.rb', 1 # # parser.rb # # Copyright (c) 1999,2000 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU Lesser General Public License version 2 or later. # # As a special exception, when this code is copied by Racc # into a Racc output file, you may use that output file # without restriction. # module Racc class ParseError < StandardError; end end unless defined? ParseError then ParseError = Racc::ParseError end module Racc class Parser private begin if defined? Racc_Debug_Ruby_Parser then raise LoadError, 'debug ruby routine' end require 'racc/cparse' unless new.respond_to? :_racc_do_parse_c, true then raise LoadError, 'old cparse.so' end Racc_Main_Parsing_Routine = :_racc_do_parse_c Racc_YY_Parse_Method = :_racc_yyparse_c rescue LoadError Racc_Main_Parsing_Routine = :_racc_do_parse_rb Racc_YY_Parse_Method = :_racc_yyparse_rb end Racc_ruby_parser_version = '1.3.3' Racc_parser_version = Racc_ruby_parser_version def self.racc_runtime_type if Racc_Main_Parsing_Routine == :_racc_do_parse_c then 'c' else 'ruby' end end def _racc_setup t = self.type unless t::Racc_debug_parser then @yydebug = false end @yydebug = false unless defined? @yydebug if @yydebug then @racc_debug_out = $stderr unless defined? @racc_debug_out @racc_debug_out ||= $stderr end arg = t::Racc_arg if arg.size < 14 then arg[13] = true end arg end def _racc_init_sysvars @racc_state = [ 0 ] @racc_tstack = [] @racc_vstack = [] @racc_t = nil @racc_val = nil @racc_read_next = true @racc_user_yyerror = false @racc_error_status = 0 end ### ### do_parse ### def do_parse __send__ Racc_Main_Parsing_Routine, _racc_setup(), false end def next_token raise NotImplementError, "#{self.type}\#next_token must be defined" end def _racc_do_parse_rb( arg, in_debug ) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result = arg _racc_init_sysvars act = i = nil nerr = 0 catch( :racc_end_parse ) { while true do if i = action_pointer[ @racc_state[-1] ] then if @racc_read_next then if @racc_t != 0 then # $ tok, @racc_val = next_token() @racc_t = (token_table[tok] or 1) # error token racc_read_token( @racc_t, tok, @racc_val ) if @yydebug @racc_read_next = false end end i += @racc_t if i >= 0 and act = action_table[i] and action_check[i] == @racc_state[-1] then ; else act = action_default[ @racc_state[-1] ] end else act = action_default[ @racc_state[-1] ] end while act = _racc_evalact( act, arg ) do end end } end ### ### yyparse ### def yyparse( recv, mid ) __send__ Racc_YY_Parse_Method, recv, mid, _racc_setup(), true end def _racc_yyparse_rb( recv, mid, arg, c_debug ) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result, = arg _racc_init_sysvars tok = nil act = nil i = nil nerr = 0 catch( :racc_end_parse ) { until i = action_pointer[ @racc_state[-1] ] do while act = _racc_evalact( action_default[ @racc_state[-1] ], arg ) do end end recv.__send__( mid ) do |tok, val| # $stderr.puts "rd: tok=#{tok}, val=#{val}" @racc_val = val @racc_t = (token_table[tok] or 1) # error token @racc_read_next = false i += @racc_t if i >= 0 and act = action_table[i] and action_check[i] == @racc_state[-1] then # $stderr.puts "01: act=#{act}" else act = action_default[ @racc_state[-1] ] # $stderr.puts "02: act=#{act}" # $stderr.puts "curstate=#{@racc_state[-1]}" end while act = _racc_evalact( act, arg ) do end while not (i = action_pointer[ @racc_state[-1] ]) or not @racc_read_next or @racc_t == 0 do # $ if i and i += @racc_t and i >= 0 and act = action_table[i] and action_check[i] == @racc_state[-1] then # $stderr.puts "03: act=#{act}" ; else # $stderr.puts "04: act=#{act}" act = action_default[ @racc_state[-1] ] end while act = _racc_evalact( act, arg ) do end end end } end ### ### common ### def _racc_evalact( act, arg ) # $stderr.puts "ea: act=#{act}" action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result, = arg nerr = 0 # tmp if act > 0 and act < shift_n then # # shift # if @racc_error_status > 0 then @racc_error_status -= 1 unless @racc_t == 1 # error token end @racc_vstack.push @racc_val @racc_state.push act @racc_read_next = true if @yydebug then @racc_tstack.push @racc_t racc_shift( @racc_t, @racc_tstack, @racc_vstack ) end elsif act < 0 and act > -reduce_n then # # reduce # code = catch( :racc_jump ) { @racc_state.push _racc_do_reduce( arg, act ) false } if code then case code when 1 # yyerror @racc_user_yyerror = true # user_yyerror return -reduce_n when 2 # yyaccept return shift_n else raise RuntimeError, '[Racc Bug] unknown jump code' end end elsif act == shift_n then # # accept # racc_accept if @yydebug throw :racc_end_parse, @racc_vstack[0] elsif act == -reduce_n then # # error # case @racc_error_status when 0 unless arg[21] then # user_yyerror nerr += 1 on_error @racc_t, @racc_val, @racc_vstack end when 3 if @racc_t == 0 then # is $ throw :racc_end_parse, nil end @racc_read_next = true end @racc_user_yyerror = false @racc_error_status = 3 while true do if i = action_pointer[ @racc_state[-1] ] then i += 1 # error token if i >= 0 and (act = action_table[i]) and action_check[i] == @racc_state[-1] then break end end throw :racc_end_parse, nil if @racc_state.size < 2 @racc_state.pop @racc_vstack.pop if @yydebug then @racc_tstack.pop racc_e_pop( @racc_state, @racc_tstack, @racc_vstack ) end end return act else raise RuntimeError, "[Racc Bug] unknown action #{act.inspect}" end racc_next_state( @racc_state[-1], @racc_state ) if @yydebug nil end def _racc_do_reduce( arg, act ) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result, = arg state = @racc_state vstack = @racc_vstack tstack = @racc_tstack i = act * -3 len = reduce_table[i] reduce_to = reduce_table[i+1] method_id = reduce_table[i+2] void_array = [] tmp_t = tstack[ -len, len ] if @yydebug tmp_v = vstack[ -len, len ] tstack[ -len, len ] = void_array if @yydebug vstack[ -len, len ] = void_array state[ -len, len ] = void_array # tstack must be updated AFTER method call if use_result then vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) else vstack.push __send__(method_id, tmp_v, vstack) end tstack.push reduce_to racc_reduce( tmp_t, reduce_to, tstack, vstack ) if @yydebug k1 = reduce_to - nt_base if i = goto_pointer[ k1 ] then i += state[-1] if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 then return curstate end end goto_default[ k1 ] end def on_error( t, val, vstack ) raise ParseError, "\nparse error on value #{val.inspect}" end def yyerror throw :racc_jump, 1 end def yyaccept throw :racc_jump, 2 end def yyerrok @racc_error_status = 0 end # for debugging output def racc_read_token( t, tok, val ) @racc_debug_out.print 'read ' @racc_debug_out.print tok.inspect, '(internaly ', racc_token2str(t), ') ' @racc_debug_out.puts val.inspect @racc_debug_out.puts end def racc_shift( tok, tstack, vstack ) @racc_debug_out.puts "shift #{racc_token2str tok}" racc_print_stacks tstack, vstack @racc_debug_out.puts end def racc_reduce( toks, sim, tstack, vstack ) out = @racc_debug_out out.print 'reduce ' if toks.empty? then out.print ' ' else toks.each {|t| out.print ' ', racc_token2str(t) } end out.puts " --> #{racc_token2str(sim)}" racc_print_stacks tstack, vstack @racc_debug_out.puts end def racc_accept @racc_debug_out.puts 'accept' @racc_debug_out.puts end def racc_e_pop( state, tstack, vstack ) @racc_debug_out.puts 'error recovering mode: pop token' racc_print_states state racc_print_stacks tstack, vstack @racc_debug_out.puts end def racc_next_state( curstate, state ) @racc_debug_out.puts "goto #{curstate}" racc_print_states state @racc_debug_out.puts end def racc_print_stacks( t, v ) out = @racc_debug_out out.print ' [' t.each_index do |i| out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' end out.puts ' ]' end def racc_print_states( s ) out = @racc_debug_out out.print ' [' s.each {|st| out.print ' ', st } out.puts ' ]' end def racc_token2str( tok ) type::Racc_token_to_s_table[tok] or raise RuntimeError, "[Racc Bug] can't convert token #{tok} to string" end end end ..end /home/katsu/local/lib/site_ruby/racc/parser.rb modeval..id92db944ac5 end # end of racc/parser.rb # # xpath.rb : generated by racc # module XPath class Error < StandardError ; end class CompileError < Error ; end class TypeError < Error ; end class NameError < Error ; end class ArgumentError < Error ; end class InvalidOperation < Error ; end class XPathProc def initialize(proc, source) @proc = proc @source = source end attr_reader :source def call(context) @proc.call context end end def self.compile(src, pattern = false) @compiler = Compiler.new unless defined? @compiler @compiler.compile src, pattern end module XPathObject def _type type.name.sub(/\A.*::(?:XPath)?(?=[^:]+\z)/, '') end private :_type def type_error(into) raise XPath::TypeError, "failed to convert #{_type} into #{into}" end private :type_error def to_str # => to Ruby String type_error 'String' end def to_f # => to Ruby Float type_error 'Float' end def true? # => to Ruby Boolean type_error 'Boolean' end def to_ruby # => to Ruby Object self end def to_predicate # => to Ruby Float, true or false. shouldn't override. true? end def to_string(context) # => to XPath String. shouldn't override. context.make_string to_str end def to_number(context) # => to XPath Number. shouldn't override. context.make_number to_f end def to_boolean(context) # => to XPath Boolean. shouldn't override. context.make_boolean true? end public # called from compiled XPath expression def ==(other) if other.is_a? XPathNodeSet or other.is_a? XPathBoolean or other.is_a? XPathNumber then other == self else to_str == other.to_str end end def <(other) if other.is_a? XPathNodeSet then other > self else to_f < other.to_f end end def >(other) if other.is_a? XPathNodeSet then other < self else to_f > other.to_f end end def <=(other) if other.is_a? XPathNodeSet then other >= self else to_f <= other.to_f end end def >=(other) if other.is_a? XPathNodeSet then other <= self else to_f >= other.to_f end end def **(other) type_error 'NodeSet' end def predicate(&block) type_error 'NodeSet' end def at(pos) type_error 'NodeSet' end def funcall(name) # for XPointer raise XPath::NameError, "undefined function `#{name}' for #{_type}" end end class XPathBoolean include XPathObject class << self attr_reader :instance private :new end def to_str true?.to_s end # def to_f # def true? def to_ruby true? end def to_boolean(context) self end def ==(other) true? == other.true? end end class XPathTrueClass < XPathBoolean @instance = new def to_f 1.0 end def true? true end end class XPathFalseClass < XPathBoolean @instance = new def to_f 0.0 end def true? false end end XPathTrue = XPathTrueClass.instance XPathFalse = XPathFalseClass.instance class XPathNumber include XPathObject def initialize(num) raise ::TypeError, "must be a Float" unless num.is_a? Float @value = num end def to_str if @value.nan? then 'NaN' elsif @value.infinite? then if @value < 0 then '-Infinity' else 'Infinity' end else sprintf("%.100f", @value).gsub(/\.?0+\z/, '') # enough? end end def to_f @value end def true? @value != 0.0 and not @value.nan? end def to_ruby to_f end def to_predicate to_f end def to_number(context) self end def ==(other) if other.is_a? XPathNodeSet or other.is_a? XPathBoolean then other == self else @value == other.to_f end end def +(other) @value += other.to_f self end def -(other) @value -= other.to_f self end def *(other) @value *= other.to_f self end def /(other) @value /= other.to_f self end def %(other) n = other.to_f f = @value % n f = -f if @value < 0 f = -f if n < 0 @value = f self end def -@ @value = -@value self end def floor @value = @value.floor.to_f self end def ceil @value = @value.ceil.to_f self end def round f = @value unless f.nan? or f.infinite? then if f >= 0.0 then @value = f.round.to_f elsif f - f.truncate >= -0.5 then @value = f.ceil.to_f else @value = f.floor.to_f end end self end end class XPathString include XPathObject def initialize(str) raise ::TypeError, "must be a String" unless str.is_a? String @value = str end def to_str @value end def to_f if /\A\s*(-?\d+\.?\d*)(?:\s|\z)/ =~ @value then $1.to_f else 0.0 / 0.0 # NaN end end def true? not @value.empty? end def to_ruby to_str end def to_string(context) self end def concat(s) @value = @value + s self end def start_with?(s) /\A#{Regexp.quote(s)}/ =~ @value end def contain?(s) /#{Regexp.quote(s)}/ =~ @value end def substring_before(s) if /#{Regexp.quote(s)}/ =~ @value then @value = $` else @value = '' end self end def substring_after(s) if /#{Regexp.quote(s)}/ =~ @value then @value = $' else @value = '' end self end def substring(start, len) start = start.round.to_f if start.infinite? or start.nan? then @value = '' elsif len then len = len.round.to_f maxlen = start + len len = maxlen - 1.0 if len >= maxlen if start <= 1.0 then start = 0 else start = start.to_i - 1 end if len.nan? or len < 1.0 then @value = '' elsif len.infinite? then # @value = @value[start..-1] /\A[\W\w]{0,#{start}}/ =~ @value @value = $' else # @value = @value[start, len.to_i] /\A[\W\w]{0,#{start}}([\W\w]{0,#{len.to_i}})/ =~ @value @value = $1 end elsif start > 1.0 then # @value = @value[(start-1)..-1] /\A[\W\w]{0,#{start.to_i-1}}/ =~ @value @value = $' end raise "BUG" unless @value self end def size @value.gsub(/[^\Wa-zA-Z_\d]/, ' ').size end def normalize_space @value = @value.strip @value.gsub!(/\s+/, ' ') self end def translate(from, to) to = to.split(//) h = {} from.split(//).each_with_index { |i,n| h[i] = to[n] unless h.key? i } @value = @value.gsub(/[#{Regexp.quote(h.keys.join)}]/) { |s| h[s] } self end def replace(str) @value = str self end end class Compiler < Racc::Parser module_eval <<'..end xpath.ry modeval..idcc62899492', 'xpath.ry', 268 module CompilePhaseObject def invoke_conv(expr, conv_method) return unless conv_method if conv_method == '.to_number' or conv_method == '.to_string' or conv_method == '.to_boolean' then expr.push conv_method, '(', nil, ')' else expr.push conv_method end end private :invoke_conv end module ConstantObject include CompilePhaseObject def to_string StringConstant.new to_str end def to_number NumberConstant.new self end def to_boolean if true? then ConstantTrue else ConstantFalse end end end module BooleanConstant include ConstantObject def value_type :boolean end def expr(conv_method = nil) if conv_method == '.to_ruby' or conv_method == '.true?' then [ true?.to_s ] else ret = [ nil, '.make_boolean(', true?.to_s, ')' ] invoke_conv ret, conv_method unless conv_method == '.to_boolean' ret end end end class ConstantTrueClass < XPathTrueClass include BooleanConstant @instance = new end class ConstantFalseClass < XPathFalseClass include BooleanConstant @instance = new end ConstantTrue = ConstantTrueClass.instance ConstantFalse = ConstantFalseClass.instance class NumberConstant < XPathNumber include ConstantObject def value_type :number end def initialize(src) f = src.to_f if src.is_a? ConstantObject and s = dump_float(f) then src = s end @src = [ src ] @precedence = 1 super f end attr_reader :precedence protected :precedence def to_number self end def expr(conv_method = nil) @src.collect! { |i| if i.is_a? ConstantObject then i.expr '.to_f' else i end } expr = @src expr.flatten! @src = :draff # for debug unless conv_method == '.to_ruby' or conv_method == '.to_f' then expr[0, 0] = [ nil, '.make_number(' ] expr.push(')') invoke_conv expr, conv_method unless conv_method == '.to_number' end expr end private def dump_float(f) if f.finite? and f == eval(s = f.to_s) then s elsif f.infinite? then if f > 0 then '(1.0 / 0.0)' else '(-1.0 / 0.0)' end elsif f.nan? then '(0.0 / 0.0)' else nil end end def concat(op, other, prec) @src.unshift('(').push(')') if @precedence < prec if other.precedence < prec then @src.push(op).push('(').concat(other.expr('.to_f')).push(')') else @src.push(op).concat(other.expr('.to_f')) end @precedence = prec end public def self.def_arithmetic_operator(op, precedence) module_eval <<_, __FILE__, __LINE__ + 1 def #{op}(other) super other if s = dump_float(@value) then @src.clear @src.push s else concat ' #{op} ', other, #{precedence} end self end _ end def_arithmetic_operator '+', 0 def_arithmetic_operator '-', 0 def_arithmetic_operator '*', 1 def_arithmetic_operator '/', 1 class << self undef def_arithmetic_operator end def %(other) orig = @value super other if s = dump_float(@value) then @src.clear @src.push s else f = other.to_f other = -other if orig % f == -@value concat ' % ', other, 1 end self end def -@ super if s = dump_float(@value) then @src.clear @src.push s else if @src.size == 1 then @src.unshift '-' else @src.unshift('-(').push(')') end @precedence = 1 end self end end class StringConstant < XPathString include ConstantObject def value_type :string end def to_string self end def expr(conv_method = nil) if conv_method == '.to_ruby' or conv_method == '.to_str' then [ @value.dump ] else ret = [ nil, '.make_string(', @value.dump, ')' ] invoke_conv ret, conv_method unless conv_method == '.to_string' ret end end end class Expression include CompilePhaseObject def initialize(expr) if expr.is_a? ConstantObject then @value = expr else raise "BUG" unless expr.is_a? Array @value = nil @valuetype = nil @expr = expr end @unary = true end attr_reader :value def value_type if @value then @value.value_type else @valuetype end end def unarize unless @unary then @expr.unshift('(').push(')') @unary = true end self end def self.def_comparison_operator(name, op) module_eval <<_, __FILE__, __LINE__ + 1 def #{name}(other) if @value and other.value then if @value #{op} other.value then @value = ConstantTrue else @value = ConstantFalse end @unary = true else @expr = expr.push(' #{op} ').concat(other.expr) @valuetype = :ruby_boolean @unary = false end self end _ end def self.def_arithmetic_operator(*ops) ops.each { |op| module_eval <<_, __FILE__, __LINE__ + 1 def #{op}(other) if @value and other.value then @value = @value.to_number #{op} other.value.to_number else @expr = expr('.to_number').push(' #{op} ') # not 'to_number', for a little speed up :-) @expr.concat other.expr('.to_f') @valuetype = :number @unary = false end self end _ } end def_comparison_operator 'eq', '==' def_comparison_operator 'neq', '!=' def_comparison_operator 'lt', '<' def_comparison_operator 'gt', '>' def_comparison_operator 'le', '<=' def_comparison_operator 'ge', '>=' def_arithmetic_operator '+', '-', '*', '/', '%' class << self undef def_comparison_operator undef def_arithmetic_operator end def -@ if @value then @value = -@value.to_number else unarize @expr = expr('.to_number').unshift('-') end self end def logical_or(other) if @value and @value.true? then @value = ConstantTrue @unary = true @expr = @valuetype = nil else @expr = expr('.true?').push(' || ').concat(other.expr('.true?')) @valuetype = :ruby_boolean @unary = false end self end def logical_and(other) if @value and not @value.true? then @value = ConstantFalse @unary = true @expr = @valuetype = nil else @expr = expr('.true?').push(' && ').concat(other.expr('.true?')) @valuetype = :ruby_boolean @unary = false end self end def **(other) @expr = expr.push(' ** ').concat(other.expr) @valuetype = nil @unary = false self end def add_predicate(pred) unarize @expr = expr.concat(pred) @valuetype = nil self end def <<(other) path = other.expr path.shift # nil path.shift # .to_nodeset add_predicate path end def add_step(axis) add_predicate [ ".step(:#{axis.tr('-','_')})" ] end def expr(conv_method = nil) if @value then ret = @value.expr(conv_method) @value = nil elsif @valuetype == :ruby_boolean then ret = @expr unless conv_method == '.to_ruby' or conv_method == '.true?' then ret[0, 0] = [ nil, '.make_boolean(' ] ret.push ')' invoke_conv ret, conv_method unless conv_method == '.to_boolean' end elsif @valuetype == :number and conv_method == '.to_number' then ret = @expr elsif @valuetype == :string and conv_method == '.to_string' then ret = @expr elsif @valuetype == :boolean and conv_method == '.to_boolean' then ret = @expr else if conv_method then unarize invoke_conv @expr, conv_method end ret = @expr end @expr = :draff # for debug ret end end class LocationPath include CompilePhaseObject def initialize @root = false @steps = [] # [ axis, [ tests ], predicates ] end attr_reader :root, :steps protected :root, :steps def absolute! @root = true self end def add_step(axis, nodetype = false, localpart = false, namespace = false, predicate = nil) if nodetype == false and localpart == false and namespace == false then append_step axis, [], predicate else append_step axis, [ [ nodetype, localpart, namespace ] ], predicate end self end def <<(other) raise "BUG" if other.root other = other.steps other.each { |step| if step[0] then append_step(*step) else add_predicate(step[2]) end } self end def add_predicate(pred) @steps.push [ nil, nil, pred ] self end def **(other) unless other.is_a? LocationPath then ret = nil else othersteps = other.steps size = @steps.size unless size == othersteps.size then othersize = othersteps.size if size >= othersize then ret = (@steps[0, othersize] == othersize and self) else ret = (othersteps[0, size] == @steps and other) end else last = @steps.pop otherlast = othersteps.pop if @steps == othersteps and mix_step(last, otherlast) then ret = self else ret = nil end @steps.push last othersteps.push otherlast end end ret or Expression.new(expr) ** other end private UnifiableAxes = { 'descendant' => { 'descendant-or-self' => 'descendant', }, 'descendant-or-self' => { 'child' => 'descendant', 'descendant' => 'descendant', 'descendant-or-self' => 'descendant-or-self', }, 'ancestor' => { 'ancestor-or-self' => 'ancestor', }, 'ancestor-or-self' => { 'parent' => 'ancestor', 'ancestor' => 'ancestor', 'ancestor-or-self' => 'ancestor-or-self', }, 'following-sibling' => { 'following-sibling' => 'following-sibling', }, 'preceding-sibling' => { 'preceding-sibling' => 'preceding-sibling', }, 'following' => { 'following' => 'following', 'following-sibling' => 'following', }, 'preceding' => { 'preceding' => 'preceding', 'preceding-sibling' => 'preceding', }, 'child' => { 'following-sibling' => 'child', 'preceding-sibling' => 'child', }, } UnifiableAxes.default = {} def append_step(axis, test, predicate) lastaxis, lasttest, lastpred = laststep = @steps.last if axis == 'self' and test.empty? then @steps.push [ nil, nil, predicate ] if predicate elsif lastaxis and lasttest.empty? and not lastpred and not predicate and w = UnifiableAxes[lastaxis][axis] then laststep[0] = w laststep[1] = test else @steps.push [ axis, test, predicate ] end end def mix_step(step, other) if step[0] and step[0] == other[0] and step[2] == other[2] then step[1].concat other[1] step else nil end end public def expr(conv_method = nil) if @root then expr = [ nil, '.root_nodeset' ] else expr = [ nil, '.to_nodeset' ] end @steps.each { |axis,test,predicate| if axis.nil? then # predicate only expr.concat predicate elsif test.empty? and not predicate then expr.push ".select_all(:#{axis.tr('-','_')})" else expr.push ".step(:#{axis.tr('-','_')})" if test.empty? then expr.push ' { |n| n.select_all' else expr.push ' { |n| n.select { |i| ' test.each { |nodetype,localpart,namespace| if nodetype then expr.push "i.node_type == :#{nodetype.tr('-','_')}", ' && ' end if localpart then expr.push "i.name_localpart == #{localpart.dump}", ' && ' end if namespace.nil? then expr.push 'i.namespace_uri.nil?', ' && ' elsif namespace then namespace = namespace.dump expr.push('i.namespace_uri == ', nil, ".get_namespace(#{namespace})", ' && ') end expr[-1] = ' or ' } expr[-1] = ' }' end expr.concat predicate if predicate expr.push ' }' end } @steps = :draff # for debug invoke_conv expr, conv_method expr end def value_type nil end def value nil end def unarize self end def self.redirect_to_expr(*ops) ops.each { |op| name = op name = op[1..-1] if op[0] == ?. module_eval <<_, __FILE__, __LINE__ + 1 def #{name}(arg) ; Expression.new(expr) #{op} arg ; end _ } end redirect_to_expr('.eq', '.neq', '.lt', '.gt', '.le', '.ge', '+', '-', '*', '/', '%', '.logical_or', '.logical_and') class << self undef redirect_to_expr end def -@ -Expression.new(expr) end end Delim = '\\s\\(\\)\\[\\]\\.@,\\/\\|\\*\\+"\'=!<>:' Name = "[^-#{Delim}][^#{Delim}]*" Operator = { '@' => true, '::' => true, '(' => true, '[' => true, :MUL => true, 'and' => true, 'or' => true, 'mod' => true, 'div' => true, '/' => true, '//' => true, '|' => true, '+' => true, '-' => true, '=' => true, '!=' => true, '<' => true, '<=' => true, '>' => true, '>=' => true, ':' => false # ':' '*' => '*' must not be a MultiplyOperator # ':' 'and' => 'and' must be a OperatorName } NodeType = { 'comment' => true, 'text' => true, 'processing-instruction' => true, 'node' => true, } private def axis?(s) /\A[-a-zA-Z]+\z/ =~ s end def nodetype?(s) NodeType.key? s end def tokenize(src) token = [] src.scan(/(\.\.?|\/\/?|::?|!=|[<>]=?|[-()\[\].@,|+=*])| ("[^"]*"|'[^']*')|(\d+\.?\d*)| (\$?#{Name}(?::#{Name})?)| \s+|./ox) { |delim,literal,number,name| #/ if delim then if delim == '*' then delim = :MUL if (prev = token[-1]) and not Operator.key? prev[0] elsif delim == '::' then prev = token[-1] if prev and prev[0] == :Name and axis? prev[1] then prev[0] = :AxisName end elsif delim == '(' then if (prev = token[-1]) and prev[0] == :Name then if nodetype? prev[1] then prev[0] = :NodeType else prev[0] = :FuncName end end end token.push [ delim, delim ] elsif name then prev = token[-1] if name[0] == ?$ then name[0,1] = '' token.push [ :Variable, name ] elsif Operator.key? name and (prev = token[-1]) and not Operator[prev[0]] then token.push [ name, name ] else token.push [ :Name, name ] end elsif number then number << '.0' unless number.include? ?. token.push [ :Number, number ] elsif literal then literal.chop! literal[0,1] = '' token.push [ :Literal, literal ] else s = $&.strip token.push [ s, s ] unless s.empty? end } token end public def compile(src, pattern = false) @token = tokenize(src) @token.push [ false, :end ] @token.each { |i| p i } if @yydebug @token.reverse! @token.push [ :PATTERN, nil ] if pattern @context = 'context0' ret = do_parse ret = ret.unshift("proc { |context0| ").push(" }").join print ">>>>\n", ret, "\n<<<<\n" if @yydebug XPathProc.new eval(ret), src end def initialize(debug = false) super() @yydebug = debug end private def next_token @token.pop end def is_xpointer? false end def on_error(*args) # tok, val, values raise CompileError, 'parse error' end ..end xpath.ry modeval..idcc62899492 ##### racc 1.3.3 generates ### racc_reduce_table = [ 0, 0, :racc_error, 0, 39, :_reduce_1, 1, 39, :_reduce_2, 2, 39, :_reduce_3, 1, 41, :_reduce_none, 3, 41, :_reduce_5, 3, 40, :_reduce_6, 3, 40, :_reduce_7, 3, 40, :_reduce_8, 3, 40, :_reduce_9, 3, 40, :_reduce_10, 3, 40, :_reduce_11, 3, 40, :_reduce_12, 3, 40, :_reduce_13, 3, 40, :_reduce_14, 3, 40, :_reduce_15, 2, 40, :_reduce_16, 3, 40, :_reduce_17, 3, 40, :_reduce_18, 3, 40, :_reduce_19, 3, 40, :_reduce_20, 1, 40, :_reduce_none, 1, 40, :_reduce_none, 3, 40, :_reduce_23, 3, 40, :_reduce_24, 1, 43, :_reduce_25, 3, 43, :_reduce_26, 1, 43, :_reduce_27, 1, 43, :_reduce_28, 1, 43, :_reduce_29, 2, 43, :_reduce_30, 4, 45, :_reduce_31, 0, 47, :_reduce_32, 1, 47, :_reduce_33, 3, 47, :_reduce_34, 0, 48, :_reduce_35, 0, 49, :_reduce_36, 5, 46, :_reduce_37, 1, 42, :_reduce_38, 2, 42, :_reduce_39, 2, 42, :_reduce_40, 1, 42, :_reduce_none, 1, 44, :_reduce_42, 3, 44, :_reduce_43, 3, 44, :_reduce_44, 0, 51, :_reduce_45, 0, 52, :_reduce_46, 8, 44, :_reduce_47, 1, 50, :_reduce_48, 1, 50, :_reduce_49, 3, 50, :_reduce_50, 0, 55, :_reduce_none, 2, 55, :_reduce_52, 1, 54, :_reduce_53, 1, 54, :_reduce_54, 3, 54, :_reduce_55, 4, 54, :_reduce_56, 0, 56, :_reduce_none, 1, 56, :_reduce_none, 0, 53, :_reduce_59, 1, 53, :_reduce_60, 2, 53, :_reduce_none ] racc_reduce_n = 62 racc_shift_n = 100 racc_action_table = [ -1, 75, 87, 16, 19, 16, 19, 82, 2, 9, 12, 9, 12, 42, 44, 47, 48, 5, 7, 10, 14, 18, 43, 20, 1, 4, 71, 2, 84, 16, 19, 26, 83, 47, 48, 9, 12, 7, 10, 14, 18, 26, 20, 1, 4, 46, 2, 26, 16, 19, 52, 49, 54, 50, 9, 12, 7, 10, 14, 18, -32, 20, 1, 4, -32, 2, 88, 16, 19, 47, 48, 47, 48, 9, 12, 7, 10, 14, 18, -32, 20, 1, 4, -32, 2, 90, 16, 19, 47, 48, 43, 79, 9, 12, 7, 10, 14, 18, 78, 20, 1, 4, 95, 2, 26, 16, 19, 96, 37, 83, 99, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, nil, 2, nil, 16, 19, nil, nil, nil, nil, 9, 12, 7, 10, 14, 18, nil, 20, 1, 4, 16, 19, nil, 16, 19, nil, 9, 12, nil, 9, 12, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 32, 34, 36, 24, 7, 10, 7, 10, 26, 81, 29, 31, 33, 16, 19, 16, 19, 16, 19, 9, 12, 9, 12, 9, 12, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 32, 34, 36, 24, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 32, 34, 36, 24, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 32, 34, 36, 24, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 32, 34, 36, 24, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 32, 34, 36, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 32, 34, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 26, nil, 29, 31, 33, 35, 23, 25, 27, 28, 30, 16, 19, -59, -59, nil, -59, 9, 12, 16, 19, nil, nil, nil, nil, 9, 12, 26, nil, 29, 31, 33, 35, 23, 26, nil, 29, 31, 33, 35, 23, 26, nil, 29, 31, 33, 35, 23, 26, nil, 29, 31, 33, 35, 23, 26, nil, 29, 31, 33 ] racc_action_check = [ 0, 47, 75, 48, 48, 47, 47, 54, 0, 48, 48, 47, 47, 11, 11, 40, 40, 0, 0, 0, 0, 0, 11, 0, 0, 0, 38, 23, 70, 0, 0, 61, 70, 13, 13, 0, 0, 23, 23, 23, 23, 22, 23, 23, 23, 12, 37, 63, 23, 23, 15, 15, 21, 15, 23, 23, 37, 37, 37, 37, 37, 37, 37, 37, 37, 94, 78, 37, 37, 41, 41, 74, 74, 37, 37, 94, 94, 94, 94, 94, 94, 94, 94, 94, 36, 79, 94, 94, 72, 72, 80, 50, 94, 94, 36, 36, 36, 36, 49, 36, 36, 36, 89, 35, 65, 36, 36, 93, 4, 97, 98, 36, 36, 35, 35, 35, 35, nil, 35, 35, 35, nil, 34, nil, 35, 35, nil, nil, nil, nil, 35, 35, 34, 34, 34, 34, nil, 34, 34, 34, nil, 83, nil, 34, 34, nil, nil, nil, nil, 34, 34, 83, 83, 83, 83, nil, 83, 83, 83, nil, 73, nil, 83, 83, nil, nil, nil, nil, 83, 83, 73, 73, 73, 73, nil, 73, 73, 73, nil, 33, nil, 73, 73, nil, nil, nil, nil, 73, 73, 33, 33, 33, 33, nil, 33, 33, 33, nil, 32, nil, 33, 33, nil, nil, nil, nil, 33, 33, 32, 32, 32, 32, nil, 32, 32, 32, nil, 18, nil, 32, 32, nil, nil, nil, nil, 32, 32, 18, 18, 18, 18, nil, 18, 18, 18, nil, 31, nil, 18, 18, nil, nil, nil, nil, 18, 18, 31, 31, 31, 31, nil, 31, 31, 31, nil, 30, nil, 31, 31, nil, nil, nil, nil, 31, 31, 30, 30, 30, 30, nil, 30, 30, 30, nil, 2, nil, 30, 30, nil, nil, nil, nil, 30, 30, 2, 2, 2, 2, nil, 2, 2, 2, nil, 29, nil, 2, 2, nil, nil, nil, nil, 2, 2, 29, 29, 29, 29, nil, 29, 29, 29, nil, 25, nil, 29, 29, nil, nil, nil, nil, 29, 29, 25, 25, 25, 25, nil, 25, 25, 25, nil, 26, nil, 25, 25, nil, nil, nil, nil, 25, 25, 26, 26, 26, 26, nil, 26, 26, 26, nil, 27, nil, 26, 26, nil, nil, nil, nil, 26, 26, 27, 27, 27, 27, nil, 27, 27, 27, nil, 28, nil, 27, 27, nil, nil, nil, nil, 27, 27, 28, 28, 28, 28, nil, 28, 28, 28, nil, 24, nil, 28, 28, nil, nil, nil, nil, 28, 28, 24, 24, 24, 24, nil, 24, 24, 24, 44, 44, nil, 24, 24, nil, 44, 44, nil, 24, 24, 53, nil, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 71, 71, 5, 5, 67, 53, 67, 67, 67, 42, 42, 71, 71, 5, 5, 42, 42, 71, 71, 5, 5, 3, nil, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 69, nil, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 92, nil, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 86, nil, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 56, nil, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 68, nil, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 66, nil, 66, 66, 66, 66, 66, 66, 66, 66, 66, 64, nil, 64, 64, 64, 64, 64, 64, 64, 64, 64, 7, 7, 7, 7, nil, 7, 7, 7, 10, 10, nil, nil, nil, nil, 10, 10, 57, nil, 57, 57, 57, 57, 57, 60, nil, 60, 60, 60, 60, 60, 59, nil, 59, 59, 59, 59, 59, 62, nil, 62, 62, 62, 62, 62, 55, nil, 55, 55, 55 ] racc_action_pointer = [ 0, nil, 266, 451, 87, 416, nil, 533, nil, nil, 541, -5, 8, 15, nil, 19, nil, nil, 209, nil, nil, 52, 39, 19, 380, 304, 323, 342, 361, 285, 247, 228, 190, 171, 114, 95, 76, 38, 24, nil, -3, 51, 412, nil, 377, nil, nil, -24, -26, 65, 70, nil, nil, 415, 7, 604, 511, 576, nil, 590, 583, 29, 597, 45, 549, 102, 538, 434, 525, 466, 6, 414, 70, 152, 53, -19, nil, nil, 35, 62, 63, nil, nil, 133, nil, nil, 496, nil, nil, 80, nil, nil, 481, 79, 57, nil, nil, 83, 88, nil ] racc_action_default = [ -59, -28, -59, -2, -62, -59, -42, -38, -21, -60, -59, -22, -62, -41, -25, -62, -48, -29, -59, -49, -27, -62, -16, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -3, -4, -39, -40, -59, -35, -59, -30, -61, -59, -59, -54, -62, -51, -53, -62, -62, -15, -6, -10, -20, -11, -12, -17, -13, -18, -8, -19, -9, -14, -7, -33, -62, -59, -23, -59, -24, -62, -43, -44, -62, -57, -50, -26, 100, -59, -31, -5, -36, -45, -55, -62, -58, -52, -34, -62, -59, -56, -37, -46, -62, -47 ] racc_goto_table = [ 3, 45, 22, 39, 70, 40, 76, 77, 41, 73, 38, 93, 21, 94, 98, 51, 80, 89, 53, nil, nil, nil, nil, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, nil, nil, nil, 72, nil, 74, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 97, nil, nil, nil, nil, nil, nil, nil, 85, 91, nil, nil, 86, nil, nil, nil, nil, nil, nil, nil, nil, nil, 92 ] racc_goto_check = [ 2, 8, 2, 4, 9, 6, 12, 12, 6, 10, 3, 11, 1, 13, 14, 16, 17, 18, 2, nil, nil, nil, nil, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, nil, nil, nil, 6, nil, 6, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 9, nil, nil, nil, nil, nil, nil, nil, 4, 8, nil, nil, 2, nil, nil, nil, nil, nil, nil, nil, nil, nil, 2 ] racc_goto_pointer = [ nil, 12, 0, 5, -2, nil, -2, nil, -10, -33, -34, -75, -41, -74, -83, nil, 0, -35, -62 ] racc_goto_default = [ nil, nil, 69, nil, 8, 11, 13, 17, nil, nil, nil, nil, 6, nil, nil, 15, nil, nil, nil ] racc_token_table = { false => 0, Object.new => 1, "|" => 2, :NEG => 3, :MUL => 4, "div" => 5, "mod" => 6, "+" => 7, "-" => 8, "<" => 9, ">" => 10, "<=" => 11, ">=" => 12, "=" => 13, "!=" => 14, "and" => 15, "or" => 16, :PATTERN => 17, "/" => 18, "//" => 19, :Variable => 20, "(" => 21, ")" => 22, :Literal => 23, :Number => 24, :FuncName => 25, "," => 26, "[" => 27, "]" => 28, "." => 29, ".." => 30, "*" => 31, :Name => 32, ":" => 33, :NodeType => 34, "@" => 35, :AxisName => 36, "::" => 37 } racc_use_result_var = false racc_nt_base = 38 Racc_arg = [ racc_action_table, racc_action_check, racc_action_default, racc_action_pointer, racc_goto_table, racc_goto_check, racc_goto_default, racc_goto_pointer, racc_nt_base, racc_reduce_table, racc_token_table, racc_shift_n, racc_reduce_n, racc_use_result_var ] Racc_debug_parser = false ##### racc system variables end ##### # reduce 0 omitted module_eval <<'.,.,', 'xpath.ry', 27 def _reduce_1( val, _values) [] end .,., module_eval <<'.,.,', 'xpath.ry', 30 def _reduce_2( val, _values) expr = val[0].expr('.to_ruby') expr.collect! { |i| i or @context } expr end .,., module_eval <<'.,.,', 'xpath.ry', 36 def _reduce_3( val, _values) expr = val[0].expr('.to_ruby') expr.collect! { |i| i or @context } expr end .,., # reduce 4 omitted module_eval <<'.,.,', 'xpath.ry', 43 def _reduce_5( val, _values) val[0] ** val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 46 def _reduce_6( val, _values) val[0].logical_or val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 48 def _reduce_7( val, _values) val[0].logical_and val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 50 def _reduce_8( val, _values) val[0].eq val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 52 def _reduce_9( val, _values) val[0].neq val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 54 def _reduce_10( val, _values) val[0].lt val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 56 def _reduce_11( val, _values) val[0].gt val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 58 def _reduce_12( val, _values) val[0].le val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 60 def _reduce_13( val, _values) val[0].ge val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 62 def _reduce_14( val, _values) val[0] + val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 64 def _reduce_15( val, _values) val[0] - val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 66 def _reduce_16( val, _values) -val[1] end .,., module_eval <<'.,.,', 'xpath.ry', 68 def _reduce_17( val, _values) val[0] * val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 70 def _reduce_18( val, _values) val[0] / val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 72 def _reduce_19( val, _values) val[0] % val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 75 def _reduce_20( val, _values) # Why `**' is used for unionizing node-sets is that its # precedence is higher than any other binary operators # in Ruby. val[0] ** val[2] end .,., # reduce 21 omitted # reduce 22 omitted module_eval <<'.,.,', 'xpath.ry', 83 def _reduce_23( val, _values) val[0] << val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 85 def _reduce_24( val, _values) val[0].add_step('descendant-or-self') << val[2] end .,., module_eval <<'.,.,', 'xpath.ry', 89 def _reduce_25( val, _values) Expression.new [ nil,'.get_variable(',val[0].dump,')' ] end .,., module_eval <<'.,.,', 'xpath.ry', 92 def _reduce_26( val, _values) val[1].unarize end .,., module_eval <<'.,.,', 'xpath.ry', 94 def _reduce_27( val, _values) Expression.new StringConstant.new(val[0]) end .,., module_eval <<'.,.,', 'xpath.ry', 96 def _reduce_28( val, _values) Expression.new NumberConstant.new(val[0]) end .,., module_eval <<'.,.,', 'xpath.ry', 98 def _reduce_29( val, _values) Expression.new val[0] end .,., module_eval <<'.,.,', 'xpath.ry', 100 def _reduce_30( val, _values) val[0].add_predicate val[1] end .,., module_eval <<'.,.,', 'xpath.ry', 104 def _reduce_31( val, _values) val[2][0,0] = [ nil, ".funcall(#{val[0].dump}" ] val[2].push(')') end .,., module_eval <<'.,.,', 'xpath.ry', 109 def _reduce_32( val, _values) [] end .,., module_eval <<'.,.,', 'xpath.ry', 111 def _reduce_33( val, _values) val[0].expr.unshift ', ' end .,., module_eval <<'.,.,', 'xpath.ry', 113 def _reduce_34( val, _values) val[0].push(', ').concat(val[2].expr) end .,., module_eval <<'.,.,', 'xpath.ry', 117 def _reduce_35( val, _values) c = @context @context = c.succ c end .,., module_eval <<'.,.,', 'xpath.ry', 123 def _reduce_36( val, _values) c = @context @context = _values[-2] c end .,., module_eval <<'.,.,', 'xpath.ry', 129 def _reduce_37( val, _values) expr = val[2] valuetype = expr.value_type value = expr.value if valuetype == :number then if value then f = value.to_f if f > 0 and f.truncate == f then [ ".at(#{f.to_i})" ] else [ '.at(0)' ] # clear end else expr.expr('.to_f'). unshift('.at(').push(')') end elsif value then if value.true? then [] else [ '.at(0)' ] # clear end else c = val[3] if valuetype == :ruby_boolean then conv = '.true?' else conv = '.to_predicate' end a = expr.expr(conv) a.collect! { |i| i or c } a.unshift(".predicate { |#{c}| ").push(' }') end end .,., module_eval <<'.,.,', 'xpath.ry', 164 def _reduce_38( val, _values) LocationPath.new.absolute! end .,., module_eval <<'.,.,', 'xpath.ry', 166 def _reduce_39( val, _values) val[1].absolute! end .,., module_eval <<'.,.,', 'xpath.ry', 169 def _reduce_40( val, _values) path = LocationPath.new path.absolute! path.add_step('descendant-or-self') << val[1] end .,., # reduce 41 omitted module_eval <<'.,.,', 'xpath.ry', 176 def _reduce_42( val, _values) LocationPath.new.add_step(*val[0]) end .,., module_eval <<'.,.,', 'xpath.ry', 178 def _reduce_43( val, _values) val[0].add_step(*val[2]) end .,., module_eval <<'.,.,', 'xpath.ry', 181 def _reduce_44( val, _values) val[0].add_step('descendant-or-self').add_step(*val[2]) end .,., module_eval <<'.,.,', 'xpath.ry', 186 def _reduce_45( val, _values) c = @context @context = c.succ c end .,., module_eval <<'.,.,', 'xpath.ry', 192 def _reduce_46( val, _values) c = @context @context = _values[-2] c end .,., module_eval <<'.,.,', 'xpath.ry', 198 def _reduce_47( val, _values) on_error unless is_xpointer? args = val[5] c = val[6] args.collect! { |i| i or c } args[0] = ".funcall(#{val[2].dump}) { |#{c}| [" args.push '] }' val[0].add_predicate args end .,., module_eval <<'.,.,', 'xpath.ry', 208 def _reduce_48( val, _values) [ 'self', false, false, false, nil ] end .,., module_eval <<'.,.,', 'xpath.ry', 210 def _reduce_49( val, _values) [ 'parent', false, false, false, nil ] end .,., module_eval <<'.,.,', 'xpath.ry', 213 def _reduce_50( val, _values) nodetest = val[1] unless nodetest[0] then axis = val[0] if axis != 'attribute' and axis != 'namespace' then nodetest[0] = 'element' end end nodetest[0] = false if nodetest[0] == 'node' nodetest.unshift(val[0]).push(val[2]) end .,., # reduce 51 omitted module_eval <<'.,.,', 'xpath.ry', 226 def _reduce_52( val, _values) (val[0] || []).concat val[1] end .,., module_eval <<'.,.,', 'xpath.ry', 229 def _reduce_53( val, _values) [ false, false, false ] end .,., module_eval <<'.,.,', 'xpath.ry', 232 def _reduce_54( val, _values) if /:/ =~ val[0] then [ false, $', $` ] #' <= for racc else [ false, val[0], nil ] end end .,., module_eval <<'.,.,', 'xpath.ry', 240 def _reduce_55( val, _values) on_error if /:/ =~ val[0] [ false, false, val[0] ] end .,., module_eval <<'.,.,', 'xpath.ry', 245 def _reduce_56( val, _values) nodetype = val[0] arg = val[2] if arg and nodetype != 'processing-instruction' then raise CompileError, "nodetest #{nodetype}() requires no argument" end [ nodetype, arg || false, false ] end .,., # reduce 57 omitted # reduce 58 omitted module_eval <<'.,.,', 'xpath.ry', 258 def _reduce_59( val, _values) 'child' end .,., module_eval <<'.,.,', 'xpath.ry', 260 def _reduce_60( val, _values) 'attribute' end .,., # reduce 61 omitted def _reduce_none( val, _values) val[0] end end # class Compiler # # Client NodeVisitor a NodeAdapter a Node # | | | | # |=| | | | # | |--{visit(node)}-->|=| | | # | | | |---{accept(self)}----------------->|=| # | | |=| | | | # | | | | | | # | | |=|<------------------{on_**(self)}---|=| # | | | | | | # | | | |--{wrap(node)}-->|=| | # | | | | | | | # | | | | |=| | # | |<--[NodeAdapter]--|=| | | # | | | | | # | |-----{request}----------------------->|=| | # | | | | |--{request}--->|=| # | | | | | | | # | | | | |<-----[Data]---|=| # | |<--------------------------[Data]-----|=| | # | | | | | # |=| | | | # | | | | # class TransparentNodeVisitor def visit(node) node end end class NullNodeAdapter def node self end def root nil end def parent nil end def children [] end def each_following_siblings end def each_preceding_siblings end def attributes [] end def namespaces [] end def index 0 end def node_type nil end def name_localpart nil end def qualified_name name_localpart end def namespace_uri nil end def string_value '' end def lang nil end def select_id(*ids) raise XPath::Error, "selection by ID is not supported" end end class AxisIterator def reverse_order? false end end class ReverseAxisIterator < AxisIterator def reverse_order? true end end class SelfIterator < AxisIterator def each(node, visitor) yield visitor.visit(node) end end class ChildIterator < AxisIterator def each(node, visitor, &block) visitor.visit(node).children.each { |i| yield visitor.visit(i) } end end class ParentIterator < AxisIterator def each(node, visitor) parent = visitor.visit(node).parent yield visitor.visit(parent) if parent end end class AncestorIterator < ReverseAxisIterator def each(node, visitor) node = visitor.visit(node).parent while node i = visitor.visit(node) parent = i.parent yield i node = parent end end end class AncestorOrSelfIterator < AncestorIterator def each(node, visitor) yield visitor.visit(node) super end end class DescendantIterator < AxisIterator def each(node, visitor) stack = visitor.visit(node).children.reverse while node = stack.pop i = visitor.visit(node) stack.concat i.children.reverse yield i end end end class DescendantOrSelfIterator < DescendantIterator def each(node, visitor) yield visitor.visit(node) super end end class FollowingSiblingIterator < AxisIterator def each(node, visitor) visitor.visit(node).each_following_siblings { |i| yield visitor.visit(i) } end end class PrecedingSiblingIterator < ReverseAxisIterator def each(node, visitor) visitor.visit(node).each_preceding_siblings { |i| yield visitor.visit(i) } end end class FollowingIterator < DescendantOrSelfIterator def each(node, visitor) while parent = (a = visitor.visit(node)).parent a.each_following_siblings { |i| super i, visitor } node = parent end end end class PrecedingIterator < ReverseAxisIterator def each(node, visitor) while parent = (adaptor = visitor.visit(node)).parent adaptor.each_preceding_siblings { |i| stack = visitor.visit(i).children.dup while node = stack.pop a = visitor.visit(node) stack.concat a.children yield a end yield visitor.visit(i) } node = parent end end end class AttributeIterator < AxisIterator def each(node, visitor) visitor.visit(node).attributes.each { |i| yield visitor.visit(i) } end end class NamespaceIterator < AxisIterator def each(node, visitor) visitor.visit(node).namespaces.each { |i| yield visitor.visit(i) } end end class XPathNodeSet class LocationStep < XPathNodeSet def initialize(context) @context = context @visitor = context.visitor @nodes = [] end def set_iterator(iterator) @iterator = iterator end def reuse(node) @node = node @nodes.clear end def select @iterator.each(@node, @visitor) { |i| node = i.node @nodes.push node if yield(i) } self end def select_all @iterator.each(@node, @visitor) { |i| @nodes.push i.node } self end end include XPathObject def initialize(context, *nodes) @context = context.dup @visitor = context.visitor nodes.sort! { |a,b| compare_position a, b } @nodes = nodes end attr_reader :nodes protected :nodes def to_str if @nodes.empty? then '' else @visitor.visit(@nodes[0]).string_value end end def to_f to_string(@context).to_f end def true? not @nodes.empty? end def to_ruby @nodes end def self.def_comparison_operator(*ops) ops.each { |op| module_eval <<_, __FILE__, __LINE__ + 1 def #{op}(other) if other.is_a? XPathBoolean then other #{op} self.to_boolean else visitor = @visitor str = @context.make_string('') ret = false @nodes.each { |node| str.replace visitor.visit(node).string_value break if ret = (other #{op} str) } ret end end _ } end def_comparison_operator '==', '<', '>', '<=', '>=' class << self undef def_comparison_operator end def **(other) super unless other.is_a? XPathNodeSet merge other.nodes self end def count @nodes.size end def first @nodes[0] end def each(&block) @nodes.each(&block) end def funcall(name) # for XPointer raise "BUG" unless block_given? func = ('f_' + name.tr('-', '_')).intern super unless respond_to? func, true size = @nodes.size pos = 1 c = @context.dup begin @nodes.collect! { |node| c.reuse node, pos, size pos += 1 args = yield(c) send(func, node, *args) } rescue Object::ArgumentError if $@[1] == "#{__FILE__}:#{__LINE__-3}:in `send'" then raise XPath::ArgumentError, "#{$!} for `#{name}'" end raise end self end private def compare_position(node1, node2) visitor = @visitor ancestors1 = [] ancestors2 = [] p1 = visitor.visit(node1).parent while p1 ancestors1.push node1 p1 = visitor.visit(node1 = p1).parent end p2 = visitor.visit(node2).parent while p2 ancestors2.push node2 p2 = visitor.visit(node2 = p2).parent end unless node1 == node2 then raise XPath::Error, "can't compare the positions of given two nodes" end n = -1 ancestors1.reverse_each { |node1| node2 = ancestors2[n] unless node1 == node2 then break unless node2 return visitor.visit(node1).index - visitor.visit(node2).index end n -= 1 } ancestors1.size - ancestors2.size end def merge(other) if @nodes.empty? or other.empty? then @nodes.concat other elsif (n = compare_position(@nodes.last, other.first)) <= 0 then @nodes.pop if n == 0 @nodes.concat other elsif (n = compare_position(other.last, @nodes.first)) <= 0 then other.pop if n == 0 @nodes = other.concat(@nodes) else newnodes = [] nodes = @nodes until nodes.empty? or other.empty? n = compare_position(nodes.last, other.last) if n > 0 then newnodes.push nodes.pop elsif n < 0 then newnodes.push other.pop else newnodes.push nodes.pop other.pop end end newnodes.reverse! @nodes.concat(other).concat(newnodes) end end IteratorForAxis = { :self => SelfIterator.new, :child => ChildIterator.new, :parent => ParentIterator.new, :ancestor => AncestorIterator.new, :ancestor_or_self => AncestorOrSelfIterator.new, :descendant => DescendantIterator.new, :descendant_or_self => DescendantOrSelfIterator.new, :following => FollowingIterator.new, :preceding => PrecedingIterator.new, :following_sibling => FollowingSiblingIterator.new, :preceding_sibling => PrecedingSiblingIterator.new, :attribute => AttributeIterator.new, :namespace => NamespaceIterator.new, } def get_iterator(axis) ret = IteratorForAxis[axis] unless ret then raise XPath::NameError, "invalid axis `#{axis.id2name.tr('_','-')}'" end ret end def make_location_step if defined? @__lstep__ then @__lstep__ else @__lstep__ = LocationStep.new(@context) end end public def step(axis) iterator = get_iterator(axis) lstep = make_location_step lstep.set_iterator iterator oldnodes = @nodes @nodes = [] oldnodes.each { |node| lstep.reuse node nodes = yield(lstep).nodes nodes.reverse! if iterator.reverse_order? merge nodes } self end def select_all(axis) iterator = get_iterator(axis) visitor = @visitor oldnodes = @nodes @nodes = [] oldnodes.each { |start| nodes = [] iterator.each(start, visitor) { |i| nodes.push i.node } nodes.reverse! if iterator.reverse_order? merge nodes } self end def predicate context = @context size = @nodes.size pos = 1 result = nil newnodes = @nodes.reject { |node| context.reuse node, pos, size pos += 1 result = yield(context) break if result.is_a? Numeric not result } if result.is_a? Numeric then at result else @nodes = newnodes end self end def at(pos) n = pos.to_i if n != pos or n <= 0 then node = nil else node = @nodes[n - 1] end @nodes.clear @nodes.push node if node self end end class Context def initialize(node, namespace = nil, variable = nil, visitor = nil) visitor = TransparentNodeVisitor.new unless visitor @visitor = visitor @node = node @context_position = 1 @context_size = 1 @variables = variable @namespaces = namespace || {} end attr_reader :visitor, :node, :context_position, :context_size def reuse(node, pos = 1, size = 1) @variables = nil @node, @context_position, @context_size = node, pos, size end def get_variable(name) value = @variables && @variables[name] # value should be a XPathObjcect. raise XPath::NameError, "undefined variable `#{name}'" unless value value end PredefinedNamespace = { 'xml' => 'http://www.w3.org/XML/1998/namespace', } def get_namespace(prefix) ret = @namespaces[prefix] || PredefinedNamespace[prefix] raise XPath::Error, "undeclared namespace `#{prefix}'" unless ret ret end def make_string(str) XPathString.new str end def make_number(num) XPathNumber.new num end def make_boolean(f) if f then XPathTrue else XPathFalse end end def make_nodeset(*nodes) XPathNodeSet.new(self, *nodes) end def to_nodeset make_nodeset @node end def root_nodeset make_nodeset @visitor.visit(@node).root end def funcall(name, *args) begin send('f_' + name.tr('-', '_'), *args) rescue Object::NameError if $@[0] == "#{__FILE__}:#{__LINE__-2}:in `send'" then raise XPath::NameError, "undefined function `#{name}'" end raise rescue Object::ArgumentError if $@[1] == "#{__FILE__}:#{__LINE__-7}:in `send'" then raise XPath::ArgumentError, "#{$!} for `#{name}'" end raise end end private def must(type, *args) args.each { |i| unless i.is_a? type then s = type.name.sub(/\A.*::(?:XPath)?(?=[^:]+\z)/, '') raise XPath::TypeError, "argument must be #{s}" end } end def must_be_nodeset(*args) must XPathNodeSet, *args end def f_last make_number @context_size.to_f end def f_position make_number @context_position.to_f end def f_count(nodeset) must_be_nodeset nodeset make_number nodeset.count.to_f end def f_id(obj) unless obj.is_a? XPathNodeSet then ids = obj.to_str.strip.split(/\s+/) else ids = [] obj.each { |node| ids.push @visitor.visit(node).string_value } end root = @visitor.visit(@node).root make_nodeset(*@visitor.visit(root).select_id(*ids)) end def f_local_name(nodeset = nil) unless nodeset then n = @node else must_be_nodeset nodeset n = nodeset.first end n = @visitor.visit(n) if n n = n.name_localpart if n n = '' unless n make_string n end def f_namespace_uri(nodeset = nil) unless nodeset then n = @node else must_be_nodeset nodeset n = nodeset.first end n = @visitor.visit(n) if n n = n.namespace_uri if n n = '' unless n make_string n end def f_name(nodeset = nil) unless nodeset then n = @node else must_be_nodeset nodeset n = nodeset.first end n = @visitor.visit(n) if n n = n.qualified_name if n n = '' unless n make_string n end def f_string(obj = nil) obj = to_nodeset unless obj obj.to_string self end def f_concat(str, str2, *strs) s = str2.to_str.dup strs.each { |i| s << i.to_str } str.to_string(self).concat(s) end def f_starts_with(str, sub) make_boolean str.to_string(self).start_with?(sub.to_str) end def f_contains(str, sub) make_boolean str.to_string(self).contain?(sub.to_str) end def f_substring_before(str, sub) str.to_string(self).substring_before sub.to_str end def f_substring_after(str, sub) str.to_string(self).substring_after sub.to_str end def f_substring(str, start, len = nil) len = len.to_number(self) if len str.to_string(self).substring start.to_number(self), len end def f_string_length(str = nil) if str then str = str.to_string(self) else str = make_string(@node.string_value) end make_number str.size.to_f end def f_normalize_space(str = nil) if str then str = str.to_string(self) else str = make_string(@node.string_value) end str.normalize_space end def f_translate(str, from, to) str.to_string(self).translate from.to_str, to.to_str end def f_boolean(obj) obj.to_boolean self end def f_not(bool) make_boolean(!bool.true?) end def f_true make_boolean true end def f_false make_boolean false end def f_lang(str) lang = @visitor.visit(@node).lang make_boolean(lang && /\A#{Regexp.quote(str.to_str)}(?:-|\z)/i =~ lang) end def f_number(obj = nil) obj = to_nodeset unless obj obj.to_number self end def f_sum(nodeset) must_be_nodeset nodeset sum = 0.0 nodeset.each { |node| sum += make_string(@visitor.visit(node).string_value).to_f } make_number sum end def f_floor(num) num.to_number(self).floor end def f_ceiling(num) num.to_number(self).ceil end def f_round(num) num.to_number(self).round end end end xmlparser/lib/xml/dom2/xpath.rb0000644000076400007640000001625407633552744017226 0ustar yoshidamyoshidam# # xpath-dom.rb # # Copyright (C) Ueno Katsuhiro 2000 # DOM2 support by yoshidam # # $Id: xpath.rb,v 1.2 2003/03/12 06:38:28 yoshidam Exp $ # require 'xml/dom2/core' require 'xml/xpath' module XMLScan XPath = ::XPath unless defined?(::XMLScan::XPath) module XPath module DOM class AbstractNodeAdapter < NullNodeAdapter def wrap(node, visitor) @node = node self end attr_reader :node def root @node.ownerDocument end def parent @node.parentNode end def children @node.childNodes.to_a end def each_following_siblings node = @node yield node while node = node.nextSibling end def each_preceding_siblings node = @node yield node while node = node.previousSibling end def index @node.parentNode.childNodes.to_a.index(@node) end def lang node = @node lang = nil until a = node.attributes and lang = a.getNamedItem('xml:lang') node = node.parentNode end lang and lang.nodeValue end end class TextNodeAdapter < AbstractNodeAdapter def node_type :text end def string_value @node.nodeValue end end class CommentNodeAdapter < TextNodeAdapter def node_type :comment end end class PINodeAdapter < AbstractNodeAdapter def node_type :processing_instruction end def name_localpart @node.nodeName end def string_value @node.nodeValue end end class ParentNodeAdapter < AbstractNodeAdapter def string_value dst = '' stack = @node.childNodes.to_a.reverse while node = stack.pop s = node.nodeValue dst << s if s stack.concat node.childNodes.to_a.reverse end dst end end class RootNodeAdapter < ParentNodeAdapter def node_type :root end alias root node def index 0 end end class ElementNodeAdapter < ParentNodeAdapter def wrap(node, visitor) @node = node @visitor = visitor self end def node_type :element end def name_localpart @node.nodeName end def namespace_uri @node.namespaceURI end def qualified_name @node.nodeName end def attributes map = @node.attributes attrs = @visitor.get_attributes(@node) unless attrs then attrs = [] map.length.times { |i| attrs.push map.item(i) } @visitor.regist_attributes @node, attrs end attrs end end class AttrNodeAdapter < AbstractNodeAdapter def wrap(node, visitor) @node = node @visitor = visitor self end def node_type :attribute end def name_localpart @node.nodeName end def namespace_uri @node.namespaceURI end def qualified_name @node.nodeName end def parent @visitor.get_attr_parent @node end def index -@visitor.get_attributes(parent).index(@node) end def string_value @node.nodeValue end end class NodeVisitor def initialize @adapters = Array.new(12, NullNodeAdapter.new) @adapters[XML::DOM::Node::ELEMENT_NODE] = ElementNodeAdapter.new @adapters[XML::DOM::Node::ATTRIBUTE_NODE] = AttrNodeAdapter.new @adapters[XML::DOM::Node::TEXT_NODE] = @adapters[XML::DOM::Node::CDATA_SECTION_NODE] = TextNodeAdapter.new @adapters[XML::DOM::Node::PROCESSING_INSTRUCTION_NODE] = PINodeAdapter.new @adapters[XML::DOM::Node::COMMENT_NODE] = CommentNodeAdapter.new @adapters[XML::DOM::Node::DOCUMENT_NODE] = RootNodeAdapter.new @attr = {} end def visit(node) @adapters[node.nodeType].wrap(node, self) end def regist_attributes(node, attrs) @attr[node] = attrs attrs.each { |i| @attr[i] = node } end def get_attributes(node) @attr[node] end def get_attr_parent(node) @attr[node] end end class Context < XMLScan::XPath::Context def initialize(node, namespace = nil, variable = nil) super node, namespace, variable, NodeVisitor.new end end end end ## module XPath end ## module XMLScan module XML module DOM class Node def __collectDescendatNS(ns = {}) childNodes.each do |node| next if node.nodeType != ELEMENT_NODE prefix = node.prefix uri = node.namespaceURI ns[prefix] = uri unless ns.has_key?(prefix) node.__collectDescendatNS(ns) end end def __collectAncestorNS(ns = {}) node = self while node prefix = node.prefix uri = node.namespaceURI ns[prefix] = uri unless ns.has_key?(prefix) node = node.parentNode end end def getNodesByXPath(xpath, ns = {}) xpath = XMLScan::XPath.compile(xpath) unless xpath.is_a? XMLScan::XPath if ns.length == 0 ## collect namespaces __collectAncestorNS(ns) __collectDescendatNS(ns) end ret = xpath.call(XPath::DOM::Context.new(self, ns)) raise "return value is not NodeSet" unless ret.is_a? Array ret end def _getMyLocationInXPath(parent) n = parent.childNodes.index(self) "node()[#{n + 1}]" end def makeXPath dst = [] node = self while parent = node.parentNode dst.push node._getMyLocationInXPath(parent) node = parent end dst.reverse! '/' + dst.join('/') end end class Element def _getMyLocationInXPath(parent) name = nodeName n = parent.childNodes.to_a.select { |i| i.nodeType == ELEMENT_NODE and i.nodeName == name }.index(self) "#{name}[#{n + 1}]" end end class Text def _getMyLocationInXPath(parent) n = parent.childNodes.to_a.select { |i| i.nodeType == TEXT_NODE or i.nodeType == CDATA_SECTION_NODE }.index(self) "text()[#{n + 1}]" end end class CDATASection def _getMyLocationInXPath(parent) n = parent.childNodes.to_a.select { |i| i.nodeType == TEXT_NODE or i.nodeType == CDATA_SECTION_NODE }.index(self) "text()[#{n + 1}]" end end class Comment def _getMyLocationInXPath(parent) n = parent.childNodes.to_a.select { |i| i.nodeType == COMMENT_NODE }.index(self) "comment()[#{n + 1}]" end end class ProcessingInstruction def _getMyLocationInXPath(parent) n = parent.childNodes.to_a.select { |i| i.nodeType == PROCESSING_INSTRUCTION_NODE }.index(self) "processing-instruction()[#{n + 1}]" end end class Attr def makeXPath '@' + nodeName end end end end