summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes494
-rw-r--r--Expat/Expat.pm1230
-rw-r--r--Expat/Expat.xs2214
-rw-r--r--Expat/Makefile.PL29
-rw-r--r--Expat/encoding.h91
-rw-r--r--Expat/typemap24
-rw-r--r--MANIFEST60
-rw-r--r--META.yml11
-rw-r--r--Makefile.PL114
-rw-r--r--Parser.pm840
-rw-r--r--Parser/Encodings/Japanese_Encodings.msg117
-rw-r--r--Parser/Encodings/README51
-rw-r--r--Parser/Encodings/big5.encbin0 -> 40706 bytes
-rw-r--r--Parser/Encodings/euc-kr.encbin0 -> 45802 bytes
-rw-r--r--Parser/Encodings/iso-8859-2.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/iso-8859-3.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/iso-8859-4.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/iso-8859-5.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/iso-8859-7.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/iso-8859-8.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/iso-8859-9.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/windows-1250.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/windows-1252.encbin0 -> 1072 bytes
-rw-r--r--Parser/Encodings/x-euc-jp-jisx0221.encbin0 -> 37890 bytes
-rw-r--r--Parser/Encodings/x-euc-jp-unicode.encbin0 -> 37890 bytes
-rw-r--r--Parser/Encodings/x-sjis-cp932.encbin0 -> 20368 bytes
-rw-r--r--Parser/Encodings/x-sjis-jdk117.encbin0 -> 18202 bytes
-rw-r--r--Parser/Encodings/x-sjis-jisx0221.encbin0 -> 18202 bytes
-rw-r--r--Parser/Encodings/x-sjis-unicode.encbin0 -> 18202 bytes
-rw-r--r--Parser/LWPExternEnt.pl71
-rw-r--r--Parser/Style/Debug.pm52
-rw-r--r--Parser/Style/Objects.pm78
-rw-r--r--Parser/Style/Stream.pm184
-rw-r--r--Parser/Style/Subs.pm58
-rw-r--r--Parser/Style/Tree.pm90
-rw-r--r--README86
-rw-r--r--samples/REC-xml-19980210.xml4197
-rwxr-xr-xsamples/canonical124
-rw-r--r--samples/canontst.xml20
-rw-r--r--samples/ctest.dtd2
-rwxr-xr-xsamples/xmlcomments44
-rwxr-xr-xsamples/xmlfilter329
-rwxr-xr-xsamples/xmlstats186
-rw-r--r--t/astress.t264
-rw-r--r--t/cdata.t40
-rw-r--r--t/decl.t166
-rw-r--r--t/defaulted.t50
-rw-r--r--t/encoding.t110
-rw-r--r--t/ext.ent1
-rw-r--r--t/ext2.ent1
-rw-r--r--t/external_ent.t70
-rw-r--r--t/file.t15
-rw-r--r--t/finish.t32
-rw-r--r--t/foo.dtd20
-rw-r--r--t/namespaces.t133
-rw-r--r--t/parament.t117
-rw-r--r--t/partial.t40
-rw-r--r--t/skip.t53
-rw-r--r--t/stream.t50
-rw-r--r--t/styles.t62
60 files changed, 12020 insertions, 0 deletions
diff --git a/Changes b/Changes
new file mode 100644
index 0000000..f4b235f
--- /dev/null
+++ b/Changes
@@ -0,0 +1,494 @@
+Revision history for Perl extension XML::Parser.
+
+2.36
+ - Fix for Carp::Heavy bugs
+
+2.35
+ - Works in 5.10 (Andreas J. Koenig)
+ - Added license in Makefile.PL (Alexandr Ciornii)
+ - Makefile.PL also searches for expat in C:/lib/Expat-2.0.0 (Alexandr Ciornii)
+ - No longer uses variable named 'namespace' in Expat.xs (Jeff Hunter)
+
+2.33
+ - Fixed Tree style (grantm)
+ - Fixed some non-utf8 stuff in DTDs (patch in XML::DOM tarball)
+
+2.32
+ - Memory leak fix (Juerd Waalboer).
+ - Added windows-1252 encoding
+ - Styles moved to separate .pm files to make loading faster and
+ ease maintainence
+ - Don't load IO::Handle unless we really need to
+
+2.31 Tue Apr 2 13:39:51 EST 2002
+ - Ilya Zakharevich <ilya@math.ohio-state.edu> and
+ Dave Mitchell <davem@fdgroup.com> both provided patches to
+ fix problems module had with 5.8.0
+ - Dave Mitchell also made some UTF-8 related fixes to the test suite.
+2.30 Thu Oct 5 12:47:36 EDT 2000
+ - Get rid of ContentStash global. Not that big a deal looking it up
+ everytime and gets rid of a potential threading problem.
+ - Switch to shareable library version of expat from sourceforge
+ (i.e. no longer include expat source and require that libexpat
+ be installed)
+ - Bob Tribit <btribit@traffic.com> demonstrated a fix for problems
+ in compiling under perl 5.6.0 with 5.005 threading.
+ - Matt Sergeant <matt@sergeant.org> discovered a typo ('IO::Handler'
+ instead of 'IO::Handle') in Expat.pm that caused IO::Handle objects
+ to be treated as strings instead of handles.
+ - Matt Sergeant also provided a patch to allow tied handles to work
+ properly in calls to parse.
+ - Eric Bohlman <ebohlman@netcom.com> reported a failure when
+ incremental parsing and external parsing were used together.
+ Need to give explicit package when calling Do_External_Parse
+ from externalEntityRef otherwise fails when called through ExpatNB.
+2.29 Sun May 21 21:19:45 EDT 2000
+ - In expat, notation declaration handler registration wasn't
+ surviving through external entity references.
+ - Chase Tingley <tingley@sundell.net> discovered that text
+ accumulation in the Stream style wasn't working across processing
+ instructions and recommended the appropriate fix.
+ - Jochen Wiedmann <jochen.wiedmann@softwareag.com>, noted that
+ you couldn't use ExpatNB directly because it wasn't setting
+ the protective _State_ variable. Now doing this in the
+ parse_more method of ExpatNB.
+ - At the suggestion of Grant Hopwood <hopwoodg@valero.com>, now
+ calling the env_proxy method on the LWP::UserAgent in the LWP
+ external entity handler when it's created to set any proxies
+ from environment variables.
+ - Grant McLean, Matt Sergeant (& others I may have missed) noted that
+ loading the LWP & URI modules slowed startup of the module, even
+ if the application didn't need it. The default LWP handler is now
+ dynamicly loaded (along with LWP & URI modules) the first time an
+ external entity is referenced. Also provided a NoLWP option to
+ XML::Parser that forces the file based external entity handler.
+ - Fixed allocation errors in element declaration patches in expat
+ - The Expat base method now works, even before expat starts parsing.
+ - Changed the canonical script to take an optional file argument.
+ - Enno Derksen <enno@att.com> reported that the attlist handler
+ was not returning NOTATION type attlist information.
+ - Michel Rodriguez <mrodrigu@ieee.org>, noted that the constructor
+ for XML::Parser objects no longer checked for the existence of
+ applications installed external entity handlers before installing
+ the default ones.
+ - Burkhard Meier <burkhard.meier@ixos.de> sent in a fix for
+ compiler directives in Expat/Makefile.PL for Win32 machines.
+ A change in 5.6.0 caused the old conditional to fail.
+ - Forgot to document changes to the Entity declaration handler:
+ there is an additional "IsParam" argument that indicates whether
+ or not the entity is a parameter entity. This information is
+ no longer passed on in the name.
+ - Ben Low <ben@snrc.uow.edu.au> reported an undefined macro with
+ version 5.004_04.
+2.28 Mon Mar 27 21:21:50 EST 2000
+ - Junked local (Expat.xs) declaration parsing and patched expat to
+ handle XML declarations, element declarations, attlist declarations,
+ and all entity declarations. By eliminating both shadow buffers and
+ local declaration parsing in Expat.xs, I've eliminated the two most
+ common sources of serious bugs in the expat interface.
+ o thus fixed the segfault and parse position bugs reported by
+ Ivan Kurmanov <iku@fnmail.com>
+ o and the doctype bug reported by Kevin Lund
+ <Kevin.Lund@westgroup.com>
+ o The element declaration handler no longer receives a string,
+ but an XML::Parser::ContentModel object that represents the
+ parsed model, but still looks like a string if referred to as
+ a string. This class is documented in the XML::Parser::Expat
+ pod under "XML::Parser::ContentModel Methods".
+ o The doctype declaration handler no longer receives the internal
+ subset as a string, but in its place a true or undef value
+ indicating whether or not there is an internal subset. Also,
+ it's called prior to processing either the internal or external
+ DTD subset (as suggested by Enno Derksen <enno@att.com>.)
+ o There is a new DoctypeFin handler that's called after finishing
+ parsing all of the DOCTYPE declaration, including any internal
+ or external DTD declarations.
+ o One bit of lossage is that recognized_string, original_string,
+ and default_current no longer work inside declaration handlers.
+ - Added a handler that gets called after parsing external entities:
+ ExternEntFin. Suggested by Jeff Horner <jhorner@netcentral.net>.
+ - parsefile, file_ext_ent_handler, & lwp_ext_ent_handler now all
+ set the base path. This problem has been raised more than once
+ and I'm not sure to whom credit should be given.
+ - The file_ext_ent_handler now opens a file handle instead of
+ reading the entire entity at once.
+ - Merged patches supplied by Larry Wall to (for perl 5.6 and beyond)
+ tag generated strings as UTF-8, where appropriate.
+ - Fixed a bug in xml_escape reported by Jerry Geiger <jgeiger@rios.de>.
+ It failed when requesting escaping of perl regex meta-characters.
+ - Laurent Caprani <caprani@pop.multimania.com> reported a bug in the
+ Proc handler for the Debug style.
+ - <chocolateboy@usa.net> sent in a patch for the element index
+ mechanism. I was popping the stack too soon in the endElement fcn.
+ - Jim Miner <jfm@winternet.com> sent in a patch to fix a warning in
+ Expat.pm.
+ - Kurt Starsinic pointed out that the eval used to check for string
+ versus IO handle was leaving $@ dirty, thereby foiling higher
+ level exception handlers
+ - An expat question by Paul Prescod <paul@prescod.net> helped me
+ see that exeptions in the parse call bypass the Expat release method,
+ causing memory leaks.
+ - Mark D. Anderson <mda@discerning.com> noted that calling
+ recognized_string from the Final method caused a dump. There are
+ a bunch of methods that should not be called after parsing has
+ finished. These now have protective if statements around them.
+ - Updated canonical utility to conform to newer version of Canonical
+ XML working draft.
+2.27 Sat Sep 25 18:26:44 EDT 1999
+ - Corrected documentation in Parser.pm
+ - Deal with XML_NS and XML_BYTE_ORDER macros in Expat/Makefile.PL
+ - Chris Thorman <chris@thorman.com> noted that "require 'URI::URL.pm'"
+ in Parser.pm was in error (should be "require 'URI/URL.pm'")
+ - Andrew McNaughton <andrew@scoop.co.nz> noted "use English" and
+ use of '$&' slowed down regex handling for whole application, so
+ they were excised from XML::Parser::Expat.
+ - Work around "modification of read-only value" bug in perl 5.004
+ - Enno Derksen <enno@att.com> reported that the Doctype handler
+ wasn't being called when ParseParamEnt was set.
+ - Now using Version 19990728 of expat, with local patches.
+ - Got rid of shadow buffer
+ o thus fixed the error reported by Ashley Sanders
+ <a.sanders@mcc.ac.uk>
+ o and removed ExpatNB limitations that Peter Billam
+ <music@pjb.com.au> noted.
+ - Vadim Konovalov <vkonovalov@lucent.com> had a problem compiling
+ for multi-threading that was fixed by changing Perl_sv_setsv to
+ sv_setsv.
+ - Added new Expat method: skip_until(index)
+ - Backward incompatible change to method xml_escape: to get former
+ behavior use $xp->xml_escape($string, '>', ...)
+ - Added utility, canonical, to samples
+2.26 Sun Jul 25 19:06:41 EDT 1999
+ - Ken Beesley <ken.beesley@xrce.xerox.com> discovered that
+ declarations in the external subset are not sent to registered
+ handlers when there is no internal subset.
+ - Fixed parse_dtd to work when entity values or attribute defaults
+ are so large that they might be broken across multiple calls to
+ the default handler.
+ - For lwp_ext_ent_handler, use URI::URL instead of URI so that old
+ 5.004 installations will work with it.
+2.25 Fri Jul 23 06:23:43 EDT 1999
+ - Now using Version 1990709 of expat. No local patches.
+ - Numerous people reported a SEGV problem when running t/cdata
+ on various platforms and versions of perl. The problem was
+ introduced with the setHandlers change. In some cases an
+ un-initialized value was being returned.
+ - Added an additional external entity handler, lwp_ext_ent_handler,
+ that deals with general URIs. It is installed instead of the
+ "file only" handler if the LWP package is installed.
+2.24 Thu Jul 8 23:05:50 EDT 1999
+ - KangChan Lee <dolphin@comeng.chungnam.ac.kr> supplied the
+ EUC-KR encoding map.
+ - Enno Derksen <enno@att.com> forwarded reports by Jon Eisenzopf
+ <eisen@pobox.com> and Stefaan Onderbeke <onderbes@bec.bel.alcatel.be>
+ about a core dump using XML::DOM. This was due to a bug in the
+ prolog parsing part of XML::Parser.
+ - Loic Dachary <loic@ceic.com> discovered that changing G_DISCARD to
+ G_VOID introduced a small memory leak. Changed G_VOID back to
+ G_DISCARD.
+ - As suggested by Ben Holzman <bholzman@earthlink.net>, the
+ setHandlers methods of both Parser and Expat now return lists that
+ consist of type, handler pairs that correspond to the input, but
+ the handlers returned are the ones that were in effect prior to
+ the call.
+ - Now using Version 19990626 of expat with a local patch (provided
+ by James Clark.)
+ - Added option ParseParamEnt. When set to a true value, parameter
+ entities are parsed and the external DTD is read (unless standalone
+ set to "Yes" in document).
+2.23 Mon Apr 26 21:30:28 EDT 1999
+ - Fixed a bug in the ExpatNB class reported by Gabe Beged-Dov
+ <begeddov@jfinity.com>. The ErrorMessage attribute wasn't
+ being initialized for ExpatNB. This should have been done in
+ the Expat constructor.
+ - Applied patch provided by Nathan Kurz <nate@valleytel.net> to
+ fix more perl stack manipulation errors in Expat.xs.
+ - Applied another patch by Nathan to change perl_call_sv flag
+ from G_DISCARD to G_VOID for callbacks, which helps performance.
+ - Murata Makoto <murata@apsdc.ksp.fujixerox.co.jp> reported a
+ problem on Win32 platforms that only showed up when UTF-16 was
+ being used. The needed call to binmode was added to the parsefile
+ methods.
+ - Added documentation for release method that was added in release
+ 2.20 to Expat pod. (Point raised by <mookie@undef.com>)
+ - Now using Version 19990425 of expat. No local patches.
+ - Added specified_attr method and made ineffective the is_defaulted
+ method.
+2.22 Sun Apr 4 11:47:25 EDT 1999
+ - Loic Dachary <loic@ceic.com> reported a core dump with a small
+ file with a comment that wasn't properly closed. Fixed in expat
+ by updating positionPtr properly in final call of XML_Parse.
+ (Reported to & acknowledged by James Clark.)
+ - Made more fixes to Expat.xs position calculation.
+ - Loic Dachary <loic@ceic.com> provided patches for fixing a
+ memory growth problem with large documents. (Garbage collection
+ wasn't happening frequently enough.)
+ - As suggested by Gabe Beged-Dov <begeddov@jfinity.com>, added
+ a non-blocking parse mechanism:
+ - Added parse_start method to XML::Parser, which returns a
+ XML::Parser::ExpatNB object.
+ - Added XML::Parser::ExpatNB class, which is a subclass of
+ Expat and has the additional methods parse_more & parse_done
+ - Made some performance tweaks as suggested by performance thread
+ on perl-xml discussion list. [With negligible results]
+ - Tried to clarify Tree style structure in Parser pod
+2.21 Sun Mar 21 17:42:04 EST 1999
+ - Warren Vik <wvik@whitebarn.com> provided patches for a bug
+ introduced with the is_defaulted method. It manifested itself
+ by bogusly reporting duplicate attributes.
+ - Now using latest expat from ftp://ftp.jclark.com/pub/test/expat.zip,
+ Version 19990307. (Plus any patches in Expat/expat.patches.)
+ - As suggested by Tim Bray, added an xml_escape method to
+ Expat.
+ - Murray Nesbitt <murray@activestate.com> had build problems
+ on Win32 that were solved by swapping 2 include files in
+ Expat.xs
+ - Added following Expat namespace methods:
+ new_ns_prefixes
+ expand_ns_prefix
+ current_ns_prefixes
+ - Fixed memory handling in recognized_string method to get rid
+ of "Attempt to free unreferenced scalar" bug.
+2.20 Sun Feb 28 15:35:52 EST 1999
+ - Fixed miscellaneous bugs in xmlfilter.
+ - In the default external entity handler, prepend the base only
+ for relative URLs.
+ - Chris Nandor <pudge@pobox.com> provided patches for building
+ on Macintosh.
+ - As suggested by Matt Sergeant <Matthew.Sergeant@eml.ericsson.se>,
+ added the finish method to Expat.
+ - Matt also provided a fix to a bug he discovered in the Streams
+ style.
+ - Fixed a parse position bug reported by Enno Derksen <enno@att.com>
+ that was affecting both original_string and position_in_context.
+ - Fixed a gross memory leak reported by David Megginson,
+ <david@megginson.com>: there was a circular reference to the Expat
+ object and the internal end handler for context was not freeing
+ element names after they were removed from the context stack.
+ - Now using expat Version 19990109
+ (Plus any patches in Expat/expat.patches)
+ - Added is_defaulted method to Expat to tell if an attribute
+ was defaulted. (Requested by Enno Derksen for XML::DOM.)
+ - Matt Sergeant <Matthew.Sergeant@eml.ericcson.se> reported that
+ the XML::Parser parse methods weren't propagating array context
+ to the Final handler. Now they are.
+ - Fixed more memory leaks (again reported by David Megginson).
+ The SVs pointing to the handlers weren't being reclaimed when
+ the callback vector was freed.
+ - Added the element_index method to Expat.
+2.19 Sun Jan 3 11:23:45 EST 1999
+ - When the recognized string is long enough, expat uses multiple
+ calls to reportDefault. Fixed recString handler in Expat.xs to
+ deal with this properly.
+ - Added original_string method to Expat. This returns the untranslated
+ string (i.e. original encoding) that caused current event.
+ - Alberto Accomazzi <alberto@cfa0.harvard.edu> sent in more patches
+ for perl5.005_54 incompatibilities.
+ - Alberto also fingered a nasty memory bug in Expat.xs that arose
+ sometimes when you registered a declaration handler but no
+ default handler. It would give you a "Not a CODE reference"
+ error in a place that wasn't using any CODE references.
+ - <schinder@pobox.com> reported a problem with compiling expat
+ on a Sun 4 due to non-exsitance of memmove on that OS. Provided
+ a workaround in Makefile.PL
+ - Now using expat Version 19981231 from James Clark's test directory.
+ - Made patch to this version in order to support original_string
+ (see Expat/expat.patches.)
+ - Added CdataStart and CdataEnd handlers to expat.
+2.18 Sun Dec 27 07:39:23 EST 1998
+ - Alberto Accomazzi <alberto@cfa0.harvard.edu> pointed out that
+ the DESTROY sub in the new XML::Parser::Encinfo package was
+ pointing to the wrong package for calling FreeEncoding.
+ - Tarang Kumar Patel <mombasa@ptolemy.arc.nasa.gov> reported
+ the mis-declaration of an integer as unsigned in the
+ convert_to_unicode function in Expat.xs.
+ - Glenn R. Kronschnabl <grk@arlut.utexas.edu> reported a problem
+ with ExternEnt handlers when using parsefile. Turned out to be
+ an unmatched ENTER; SAVETMPS pair that screwed up the Perl stack.
+ - Tom Hughes <tom@compton.demon.co.uk> reported that the fix I put
+ in for the swith to PL_sv.. names failed with 5.0005_54, since
+ these became real variables instead of macros. Switched to just
+ checking the PATCHLEVEL macro.
+ - Yoshida Masato <yoshidam@inse.co.jp> provided the EUC-JP encodings
+ (the corresponding XML files are in XML::Encoding 1.01 or later.)
+ - With the advice of MURATA Makoto <murata@apsdc.ksp.fujixerox.co.jp>,
+ removed the Shift_JIS encoding and replaced it with 4 variations
+ he provided. He also provided an explanatory message.
+ - Added the recognized_string method to Expat, deprecating
+ default_current.
+ - Now using expat Version 19981122 from James Clark's test directory
+ (this fixes another bug with external entity reference handlers)
+ - Added a default external entity handler that only accesses file:
+ based URLs.
+2.17 Sun Dec 13 17:39:58 EST 1998
+ - Replaced uses of malloc, realloc, and free with New, Renew,
+ and Safefree respectively
+ - In Expat.pm, fixed methods in_element and within_element to
+ work correctly with namespaces.
+ - xmlfilter - Substitute quoted equivalents for special characters
+ in attribute values.
+ - position_in_context was off by one line when position was at
+ the end of line.
+ - For the context methods in Expat.pm, do the right thing when
+ the context list is empty.
+ - Added methods xpcroak and xpcarp to Expat.
+ - Alberto Accomazzi <alberto@cfa0.harvard.edu> noted that perl
+ releases 5.005_5* (the pre 5.006 development versions) won't
+ accept sv_undef (and related constants) anymore and we have
+ to switch to PL_sv_...
+ - Alberto also reported a warning in the newer versions of
+ IO::Handle about input_record_separator not being treated on
+ a per-handle basis.
+ - Fixed bug that Jon Udell <udell@top.monad.net> reported in
+ Stream style: Text handler most of the time didn't see proper
+ context.
+ - Added XML::Parser::Expat::load_encoding function and support
+ for external encodings.
+2.16 Tue Oct 27 22:27:33 EST 1998
+ - Fixed bug reported by Enno Derksen <enno@att.com>:
+ Now treats parameter entity declarations correctly. The entity
+ handler sees the name beginning with '%' if it's a parameter
+ entity declaration.
+ - Nigel Hutchison <nwoh@software-ag.de> pointed out that stream.t
+ wasn't portable off Unix systems. Replaced with portable version.
+ - Fixed bug reported by Enno Derksen <enno@att.com>:
+ XML Declaration was firing off both XMLDecl handler *and* Default
+ handler.
+ - Added option NoExpand to Expat to turn off expansion of entity
+ references when a default handler is set.
+2.15 Tue Oct 20 14:50:11 EDT 1998
+ - In Expat's parse method, account for undefined previous
+ record separators.
+ - Simplify a couple of Expat methods.
+ - Re-ordered Changes entries to put latest changes first.
+ - In XML::Parser::new, set Handlers if not already set
+ - New Handler (XMLDecl) for handling XML declarations
+ - New Handler (Doctype) for handling DOCTYPE declarations
+ - New Handler (Entity) for handling ENTITY declarations in
+ the internal subset.
+ - New Handler (Element) for handling ELEMENT declarations in
+ the internal subset.
+ - New Handler (Attlist) for handling ATTLIST declarations in
+ the internal subset.
+ - Documented new handlers
+ - Added t/decl.t to test new handlers
+2.14 Sun Oct 11 22:17:15 EDT 1998
+ - Always use method calls for streams.
+ - Use perl's input_record_separator to find delimiter (i.e. each
+ "line" is an entire XML doc with delimiter appended)
+ - Deal with line being longer than buffer.
+2.13 Thu Oct 8 16:58:39 EDT 1998
+ - Fixed a major oops in Expat.xs where I was trying to decrement
+ a refcnt on an unallocated SV, leading to a segment violation.
+ (Why did this show up on HPUX but not Linux?)
+2.12 Thu Oct 8 00:05:10 EDT 1998
+ - Incorporated fix to t/astress.t from <fletch@phydeaux.org> (Mike
+ Fletcher).
+ - Change to xmlstats from <dblack@candle.superlink.net> (David
+ Alan Black)
+ - Access Handlers_Setters in Expat and Handler_Types in Parser
+ through object reference (following admonition in perltoot
+ about class data.)
+ - Added Stream_Delimiter option to Expat.
+ - In the parse_stream function in Expat.xs, if we either have a
+ Stream_Delimiter or if there's no file descriptor, use method
+ calls instead. For Stream_Delimiter in particular, the function
+ now uses the getline method so it can check for the delimiter
+ without consuming stuff past the delimiter from the stream.
+2.11 Sun Oct 4 22:15:53 EDT 1998
+ - Swapped out local patch for expat and swapped in James Clark's
+ patch.
+ - Pass on all Parser attributes (other than those excluded by
+ Non_Expat_Options) to the instance of Expat created at parse time.
+ - New method for Expat: generate_ns_name
+ - Split test.pl into t/*.t and change Makefile.PL so we don't do a
+ useless descent into Expat subdir for testing.
+ - Stop the numeric warning for eq_name and namespace method.
+2.10 Fri Sep 25 18:36:46 EDT 1998
+ - Uses expat Version 19980924
+ (with local patch - see Expat/expat/xmlparse/xmlparse.c.diff)
+ - Use newSVpvn when PERL_VERSION >= 5.005
+ - Completed xmlfilter
+ - Added support for namespace processing:
+ o Namespaces option to XML::Parser and XML::Parser::Expat
+ o Two new methods in Expat:
+ namespace - to return namespace associated with name
+ eq_name - compare 2 names for equality across namespaces.
+ - Use expat's new SetDefaultHandlerExpand instead of SetDefaultHandler
+ so that entity expansion may continue even if the default handler
+ is set.
+ - Moved test.pl back up main level and changed to work with XML::Parser
+ - Added tests for namespaces
+2.09 Fri Sep 18 10:33:38 EDT 1998
+ - Fixed errors that caused -w to fret in XML::Parser.
+ - Fixed depth method in XML::Parser::Expat
+ - There were a few places in Expat.xs where garbage strings may
+ have been returned due to the expat library giving us zero-length
+ strings. Fixed by using a local version of newSVpv where length
+ means length, even when zero.
+ - The default handler setter in Expat.xs, was inappropriately setting
+ cbv->dflt_sv when there was a null handler.
+2.08 Thu Sep 17 11:47:13 EDT 1998
+ - Make XML::Parser higher-level re-usable parser objects. Old object
+ now becomes XML::Parser::Expat.
+ - The XML::Parser object now supports the style mechanism very close
+ to that in the 1.0 version.
+2.07 Wed Sep 9 11:03:43 EDT 1998
+ - Added some samples (xmlcomments & xmlstats)
+ - Now requires 5.004 (due to sv_catpvf)
+ - Changed Makefile.PL to allow automatic manification
+ - Added a test that reads xml spec (to check buffer boundary errors)
+2.06 Tue Sep 1 10:40:41 EDT 1998
+ - Fixed the methods current_line, current_byte, and current_column
+ - Added some tests
+2.05 Mon Aug 31 15:29:42 EDT 1998
+ - Made Makefile.PL changes suggested by Murray Nesbitt
+ <murray@ActiveState.com> to support building on Win32
+ and for making PPM binaries.
+ - Added method parse
+ - Changed parsestring and parsefile to use new parse method
+ - Deprecated parsestring method
+ - Improved error handling in the ExternEnt handler
+2.04 Wed Aug 26 13:25:01 EDT 1998
+ - Uses expat Version 1.0 of August 14, 1998
+ - Some document changes
+ - Changed dist section in Makefile.PL
+ - Added ExternEnt handler
+ - Added tests for ExternEnt
+2.03 Fri Aug 21 17:19:26 EDT 1998
+ - Changed InitEncoding to ProtocolEncoding. Default to none.
+ Pass null string to expat's ParserCreate when there is no
+ ProtocolEncoding.
+ - Fixed bug in parsefile & parsestring where they were referring
+ to an ErrorContext *method* instead of a field.
+ - Fixed position_in_context bugs:
+ -- 'last' in do {} while ();
+ -- insert newline before pointer when no following newline
+ in buffer.
+ - Added some additional tests
+2.02 Thu Aug 20 14:05:08 EDT 1998
+ - Fixed parsefile problem reported by
+ "Robert Hanson" <robertha@zenweb.com>, using a modification of
+ his suggested fix.
+ - Responded to problem reported by
+ Bart Schuller <schuller+perl-xml@lunatech.com>
+ by pre-expanding parts of the XML_UPD macro to avoid confusing
+ some versions of gcc.
+ - Changed the constructor to take the option InitEncoding, which
+ gets passed to the ParserCreate call. When not given, defaults
+ to UTF-8.
+ - Added method position_in_context
+ - Added Constructor option ErrorContext and added reporting of
+ errors in context.
+2.01 Wed Aug 19 11:42:42 EDT 1998
+ - Added methods:
+ default_current, base, current_line, current_column,
+ current_byte, context
+ - Added some tests
+ - parsestring and parsefile now croak if they're re-used
+ - Filled in some documentation
+2.00 Mon Aug 17 12:01:33 EDT 1998
+ - repackaged with James Clark's most recent expat
+ - changed to an API closer to expat
+1.00 March 1998
+ - Larry Wall's original version
diff --git a/Expat/Expat.pm b/Expat/Expat.pm
new file mode 100644
index 0000000..9413d80
--- /dev/null
+++ b/Expat/Expat.pm
@@ -0,0 +1,1230 @@
+package XML::Parser::Expat;
+
+require 5.004;
+
+use strict;
+use vars qw($VERSION @ISA %Handler_Setters %Encoding_Table @Encoding_Path
+ $have_File_Spec);
+use Carp;
+
+require DynaLoader;
+
+@ISA = qw(DynaLoader);
+$VERSION = "2.36" ;
+
+$have_File_Spec = $INC{'File/Spec.pm'} || do 'File/Spec.pm';
+
+%Encoding_Table = ();
+if ($have_File_Spec) {
+ @Encoding_Path = (grep(-d $_,
+ map(File::Spec->catdir($_, qw(XML Parser Encodings)),
+ @INC)),
+ File::Spec->curdir);
+}
+else {
+ @Encoding_Path = (grep(-d $_, map($_ . '/XML/Parser/Encodings', @INC)), '.');
+}
+
+
+bootstrap XML::Parser::Expat $VERSION;
+
+%Handler_Setters = (
+ Start => \&SetStartElementHandler,
+ End => \&SetEndElementHandler,
+ Char => \&SetCharacterDataHandler,
+ Proc => \&SetProcessingInstructionHandler,
+ Comment => \&SetCommentHandler,
+ CdataStart => \&SetStartCdataHandler,
+ CdataEnd => \&SetEndCdataHandler,
+ Default => \&SetDefaultHandler,
+ Unparsed => \&SetUnparsedEntityDeclHandler,
+ Notation => \&SetNotationDeclHandler,
+ ExternEnt => \&SetExternalEntityRefHandler,
+ ExternEntFin => \&SetExtEntFinishHandler,
+ Entity => \&SetEntityDeclHandler,
+ Element => \&SetElementDeclHandler,
+ Attlist => \&SetAttListDeclHandler,
+ Doctype => \&SetDoctypeHandler,
+ DoctypeFin => \&SetEndDoctypeHandler,
+ XMLDecl => \&SetXMLDeclHandler
+ );
+
+sub new {
+ my ($class, %args) = @_;
+ my $self = bless \%args, $_[0];
+ $args{_State_} = 0;
+ $args{Context} = [];
+ $args{Namespaces} ||= 0;
+ $args{ErrorMessage} ||= '';
+ if ($args{Namespaces}) {
+ $args{Namespace_Table} = {};
+ $args{Namespace_List} = [undef];
+ $args{Prefix_Table} = {};
+ $args{New_Prefixes} = [];
+ }
+ $args{_Setters} = \%Handler_Setters;
+ $args{Parser} = ParserCreate($self, $args{ProtocolEncoding},
+ $args{Namespaces});
+ $self;
+}
+
+sub load_encoding {
+ my ($file) = @_;
+
+ $file =~ s!([^/]+)$!\L$1\E!;
+ $file .= '.enc' unless $file =~ /\.enc$/;
+ unless ($file =~ m!^/!) {
+ foreach (@Encoding_Path) {
+ my $tmp = ($have_File_Spec
+ ? File::Spec->catfile($_, $file)
+ : "$_/$file");
+ if (-e $tmp) {
+ $file = $tmp;
+ last;
+ }
+ }
+ }
+
+ local(*ENC);
+ open(ENC, $file) or croak("Couldn't open encmap $file:\n$!\n");
+ binmode(ENC);
+ my $data;
+ my $br = sysread(ENC, $data, -s $file);
+ croak("Trouble reading $file:\n$!\n")
+ unless defined($br);
+ close(ENC);
+
+ my $name = LoadEncoding($data, $br);
+ croak("$file isn't an encmap file")
+ unless defined($name);
+
+ $name;
+} # End load_encoding
+
+sub setHandlers {
+ my ($self, @handler_pairs) = @_;
+
+ croak("Uneven number of arguments to setHandlers method")
+ if (int(@handler_pairs) & 1);
+
+ my @ret;
+
+ while (@handler_pairs) {
+ my $type = shift @handler_pairs;
+ my $handler = shift @handler_pairs;
+ croak "Handler for $type not a Code ref"
+ unless (! defined($handler) or ! $handler or ref($handler) eq 'CODE');
+
+ my $hndl = $self->{_Setters}->{$type};
+
+ unless (defined($hndl)) {
+ my @types = sort keys %{$self->{_Setters}};
+ croak("Unknown Expat handler type: $type\n Valid types: @types");
+ }
+
+ my $old = &$hndl($self->{Parser}, $handler);
+ push (@ret, $type, $old);
+ }
+
+ return @ret;
+}
+
+sub xpcroak
+ {
+ my ($self, $message) = @_;
+
+ my $eclines = $self->{ErrorContext};
+ my $line = GetCurrentLineNumber($_[0]->{Parser});
+ $message .= " at line $line";
+ $message .= ":\n" . $self->position_in_context($eclines)
+ if defined($eclines);
+ croak $message;
+}
+
+sub xpcarp {
+ my ($self, $message) = @_;
+
+ my $eclines = $self->{ErrorContext};
+ my $line = GetCurrentLineNumber($_[0]->{Parser});
+ $message .= " at line $line";
+ $message .= ":\n" . $self->position_in_context($eclines)
+ if defined($eclines);
+ carp $message;
+}
+
+sub default_current {
+ my $self = shift;
+ if ($self->{_State_} == 1) {
+ return DefaultCurrent($self->{Parser});
+ }
+}
+
+sub recognized_string {
+ my $self = shift;
+ if ($self->{_State_} == 1) {
+ return RecognizedString($self->{Parser});
+ }
+}
+
+sub original_string {
+ my $self = shift;
+ if ($self->{_State_} == 1) {
+ return OriginalString($self->{Parser});
+ }
+}
+
+sub current_line {
+ my $self = shift;
+ if ($self->{_State_} == 1) {
+ return GetCurrentLineNumber($self->{Parser});
+ }
+}
+
+sub current_column {
+ my $self = shift;
+ if ($self->{_State_} == 1) {
+ return GetCurrentColumnNumber($self->{Parser});
+ }
+}
+
+sub current_byte {
+ my $self = shift;
+ if ($self->{_State_} == 1) {
+ return GetCurrentByteIndex($self->{Parser});
+ }
+}
+
+sub base {
+ my ($self, $newbase) = @_;
+ my $p = $self->{Parser};
+ my $oldbase = GetBase($p);
+ SetBase($p, $newbase) if @_ > 1;
+ return $oldbase;
+}
+
+sub context {
+ my $ctx = $_[0]->{Context};
+ @$ctx;
+}
+
+sub current_element {
+ my ($self) = @_;
+ @{$self->{Context}} ? $self->{Context}->[-1] : undef;
+}
+
+sub in_element {
+ my ($self, $element) = @_;
+ @{$self->{Context}} ? $self->eq_name($self->{Context}->[-1], $element)
+ : undef;
+}
+
+sub within_element {
+ my ($self, $element) = @_;
+ my $cnt = 0;
+ foreach (@{$self->{Context}}) {
+ $cnt++ if $self->eq_name($_, $element);
+ }
+ return $cnt;
+}
+
+sub depth {
+ my ($self) = @_;
+ int(@{$self->{Context}});
+}
+
+sub element_index {
+ my ($self) = @_;
+
+ if ($self->{_State_} == 1) {
+ return ElementIndex($self->{Parser});
+ }
+}
+
+################
+# Namespace methods
+
+sub namespace {
+ my ($self, $name) = @_;
+ local($^W) = 0;
+ $self->{Namespace_List}->[int($name)];
+}
+
+sub eq_name {
+ my ($self, $nm1, $nm2) = @_;
+ local($^W) = 0;
+
+ int($nm1) == int($nm2) and $nm1 eq $nm2;
+}
+
+sub generate_ns_name {
+ my ($self, $name, $namespace) = @_;
+
+ $namespace ?
+ GenerateNSName($name, $namespace, $self->{Namespace_Table},
+ $self->{Namespace_List})
+ : $name;
+}
+
+sub new_ns_prefixes {
+ my ($self) = @_;
+ if ($self->{Namespaces}) {
+ return @{$self->{New_Prefixes}};
+ }
+ return ();
+}
+
+sub expand_ns_prefix {
+ my ($self, $prefix) = @_;
+
+ if ($self->{Namespaces}) {
+ my $stack = $self->{Prefix_Table}->{$prefix};
+ return (defined($stack) and @$stack) ? $stack->[-1] : undef;
+ }
+
+ return undef;
+}
+
+sub current_ns_prefixes {
+ my ($self) = @_;
+
+ if ($self->{Namespaces}) {
+ my %set = %{$self->{Prefix_Table}};
+
+ if (exists $set{'#default'} and not defined($set{'#default'}->[-1])) {
+ delete $set{'#default'};
+ }
+
+ return keys %set;
+ }
+
+ return ();
+}
+
+
+################################################################
+# Namespace declaration handlers
+#
+
+sub NamespaceStart {
+ my ($self, $prefix, $uri) = @_;
+
+ $prefix = '#default' unless defined $prefix;
+ my $stack = $self->{Prefix_Table}->{$prefix};
+
+ if (defined $stack) {
+ push(@$stack, $uri);
+ }
+ else {
+ $self->{Prefix_Table}->{$prefix} = [$uri];
+ }
+
+ # The New_Prefixes list gets emptied at end of startElement function
+ # in Expat.xs
+
+ push(@{$self->{New_Prefixes}}, $prefix);
+}
+
+sub NamespaceEnd {
+ my ($self, $prefix) = @_;
+
+ $prefix = '#default' unless defined $prefix;
+
+ my $stack = $self->{Prefix_Table}->{$prefix};
+ if (@$stack > 1) {
+ pop(@$stack);
+ }
+ else {
+ delete $self->{Prefix_Table}->{$prefix};
+ }
+}
+
+################
+
+sub specified_attr {
+ my $self = shift;
+
+ if ($self->{_State_} == 1) {
+ return GetSpecifiedAttributeCount($self->{Parser});
+ }
+}
+
+sub finish {
+ my ($self) = @_;
+ if ($self->{_State_} == 1) {
+ my $parser = $self->{Parser};
+ UnsetAllHandlers($parser);
+ }
+}
+
+sub position_in_context {
+ my ($self, $lines) = @_;
+ if ($self->{_State_} == 1) {
+ my $parser = $self->{Parser};
+ my ($string, $linepos) = PositionContext($parser, $lines);
+
+ return '' unless defined($string);
+
+ my $col = GetCurrentColumnNumber($parser);
+ my $ptr = ('=' x ($col - 1)) . '^' . "\n";
+ my $ret;
+ my $dosplit = $linepos < length($string);
+
+ $string .= "\n" unless $string =~ /\n$/;
+
+ if ($dosplit) {
+ $ret = substr($string, 0, $linepos) . $ptr
+ . substr($string, $linepos);
+ } else {
+ $ret = $string . $ptr;
+ }
+
+ return $ret;
+ }
+}
+
+sub xml_escape {
+ my $self = shift;
+ my $text = shift;
+
+ study $text;
+ $text =~ s/\&/\&amp;/g;
+ $text =~ s/</\&lt;/g;
+ foreach (@_) {
+ croak "xml_escape: '$_' isn't a single character" if length($_) > 1;
+
+ if ($_ eq '>') {
+ $text =~ s/>/\&gt;/g;
+ }
+ elsif ($_ eq '"') {
+ $text =~ s/\"/\&quot;/;
+ }
+ elsif ($_ eq "'") {
+ $text =~ s/\'/\&apos;/;
+ }
+ else {
+ my $rep = '&#' . sprintf('x%X', ord($_)) . ';';
+ if (/\W/) {
+ my $ptrn = "\\$_";
+ $text =~ s/$ptrn/$rep/g;
+ }
+ else {
+ $text =~ s/$_/$rep/g;
+ }
+ }
+ }
+ $text;
+}
+
+sub skip_until {
+ my $self = shift;
+ if ($self->{_State_} <= 1) {
+ SkipUntil($self->{Parser}, $_[0]);
+ }
+}
+
+sub release {
+ my $self = shift;
+ ParserRelease($self->{Parser});
+}
+
+sub DESTROY {
+ my $self = shift;
+ ParserFree($self->{Parser});
+}
+
+sub parse {
+ my $self = shift;
+ my $arg = shift;
+ croak "Parse already in progress (Expat)" if $self->{_State_};
+ $self->{_State_} = 1;
+ my $parser = $self->{Parser};
+ my $ioref;
+ my $result = 0;
+
+ if (defined $arg) {
+ if (ref($arg) and UNIVERSAL::isa($arg, 'IO::Handle')) {
+ $ioref = $arg;
+ } elsif (tied($arg)) {
+ my $class = ref($arg);
+ no strict 'refs';
+ $ioref = $arg if defined &{"${class}::TIEHANDLE"};
+ }
+ else {
+ require IO::Handle;
+ eval {
+ no strict 'refs';
+ $ioref = *{$arg}{IO} if defined *{$arg};
+ };
+ undef $@;
+ }
+ }
+
+ if (defined($ioref)) {
+ my $delim = $self->{Stream_Delimiter};
+ my $prev_rs;
+
+ $prev_rs = ref($ioref)->input_record_separator("\n$delim\n")
+ if defined($delim);
+
+ $result = ParseStream($parser, $ioref, $delim);
+
+ ref($ioref)->input_record_separator($prev_rs)
+ if defined($delim);
+ } else {
+ $result = ParseString($parser, $arg);
+ }
+
+ $self->{_State_} = 2;
+ $result or croak $self->{ErrorMessage};
+}
+
+sub parsestring {
+ my $self = shift;
+ $self->parse(@_);
+}
+
+sub parsefile {
+ my $self = shift;
+ croak "Parser has already been used" if $self->{_State_};
+ local(*FILE);
+ open(FILE, $_[0]) or croak "Couldn't open $_[0]:\n$!";
+ binmode(FILE);
+ my $ret = $self->parse(*FILE);
+ close(FILE);
+ $ret;
+}
+
+################################################################
+package XML::Parser::ContentModel;
+use overload '""' => \&asString, 'eq' => \&thiseq;
+
+sub EMPTY () {1}
+sub ANY () {2}
+sub MIXED () {3}
+sub NAME () {4}
+sub CHOICE () {5}
+sub SEQ () {6}
+
+
+sub isempty {
+ return $_[0]->{Type} == EMPTY;
+}
+
+sub isany {
+ return $_[0]->{Type} == ANY;
+}
+
+sub ismixed {
+ return $_[0]->{Type} == MIXED;
+}
+
+sub isname {
+ return $_[0]->{Type} == NAME;
+}
+
+sub name {
+ return $_[0]->{Tag};
+}
+
+sub ischoice {
+ return $_[0]->{Type} == CHOICE;
+}
+
+sub isseq {
+ return $_[0]->{Type} == SEQ;
+}
+
+sub quant {
+ return $_[0]->{Quant};
+}
+
+sub children {
+ my $children = $_[0]->{Children};
+ if (defined $children) {
+ return @$children;
+ }
+ return undef;
+}
+
+sub asString {
+ my ($self) = @_;
+ my $ret;
+
+ if ($self->{Type} == NAME) {
+ $ret = $self->{Tag};
+ }
+ elsif ($self->{Type} == EMPTY) {
+ return "EMPTY";
+ }
+ elsif ($self->{Type} == ANY) {
+ return "ANY";
+ }
+ elsif ($self->{Type} == MIXED) {
+ $ret = '(#PCDATA';
+ foreach (@{$self->{Children}}) {
+ $ret .= '|' . $_;
+ }
+ $ret .= ')';
+ }
+ else {
+ my $sep = $self->{Type} == CHOICE ? '|' : ',';
+ $ret = '(' . join($sep, map { $_->asString } @{$self->{Children}}) . ')';
+ }
+
+ $ret .= $self->{Quant} if $self->{Quant};
+ return $ret;
+}
+
+sub thiseq {
+ my $self = shift;
+
+ return $self->asString eq $_[0];
+}
+
+################################################################
+package XML::Parser::ExpatNB;
+
+use vars qw(@ISA);
+use Carp;
+
+@ISA = qw(XML::Parser::Expat);
+
+sub parse {
+ my $self = shift;
+ my $class = ref($self);
+ croak "parse method not supported in $class";
+}
+
+sub parsestring {
+ my $self = shift;
+ my $class = ref($self);
+ croak "parsestring method not supported in $class";
+}
+
+sub parsefile {
+ my $self = shift;
+ my $class = ref($self);
+ croak "parsefile method not supported in $class";
+}
+
+sub parse_more {
+ my ($self, $data) = @_;
+
+ $self->{_State_} = 1;
+ my $ret = XML::Parser::Expat::ParsePartial($self->{Parser}, $data);
+
+ croak $self->{ErrorMessage} unless $ret;
+}
+
+sub parse_done {
+ my $self = shift;
+
+ my $ret = XML::Parser::Expat::ParseDone($self->{Parser});
+ unless ($ret) {
+ my $msg = $self->{ErrorMessage};
+ $self->release;
+ croak $msg;
+ }
+
+ $self->{_State_} = 2;
+
+ my $result = $ret;
+ my @result = ();
+ my $final = $self->{FinalHandler};
+ if (defined $final) {
+ if (wantarray) {
+ @result = &$final($self);
+ }
+ else {
+ $result = &$final($self);
+ }
+ }
+
+ $self->release;
+
+ return unless defined wantarray;
+ return wantarray ? @result : $result;
+}
+
+################################################################
+
+package XML::Parser::Encinfo;
+
+sub DESTROY {
+ my $self = shift;
+ XML::Parser::Expat::FreeEncoding($self);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+XML::Parser::Expat - Lowlevel access to James Clark's expat XML parser
+
+=head1 SYNOPSIS
+
+ use XML::Parser::Expat;
+
+ $parser = new XML::Parser::Expat;
+ $parser->setHandlers('Start' => \&sh,
+ 'End' => \&eh,
+ 'Char' => \&ch);
+ open(FOO, 'info.xml') or die "Couldn't open";
+ $parser->parse(*FOO);
+ close(FOO);
+ # $parser->parse('<foo id="me"> here <em>we</em> go </foo>');
+
+ sub sh
+ {
+ my ($p, $el, %atts) = @_;
+ $p->setHandlers('Char' => \&spec)
+ if ($el eq 'special');
+ ...
+ }
+
+ sub eh
+ {
+ my ($p, $el) = @_;
+ $p->setHandlers('Char' => \&ch) # Special elements won't contain
+ if ($el eq 'special'); # other special elements
+ ...
+ }
+
+=head1 DESCRIPTION
+
+This module provides an interface to James Clark's XML parser, expat. As in
+expat, a single instance of the parser can only parse one document. Calls
+to parsestring after the first for a given instance will die.
+
+Expat (and XML::Parser::Expat) are event based. As the parser recognizes
+parts of the document (say the start or end of an XML element), then any
+handlers registered for that type of an event are called with suitable
+parameters.
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+This is a class method, the constructor for XML::Parser::Expat. Options are
+passed as keyword value pairs. The recognized options are:
+
+=over 4
+
+=item * ProtocolEncoding
+
+The protocol encoding name. The default is none. The expat built-in
+encodings are: C<UTF-8>, C<ISO-8859-1>, C<UTF-16>, and C<US-ASCII>.
+Other encodings may be used if they have encoding maps in one of the
+directories in the @Encoding_Path list. Setting the protocol encoding
+overrides any encoding in the XML declaration.
+
+=item * Namespaces
+
+When this option is given with a true value, then the parser does namespace
+processing. By default, namespace processing is turned off. When it is
+turned on, the parser consumes I<xmlns> attributes and strips off prefixes
+from element and attributes names where those prefixes have a defined
+namespace. A name's namespace can be found using the L<"namespace"> method
+and two names can be checked for absolute equality with the L<"eq_name">
+method.
+
+=item * NoExpand
+
+Normally, the parser will try to expand references to entities defined in
+the internal subset. If this option is set to a true value, and a default
+handler is also set, then the default handler will be called when an
+entity reference is seen in text. This has no effect if a default handler
+has not been registered, and it has no effect on the expansion of entity
+references inside attribute values.
+
+=item * Stream_Delimiter
+
+This option takes a string value. When this string is found alone on a line
+while parsing from a stream, then the parse is ended as if it saw an end of
+file. The intended use is with a stream of xml documents in a MIME multipart
+format. The string should not contain a trailing newline.
+
+=item * ErrorContext
+
+When this option is defined, errors are reported in context. The value
+of ErrorContext should be the number of lines to show on either side of
+the line in which the error occurred.
+
+=item * ParseParamEnt
+
+Unless standalone is set to "yes" in the XML declaration, setting this to
+a true value allows the external DTD to be read, and parameter entities
+to be parsed and expanded.
+
+=item * Base
+
+The base to use for relative pathnames or URLs. This can also be done by
+using the base method.
+
+=back
+
+=item setHandlers(TYPE, HANDLER [, TYPE, HANDLER [...]])
+
+This method registers handlers for the various events. If no handlers are
+registered, then a call to parsestring or parsefile will only determine if
+the corresponding XML document is well formed (by returning without error.)
+This may be called from within a handler, after the parse has started.
+
+Setting a handler to something that evaluates to false unsets that
+handler.
+
+This method returns a list of type, handler pairs corresponding to the
+input. The handlers returned are the ones that were in effect before the
+call to setHandlers.
+
+The recognized events and the parameters passed to the corresponding
+handlers are:
+
+=over 4
+
+=item * Start (Parser, Element [, Attr, Val [,...]])
+
+This event is generated when an XML start tag is recognized. Parser is
+an XML::Parser::Expat instance. Element is the name of the XML element that
+is opened with the start tag. The Attr & Val pairs are generated for each
+attribute in the start tag.
+
+=item * End (Parser, Element)
+
+This event is generated when an XML end tag is recognized. Note that
+an XML empty tag (<foo/>) generates both a start and an end event.
+
+There is always a lower level start and end handler installed that wrap
+the corresponding callbacks. This is to handle the context mechanism.
+A consequence of this is that the default handler (see below) will not
+see a start tag or end tag unless the default_current method is called.
+
+=item * Char (Parser, String)
+
+This event is generated when non-markup is recognized. The non-markup
+sequence of characters is in String. A single non-markup sequence of
+characters may generate multiple calls to this handler. Whatever the
+encoding of the string in the original document, this is given to the
+handler in UTF-8.
+
+=item * Proc (Parser, Target, Data)
+
+This event is generated when a processing instruction is recognized.
+
+=item * Comment (Parser, String)
+
+This event is generated when a comment is recognized.
+
+=item * CdataStart (Parser)
+
+This is called at the start of a CDATA section.
+
+=item * CdataEnd (Parser)
+
+This is called at the end of a CDATA section.
+
+=item * Default (Parser, String)
+
+This is called for any characters that don't have a registered handler.
+This includes both characters that are part of markup for which no
+events are generated (markup declarations) and characters that
+could generate events, but for which no handler has been registered.
+
+Whatever the encoding in the original document, the string is returned to
+the handler in UTF-8.
+
+=item * Unparsed (Parser, Entity, Base, Sysid, Pubid, Notation)
+
+This is called for a declaration of an unparsed entity. Entity is the name
+of the entity. Base is the base to be used for resolving a relative URI.
+Sysid is the system id. Pubid is the public id. Notation is the notation
+name. Base and Pubid may be undefined.
+
+=item * Notation (Parser, Notation, Base, Sysid, Pubid)
+
+This is called for a declaration of notation. Notation is the notation name.
+Base is the base to be used for resolving a relative URI. Sysid is the system
+id. Pubid is the public id. Base, Sysid, and Pubid may all be undefined.
+
+=item * ExternEnt (Parser, Base, Sysid, Pubid)
+
+This is called when an external entity is referenced. Base is the base to be
+used for resolving a relative URI. Sysid is the system id. Pubid is the public
+id. Base, and Pubid may be undefined.
+
+This handler should either return a string, which represents the contents of
+the external entity, or return an open filehandle that can be read to obtain
+the contents of the external entity, or return undef, which indicates the
+external entity couldn't be found and will generate a parse error.
+
+If an open filehandle is returned, it must be returned as either a glob
+(*FOO) or as a reference to a glob (e.g. an instance of IO::Handle).
+
+=item * ExternEntFin (Parser)
+
+This is called after an external entity has been parsed. It allows
+applications to perform cleanup on actions performed in the above
+ExternEnt handler.
+
+=item * Entity (Parser, Name, Val, Sysid, Pubid, Ndata, IsParam)
+
+This is called when an entity is declared. For internal entities, the Val
+parameter will contain the value and the remaining three parameters will
+be undefined. For external entities, the Val parameter
+will be undefined, the Sysid parameter will have the system id, the Pubid
+parameter will have the public id if it was provided (it will be undefined
+otherwise), the Ndata parameter will contain the notation for unparsed
+entities. If this is a parameter entity declaration, then the IsParam
+parameter is true.
+
+Note that this handler and the Unparsed handler above overlap. If both are
+set, then this handler will not be called for unparsed entities.
+
+=item * Element (Parser, Name, Model)
+
+The element handler is called when an element declaration is found. Name is
+the element name, and Model is the content model as an
+XML::Parser::ContentModel object. See L<"XML::Parser::ContentModel Methods">
+for methods available for this class.
+
+=item * Attlist (Parser, Elname, Attname, Type, Default, Fixed)
+
+This handler is called for each attribute in an ATTLIST declaration.
+So an ATTLIST declaration that has multiple attributes
+will generate multiple calls to this handler. The Elname parameter is the
+name of the element with which the attribute is being associated. The Attname
+parameter is the name of the attribute. Type is the attribute type, given as
+a string. Default is the default value, which will either be "#REQUIRED",
+"#IMPLIED" or a quoted string (i.e. the returned string will begin and end
+with a quote character). If Fixed is true, then this is a fixed attribute.
+
+=item * Doctype (Parser, Name, Sysid, Pubid, Internal)
+
+This handler is called for DOCTYPE declarations. Name is the document type
+name. Sysid is the system id of the document type, if it was provided,
+otherwise it's undefined. Pubid is the public id of the document type,
+which will be undefined if no public id was given. Internal will be
+true or false, indicating whether or not the doctype declaration contains
+an internal subset.
+
+=item * DoctypeFin (Parser)
+
+This handler is called after parsing of the DOCTYPE declaration has finished,
+including any internal or external DTD declarations.
+
+=item * XMLDecl (Parser, Version, Encoding, Standalone)
+
+This handler is called for XML declarations. Version is a string containg
+the version. Encoding is either undefined or contains an encoding string.
+Standalone is either undefined, or true or false. Undefined indicates
+that no standalone parameter was given in the XML declaration. True or
+false indicates "yes" or "no" respectively.
+
+=back
+
+=item namespace(name)
+
+Return the URI of the namespace that the name belongs to. If the name doesn't
+belong to any namespace, an undef is returned. This is only valid on names
+received through the Start or End handlers from a single document, or through
+a call to the generate_ns_name method. In other words, don't use names
+generated from one instance of XML::Parser::Expat with other instances.
+
+=item eq_name(name1, name2)
+
+Return true if name1 and name2 are identical (i.e. same name and from
+the same namespace.) This is only meaningful if both names were obtained
+through the Start or End handlers from a single document, or through
+a call to the generate_ns_name method.
+
+=item generate_ns_name(name, namespace)
+
+Return a name, associated with a given namespace, good for using with the
+above 2 methods. The namespace argument should be the namespace URI, not
+a prefix.
+
+=item new_ns_prefixes
+
+When called from a start tag handler, returns namespace prefixes declared
+with this start tag. If called elsewere (or if there were no namespace
+prefixes declared), it returns an empty list. Setting of the default
+namespace is indicated with '#default' as a prefix.
+
+=item expand_ns_prefix(prefix)
+
+Return the uri to which the given prefix is currently bound. Returns
+undef if the prefix isn't currently bound. Use '#default' to find the
+current binding of the default namespace (if any).
+
+=item current_ns_prefixes
+
+Return a list of currently bound namespace prefixes. The order of the
+the prefixes in the list has no meaning. If the default namespace is
+currently bound, '#default' appears in the list.
+
+=item recognized_string
+
+Returns the string from the document that was recognized in order to call
+the current handler. For instance, when called from a start handler, it
+will give us the the start-tag string. The string is encoded in UTF-8.
+This method doesn't return a meaningful string inside declaration handlers.
+
+=item original_string
+
+Returns the verbatim string from the document that was recognized in
+order to call the current handler. The string is in the original document
+encoding. This method doesn't return a meaningful string inside declaration
+handlers.
+
+=item default_current
+
+When called from a handler, causes the sequence of characters that generated
+the corresponding event to be sent to the default handler (if one is
+registered). Use of this method is deprecated in favor the recognized_string
+method, which you can use without installing a default handler. This
+method doesn't deliver a meaningful string to the default handler when
+called from inside declaration handlers.
+
+=item xpcroak(message)
+
+Concatenate onto the given message the current line number within the
+XML document plus the message implied by ErrorContext. Then croak with
+the formed message.
+
+=item xpcarp(message)
+
+Concatenate onto the given message the current line number within the
+XML document plus the message implied by ErrorContext. Then carp with
+the formed message.
+
+=item current_line
+
+Returns the line number of the current position of the parse.
+
+=item current_column
+
+Returns the column number of the current position of the parse.
+
+=item current_byte
+
+Returns the current position of the parse.
+
+=item base([NEWBASE]);
+
+Returns the current value of the base for resolving relative URIs. If
+NEWBASE is supplied, changes the base to that value.
+
+=item context
+
+Returns a list of element names that represent open elements, with the
+last one being the innermost. Inside start and end tag handlers, this
+will be the tag of the parent element.
+
+=item current_element
+
+Returns the name of the innermost currently opened element. Inside
+start or end handlers, returns the parent of the element associated
+with those tags.
+
+=item in_element(NAME)
+
+Returns true if NAME is equal to the name of the innermost currently opened
+element. If namespace processing is being used and you want to check
+against a name that may be in a namespace, then use the generate_ns_name
+method to create the NAME argument.
+
+=item within_element(NAME)
+
+Returns the number of times the given name appears in the context list.
+If namespace processing is being used and you want to check
+against a name that may be in a namespace, then use the generate_ns_name
+method to create the NAME argument.
+
+=item depth
+
+Returns the size of the context list.
+
+=item element_index
+
+Returns an integer that is the depth-first visit order of the current
+element. This will be zero outside of the root element. For example,
+this will return 1 when called from the start handler for the root element
+start tag.
+
+=item skip_until(INDEX)
+
+INDEX is an integer that represents an element index. When this method
+is called, all handlers are suspended until the start tag for an element
+that has an index number equal to INDEX is seen. If a start handler has
+been set, then this is the first tag that the start handler will see
+after skip_until has been called.
+
+
+=item position_in_context(LINES)
+
+Returns a string that shows the current parse position. LINES should be
+an integer >= 0 that represents the number of lines on either side of the
+current parse line to place into the returned string.
+
+=item xml_escape(TEXT [, CHAR [, CHAR ...]])
+
+Returns TEXT with markup characters turned into character entities. Any
+additional characters provided as arguments are also turned into character
+references where found in TEXT.
+
+=item parse (SOURCE)
+
+The SOURCE parameter should either be a string containing the whole XML
+document, or it should be an open IO::Handle. Only a single document
+may be parsed for a given instance of XML::Parser::Expat, so this will croak
+if it's been called previously for this instance.
+
+=item parsestring(XML_DOC_STRING)
+
+Parses the given string as an XML document. Only a single document may be
+parsed for a given instance of XML::Parser::Expat, so this will die if either
+parsestring or parsefile has been called for this instance previously.
+
+This method is deprecated in favor of the parse method.
+
+=item parsefile(FILENAME)
+
+Parses the XML document in the given file. Will die if parsestring or
+parsefile has been called previously for this instance.
+
+=item is_defaulted(ATTNAME)
+
+NO LONGER WORKS. To find out if an attribute is defaulted please use
+the specified_attr method.
+
+=item specified_attr
+
+When the start handler receives lists of attributes and values, the
+non-defaulted (i.e. explicitly specified) attributes occur in the list
+first. This method returns the number of specified items in the list.
+So if this number is equal to the length of the list, there were no
+defaulted values. Otherwise the number points to the index of the
+first defaulted attribute name.
+
+=item finish
+
+Unsets all handlers (including internal ones that set context), but expat
+continues parsing to the end of the document or until it finds an error.
+It should finish up a lot faster than with the handlers set.
+
+=item release
+
+There are data structures used by XML::Parser::Expat that have circular
+references. This means that these structures will never be garbage
+collected unless these references are explicitly broken. Calling this
+method breaks those references (and makes the instance unusable.)
+
+Normally, higher level calls handle this for you, but if you are using
+XML::Parser::Expat directly, then it's your responsibility to call it.
+
+=back
+
+=head2 XML::Parser::ContentModel Methods
+
+The element declaration handlers are passed objects of this class as the
+content model of the element declaration. They also represent content
+particles, components of a content model.
+
+When referred to as a string, these objects are automagicly converted to a
+string representation of the model (or content particle).
+
+=over 4
+
+=item isempty
+
+This method returns true if the object is "EMPTY", false otherwise.
+
+=item isany
+
+This method returns true if the object is "ANY", false otherwise.
+
+=item ismixed
+
+This method returns true if the object is "(#PCDATA)" or "(#PCDATA|...)*",
+false otherwise.
+
+=item isname
+
+This method returns if the object is an element name.
+
+=item ischoice
+
+This method returns true if the object is a choice of content particles.
+
+
+=item isseq
+
+This method returns true if the object is a sequence of content particles.
+
+=item quant
+
+This method returns undef or a string representing the quantifier
+('?', '*', '+') associated with the model or particle.
+
+=item children
+
+This method returns undef or (for mixed, choice, and sequence types)
+an array of component content particles. There will always be at least
+one component for choices and sequences, but for a mixed content model
+of pure PCDATA, "(#PCDATA)", then an undef is returned.
+
+=back
+
+=head2 XML::Parser::ExpatNB Methods
+
+The class XML::Parser::ExpatNB is a subclass of XML::Parser::Expat used
+for non-blocking access to the expat library. It does not support the parse,
+parsestring, or parsefile methods, but it does have these additional methods:
+
+=over 4
+
+=item parse_more(DATA)
+
+Feed expat more text to munch on.
+
+=item parse_done
+
+Tell expat that it's gotten the whole document.
+
+=back
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item XML::Parser::Expat::load_encoding(ENCODING)
+
+Load an external encoding. ENCODING is either the name of an encoding or
+the name of a file. The basename is converted to lowercase and a '.enc'
+extension is appended unless there's one already there. Then, unless
+it's an absolute pathname (i.e. begins with '/'), the first file by that
+name discovered in the @Encoding_Path path list is used.
+
+The encoding in the file is loaded and kept in the %Encoding_Table
+table. Earlier encodings of the same name are replaced.
+
+This function is automaticly called by expat when it encounters an encoding
+it doesn't know about. Expat shouldn't call this twice for the same
+encoding name. The only reason users should use this function is to
+explicitly load an encoding not contained in the @Encoding_Path list.
+
+=back
+
+=head1 AUTHORS
+
+Larry Wall <F<larry@wall.org>> wrote version 1.0.
+
+Clark Cooper <F<coopercc@netheaven.com>> picked up support, changed the API
+for this version (2.x), provided documentation, and added some standard
+package features.
+
+=cut
diff --git a/Expat/Expat.xs b/Expat/Expat.xs
new file mode 100644
index 0000000..497b64f
--- /dev/null
+++ b/Expat/Expat.xs
@@ -0,0 +1,2214 @@
+/*****************************************************************
+** Expat.xs
+**
+** 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.
+**
+*/
+
+#include <expat.h>
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#undef convert
+
+#include "patchlevel.h"
+#include "encoding.h"
+
+
+/* Version 5.005_5x (Development version for 5.006) doesn't like sv_...
+ anymore, but 5.004 doesn't know about PL_sv..
+ Don't want to push up required version just for this. */
+
+#if PATCHLEVEL < 5
+#define PL_sv_undef sv_undef
+#define PL_sv_no sv_no
+#define PL_sv_yes sv_yes
+#define PL_na na
+#endif
+
+#define BUFSIZE 32768
+
+#define NSDELIM '|'
+
+/* Macro to update handler fields. Used in the various handler setting
+ XSUBS */
+
+#define XMLP_UPD(fld) \
+ RETVAL = cbv->fld ? newSVsv(cbv->fld) : &PL_sv_undef;\
+ if (cbv->fld) {\
+ if (cbv->fld != fld)\
+ sv_setsv(cbv->fld, fld);\
+ }\
+ else\
+ cbv->fld = newSVsv(fld)
+
+/* Macro to push old handler value onto return stack. This is done here
+ to get around a bug in 5.004 sv_2mortal function. */
+
+#define PUSHRET \
+ ST(0) = RETVAL;\
+ if (RETVAL != &PL_sv_undef && SvREFCNT(RETVAL)) sv_2mortal(RETVAL)
+
+typedef struct {
+ SV* self_sv;
+ XML_Parser p;
+
+ AV* context;
+ AV* new_prefix_list;
+ HV *nstab;
+ AV *nslst;
+
+ unsigned int st_serial;
+ unsigned int st_serial_stackptr;
+ unsigned int st_serial_stacksize;
+ unsigned int * st_serial_stack;
+
+ unsigned int skip_until;
+
+ SV *recstring;
+ char * delim;
+ STRLEN delimlen;
+
+ unsigned ns:1;
+ unsigned no_expand:1;
+ unsigned parseparam:1;
+
+ /* Callback handlers */
+
+ SV* start_sv;
+ SV* end_sv;
+ SV* char_sv;
+ SV* proc_sv;
+ SV* cmnt_sv;
+ SV* dflt_sv;
+
+ SV* entdcl_sv;
+ SV* eledcl_sv;
+ SV* attdcl_sv;
+ SV* doctyp_sv;
+ SV* doctypfin_sv;
+ SV* xmldec_sv;
+
+ SV* unprsd_sv;
+ SV* notation_sv;
+
+ SV* extent_sv;
+ SV* extfin_sv;
+
+ SV* startcd_sv;
+ SV* endcd_sv;
+} CallbackVector;
+
+
+static HV* EncodingTable = NULL;
+
+static XML_Char nsdelim[] = {NSDELIM, '\0'};
+
+static char *QuantChar[] = {"", "?", "*", "+"};
+
+/* Forward declarations */
+
+static void suspend_callbacks(CallbackVector *);
+static void resume_callbacks(CallbackVector *);
+
+#if PATCHLEVEL < 5 && SUBVERSION < 5
+
+/* ================================================================
+** This is needed where the length is explicitly given. The expat
+** library may sometimes give us zero-length strings. Perl's newSVpv
+** interprets a zero length as a directive to do a strlen. This
+** function is used when we want to force length to mean length, even
+** if zero.
+*/
+
+static SV *
+newSVpvn(char *s, STRLEN len)
+{
+ register SV *sv;
+
+ sv = newSV(0);
+ sv_setpvn(sv, s, len);
+ return sv;
+} /* End newSVpvn */
+
+#define ERRSV GvSV(errgv)
+#endif
+
+#ifdef SvUTF8_on
+
+static SV *
+newUTF8SVpv(char *s, STRLEN len) {
+ register SV *sv;
+
+ sv = newSVpv(s, len);
+ SvUTF8_on(sv);
+ return sv;
+} /* End new UTF8SVpv */
+
+static SV *
+newUTF8SVpvn(char *s, STRLEN len) {
+ register SV *sv;
+
+ sv = newSV(0);
+ sv_setpvn(sv, s, len);
+ SvUTF8_on(sv);
+ return sv;
+}
+
+#else /* SvUTF8_on not defined */
+
+#define newUTF8SVpv newSVpv
+#define newUTF8SVpvn newSVpvn
+
+#endif
+
+static void*
+mymalloc(size_t size) {
+#ifndef LEAKTEST
+ return safemalloc(size);
+#else
+ return safexmalloc(328,size);
+#endif
+}
+
+static void*
+myrealloc(void *p, size_t s) {
+#ifndef LEAKTEST
+ return saferealloc(p, s);
+#else
+ return safexrealloc(p, s);
+#endif
+}
+
+static void
+myfree(void *p) {
+ Safefree(p);
+}
+
+static XML_Memory_Handling_Suite ms = {mymalloc, myrealloc, myfree};
+
+static void
+append_error(XML_Parser parser, char * err)
+{
+ dSP;
+ CallbackVector * cbv;
+ SV ** errstr;
+
+ cbv = (CallbackVector*) XML_GetUserData(parser);
+ errstr = hv_fetch((HV*)SvRV(cbv->self_sv),
+ "ErrorMessage", 12, 0);
+
+ if (errstr && SvPOK(*errstr)) {
+ SV ** errctx = hv_fetch((HV*) SvRV(cbv->self_sv),
+ "ErrorContext", 12, 0);
+ int dopos = !err && errctx && SvOK(*errctx);
+
+ if (! err)
+ err = (char *) XML_ErrorString(XML_GetErrorCode(parser));
+
+ sv_catpvf(*errstr, "\n%s at line %d, column %d, byte %d%s",
+ err,
+ XML_GetCurrentLineNumber(parser),
+ XML_GetCurrentColumnNumber(parser),
+ XML_GetCurrentByteIndex(parser),
+ dopos ? ":\n" : "");
+
+ if (dopos)
+ {
+ int count;
+
+ ENTER ;
+ SAVETMPS ;
+ PUSHMARK(sp);
+ XPUSHs(cbv->self_sv);
+ XPUSHs(*errctx);
+ PUTBACK ;
+
+ count = perl_call_method("position_in_context", G_SCALAR);
+
+ SPAGAIN ;
+
+ if (count >= 1) {
+ sv_catsv(*errstr, POPs);
+ }
+
+ PUTBACK ;
+ FREETMPS ;
+ LEAVE ;
+ }
+ }
+} /* End append_error */
+
+static SV *
+generate_model(XML_Content *model) {
+ HV * hash = newHV();
+ SV * obj = newRV_noinc((SV *) hash);
+
+ sv_bless(obj, gv_stashpv("XML::Parser::ContentModel", 1));
+
+ hv_store(hash, "Type", 4, newSViv(model->type), 0);
+ if (model->quant != XML_CQUANT_NONE) {
+ hv_store(hash, "Quant", 5, newSVpv(QuantChar[model->quant], 1), 0);
+ }
+
+ switch(model->type) {
+ case XML_CTYPE_NAME:
+ hv_store(hash, "Tag", 3, newUTF8SVpv((char *)model->name, 0), 0);
+ break;
+
+ case XML_CTYPE_MIXED:
+ case XML_CTYPE_CHOICE:
+ case XML_CTYPE_SEQ:
+ if (model->children && model->numchildren)
+ {
+ AV * children = newAV();
+ int i;
+
+ for (i = 0; i < model->numchildren; i++) {
+ av_push(children, generate_model(&model->children[i]));
+ }
+
+ hv_store(hash, "Children", 8, newRV_noinc((SV *) children), 0);
+ }
+ break;
+ }
+
+ return obj;
+} /* End generate_model */
+
+static int
+parse_stream(XML_Parser parser, SV * ioref)
+{
+ dSP;
+ SV * tbuff;
+ SV * tsiz;
+ char * linebuff;
+ STRLEN lblen;
+ STRLEN br = 0;
+ int buffsize;
+ int done = 0;
+ int ret = 1;
+ char * msg = NULL;
+ CallbackVector * cbv;
+ char *buff = (char *) 0;
+
+ cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ ENTER;
+ SAVETMPS;
+
+ if (cbv->delim) {
+ int cnt;
+ SV * tline;
+
+ PUSHMARK(SP);
+ XPUSHs(ioref);
+ PUTBACK ;
+
+ cnt = perl_call_method("getline", G_SCALAR);
+
+ SPAGAIN;
+
+ if (cnt != 1)
+ croak("getline method call failed");
+
+ tline = POPs;
+
+ if (! SvOK(tline)) {
+ lblen = 0;
+ }
+ else {
+ char * chk;
+ linebuff = SvPV(tline, lblen);
+ chk = &linebuff[lblen - cbv->delimlen - 1];
+
+ if (lblen > cbv->delimlen + 1
+ && *chk == *cbv->delim
+ && chk[cbv->delimlen] == '\n'
+ && strnEQ(++chk, cbv->delim + 1, cbv->delimlen - 1))
+ lblen -= cbv->delimlen + 1;
+ }
+
+ PUTBACK ;
+ buffsize = lblen;
+ done = lblen == 0;
+ }
+ else {
+ tbuff = newSV(0);
+ tsiz = newSViv(BUFSIZE);
+ buffsize = BUFSIZE;
+ }
+
+ while (! done)
+ {
+ char *buffer = XML_GetBuffer(parser, buffsize);
+
+ if (! buffer)
+ croak("Ran out of memory for input buffer");
+
+ SAVETMPS;
+
+ if (cbv->delim) {
+ Copy(linebuff, buffer, lblen, char);
+ br = lblen;
+ done = 1;
+ }
+ else {
+ int cnt;
+ SV * rdres;
+ char * tb;
+
+ PUSHMARK(SP);
+ EXTEND(SP, 3);
+ PUSHs(ioref);
+ PUSHs(tbuff);
+ PUSHs(tsiz);
+ PUTBACK ;
+
+ cnt = perl_call_method("read", G_SCALAR);
+
+ SPAGAIN ;
+
+ if (cnt != 1)
+ croak("read method call failed");
+
+ rdres = POPs;
+
+ if (! SvOK(rdres))
+ croak("read error");
+
+ tb = SvPV(tbuff, br);
+ if (br > 0)
+ Copy(tb, buffer, br, char);
+ else
+ done = 1;
+
+ PUTBACK ;
+ }
+
+ ret = XML_ParseBuffer(parser, br, done);
+
+ SPAGAIN; /* resync local SP in case callbacks changed global stack */
+
+ if (! ret)
+ break;
+
+ FREETMPS;
+ }
+
+ if (! ret)
+ append_error(parser, msg);
+
+ if (! cbv->delim) {
+ SvREFCNT_dec(tsiz);
+ SvREFCNT_dec(tbuff);
+ }
+
+ FREETMPS;
+ LEAVE;
+
+ return ret;
+} /* End parse_stream */
+
+static SV *
+gen_ns_name(const char * name, HV * ns_table, AV * ns_list)
+{
+ char *pos = strchr(name, NSDELIM);
+ SV * ret;
+
+ if (pos && pos > name)
+ {
+ SV ** name_ent = hv_fetch(ns_table, (char *) name,
+ pos - name, TRUE);
+ ret = newUTF8SVpv(&pos[1], 0);
+
+ if (name_ent)
+ {
+ int index;
+
+ if (SvOK(*name_ent))
+ {
+ index = SvIV(*name_ent);
+ }
+ else
+ {
+ av_push(ns_list, newUTF8SVpv((char *) name, pos - name));
+ index = av_len(ns_list);
+ sv_setiv(*name_ent, (IV) index);
+ }
+
+ sv_setiv(ret, (IV) index);
+ SvPOK_on(ret);
+ }
+ }
+ else
+ ret = newUTF8SVpv((char *) name, 0);
+
+ return ret;
+} /* End gen_ns_name */
+
+static void
+characterData(void *userData, const char *s, int len)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpvn((char*)s,len)));
+ PUTBACK;
+ perl_call_sv(cbv->char_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End characterData */
+
+static void
+startElement(void *userData, const char *name, const char **atts)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+ SV ** pcontext;
+ unsigned do_ns = cbv->ns;
+ unsigned skipping = 0;
+ SV ** pnstab;
+ SV ** pnslst;
+ SV * elname;
+
+ cbv->st_serial++;
+
+ if (cbv->skip_until) {
+ skipping = cbv->st_serial < cbv->skip_until;
+ if (! skipping) {
+ resume_callbacks(cbv);
+ cbv->skip_until = 0;
+ }
+ }
+
+ if (cbv->st_serial_stackptr >= cbv->st_serial_stacksize) {
+ unsigned int newsize = cbv->st_serial_stacksize + 512;
+
+ Renew(cbv->st_serial_stack, newsize, unsigned int);
+ cbv->st_serial_stacksize = newsize;
+ }
+
+ cbv->st_serial_stack[++cbv->st_serial_stackptr] = cbv->st_serial;
+
+ if (do_ns)
+ elname = gen_ns_name(name, cbv->nstab, cbv->nslst);
+ else
+ elname = newUTF8SVpv((char *)name, 0);
+
+ if (! skipping && SvTRUE(cbv->start_sv))
+ {
+ const char **attlim = atts;
+
+ while (*attlim)
+ attlim++;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, attlim - atts + 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(elname);
+ while (*atts)
+ {
+ SV * attname;
+
+ attname = (do_ns ? gen_ns_name(*atts, cbv->nstab, cbv->nslst)
+ : newUTF8SVpv((char *) *atts, 0));
+
+ atts++;
+ PUSHs(sv_2mortal(attname));
+ if (*atts)
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)*atts++,0)));
+ }
+ PUTBACK;
+ perl_call_sv(cbv->start_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+ }
+
+ av_push(cbv->context, elname);
+
+ if (cbv->ns) {
+ av_clear(cbv->new_prefix_list);
+ }
+} /* End startElement */
+
+static void
+endElement(void *userData, const char *name)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+ SV *elname;
+
+ elname = av_pop(cbv->context);
+
+ if (! cbv->st_serial_stackptr) {
+ croak("endElement: Start tag serial number stack underflow");
+ }
+
+ if (! cbv->skip_until && SvTRUE(cbv->end_sv))
+ {
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(elname);
+ PUTBACK;
+ perl_call_sv(cbv->end_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+ }
+
+ cbv->st_serial_stackptr--;
+
+ SvREFCNT_dec(elname);
+} /* End endElement */
+
+static void
+processingInstruction(void *userData, const char *target, const char *data)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 3);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)target,0)));
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)data,0)));
+ PUTBACK;
+ perl_call_sv(cbv->proc_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End processingInstruction */
+
+static void
+commenthandle(void *userData, const char *string)
+{
+ dSP;
+ CallbackVector * cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) string, 0)));
+ PUTBACK;
+ perl_call_sv(cbv->cmnt_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End commenthandler */
+
+static void
+startCdata(void *userData)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ if (cbv->startcd_sv) {
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs(cbv->self_sv);
+ PUTBACK;
+ perl_call_sv(cbv->startcd_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+ }
+} /* End startCdata */
+
+static void
+endCdata(void *userData)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ if (cbv->endcd_sv) {
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ XPUSHs(cbv->self_sv);
+ PUTBACK;
+ perl_call_sv(cbv->endcd_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+ }
+} /* End endCdata */
+
+static void
+nsStart(void *userdata, const XML_Char *prefix, const XML_Char *uri){
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userdata;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 3);
+ PUSHs(cbv->self_sv);
+ PUSHs(prefix ? sv_2mortal(newUTF8SVpv((char *)prefix, 0)) : &PL_sv_undef);
+ PUSHs(uri ? sv_2mortal(newUTF8SVpv((char *)uri, 0)) : &PL_sv_undef);
+ PUTBACK;
+ perl_call_method("NamespaceStart", G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End nsStart */
+
+static void
+nsEnd(void *userdata, const XML_Char *prefix) {
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userdata;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(prefix ? sv_2mortal(newUTF8SVpv((char *)prefix, 0)) : &PL_sv_undef);
+ PUTBACK;
+ perl_call_method("NamespaceEnd", G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End nsEnd */
+
+static void
+defaulthandle(void *userData, const char *string, int len)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpvn((char*)string, len)));
+ PUTBACK;
+ perl_call_sv(cbv->dflt_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End defaulthandle */
+
+static void
+elementDecl(void *data,
+ const char *name,
+ XML_Content *model) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) data;
+ SV *cmod;
+
+ ENTER;
+ SAVETMPS;
+
+
+ cmod = generate_model(model);
+
+ Safefree(model);
+ PUSHMARK(sp);
+ EXTEND(sp, 3);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char *)name, 0)));
+ PUSHs(sv_2mortal(cmod));
+ PUTBACK;
+ perl_call_sv(cbv->eledcl_sv, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+
+} /* End elementDecl */
+
+static void
+attributeDecl(void *data,
+ const char * elname,
+ const char * attname,
+ const char * att_type,
+ const char * dflt,
+ int reqorfix) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) data;
+ SV * dfltsv;
+
+ if (dflt) {
+ dfltsv = newUTF8SVpv("'", 1);
+ sv_catpv(dfltsv, (char *) dflt);
+ sv_catpv(dfltsv, "'");
+ }
+ else {
+ dfltsv = newUTF8SVpv(reqorfix ? "#REQUIRED" : "#IMPLIED", 0);
+ }
+
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(sp);
+ EXTEND(sp, 5);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char *)elname, 0)));
+ PUSHs(sv_2mortal(newUTF8SVpv((char *)attname, 0)));
+ PUSHs(sv_2mortal(newUTF8SVpv((char *)att_type, 0)));
+ PUSHs(sv_2mortal(dfltsv));
+ if (dflt && reqorfix)
+ XPUSHs(&PL_sv_yes);
+ PUTBACK;
+ perl_call_sv(cbv->attdcl_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End attributeDecl */
+
+static void
+entityDecl(void *data,
+ const char *name,
+ int isparam,
+ const char *value,
+ int vlen,
+ const char *base,
+ const char *sysid,
+ const char *pubid,
+ const char *notation) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) data;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 6);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)name, 0)));
+ PUSHs(value ? sv_2mortal(newUTF8SVpvn((char*)value, vlen)) : &PL_sv_undef);
+ PUSHs(sysid ? sv_2mortal(newUTF8SVpv((char *)sysid, 0)) : &PL_sv_undef);
+ PUSHs(pubid ? sv_2mortal(newUTF8SVpv((char *)pubid, 0)) : &PL_sv_undef);
+ PUSHs(notation ? sv_2mortal(newUTF8SVpv((char *)notation, 0)) : &PL_sv_undef);
+ if (isparam)
+ XPUSHs(&PL_sv_yes);
+ PUTBACK;
+ perl_call_sv(cbv->entdcl_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End entityDecl */
+
+static void
+doctypeStart(void *userData,
+ const char* name,
+ const char* sysid,
+ const char* pubid,
+ int hasinternal) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 5);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*)name, 0)));
+ PUSHs(sysid ? sv_2mortal(newUTF8SVpv((char*)sysid, 0)) : &PL_sv_undef);
+ PUSHs(pubid ? sv_2mortal(newUTF8SVpv((char*)pubid, 0)) : &PL_sv_undef);
+ PUSHs(hasinternal ? &PL_sv_yes : &PL_sv_no);
+ PUTBACK;
+ perl_call_sv(cbv->doctyp_sv, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+} /* End doctypeStart */
+
+static void
+doctypeEnd(void *userData) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 1);
+ PUSHs(cbv->self_sv);
+ PUTBACK;
+ perl_call_sv(cbv->doctypfin_sv, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+} /* End doctypeEnd */
+
+static void
+xmlDecl(void *userData,
+ const char *version,
+ const char *encoding,
+ int standalone) {
+ dSP;
+ CallbackVector *cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 4);
+ PUSHs(cbv->self_sv);
+ PUSHs(version ? sv_2mortal(newUTF8SVpv((char *)version, 0))
+ : &PL_sv_undef);
+ PUSHs(encoding ? sv_2mortal(newUTF8SVpv((char *)encoding, 0))
+ : &PL_sv_undef);
+ PUSHs(standalone == -1 ? &PL_sv_undef
+ : (standalone ? &PL_sv_yes : &PL_sv_no));
+ PUTBACK;
+ perl_call_sv(cbv->xmldec_sv, G_DISCARD);
+ FREETMPS;
+ LEAVE;
+} /* End xmlDecl */
+
+static void
+unparsedEntityDecl(void *userData,
+ const char* entity,
+ const char* base,
+ const char* sysid,
+ const char* pubid,
+ const char* notation)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 6);
+ PUSHs(cbv->self_sv);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) entity, 0)));
+ PUSHs(base ? sv_2mortal(newUTF8SVpv((char*) base, 0)) : &PL_sv_undef);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) sysid, 0)));
+ PUSHs(pubid ? sv_2mortal(newUTF8SVpv((char*) pubid, 0)) : &PL_sv_undef);
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) notation, 0)));
+ PUTBACK;
+ perl_call_sv(cbv->unprsd_sv, G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+} /* End unparsedEntityDecl */
+
+static void
+notationDecl(void *userData,
+ const char *name,
+ const char *base,
+ const char *sysid,
+ const char *pubid)
+{
+ dSP;
+ CallbackVector* cbv = (CallbackVector*) userData;
+
+ PUSHMARK(sp);
+ XPUSHs(cbv->self_sv);
+ XPUSHs(sv_2mortal(newUTF8SVpv((char*) name, 0)));
+ if (base)
+ {
+ XPUSHs(sv_2mortal(newUTF8SVpv((char *) base, 0)));
+ }
+ else if (sysid || pubid)
+ {
+ XPUSHs(&PL_sv_undef);
+ }
+
+ if (sysid)
+ {
+ XPUSHs(sv_2mortal(newUTF8SVpv((char *) sysid, 0)));
+ }
+ else if (pubid)
+ {
+ XPUSHs(&PL_sv_undef);
+ }
+
+ if (pubid)
+ XPUSHs(sv_2mortal(newUTF8SVpv((char *) pubid, 0)));
+
+ PUTBACK;
+ perl_call_sv(cbv->notation_sv, G_DISCARD);
+} /* End notationDecl */
+
+static int
+externalEntityRef(XML_Parser parser,
+ const char* open,
+ const char* base,
+ const char* sysid,
+ const char* pubid)
+{
+ dSP;
+#if defined(USE_THREADS) && PATCHLEVEL==6
+ dTHX;
+#endif
+
+ int count;
+ int ret = 0;
+ int parse_done = 0;
+
+ CallbackVector* cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ if (! cbv->extent_sv)
+ return 0;
+
+ ENTER ;
+ SAVETMPS ;
+ PUSHMARK(sp);
+ EXTEND(sp, pubid ? 4 : 3);
+ PUSHs(cbv->self_sv);
+ PUSHs(base ? sv_2mortal(newUTF8SVpv((char*) base, 0)) : &PL_sv_undef);
+ PUSHs(sv_2mortal(newSVpv((char*) sysid, 0)));
+ if (pubid)
+ PUSHs(sv_2mortal(newUTF8SVpv((char*) pubid, 0)));
+ PUTBACK ;
+ count = perl_call_sv(cbv->extent_sv, G_SCALAR);
+
+ SPAGAIN ;
+
+ if (count >= 1) {
+ SV * result = POPs;
+ int type;
+
+ if (result && (type = SvTYPE(result)) > 0) {
+ SV **pval = hv_fetch((HV*) SvRV(cbv->self_sv), "Parser", 6, 0);
+
+ if (! pval || ! SvIOK(*pval))
+ append_error(parser, "Can't find parser entry in XML::Parser object");
+ else {
+ XML_Parser entpar;
+ char *errmsg = (char *) 0;
+
+ entpar = XML_ExternalEntityParserCreate(parser, open, 0);
+
+ XML_SetBase(entpar, XML_GetBase(parser));
+
+ sv_setiv(*pval, (IV) entpar);
+
+ cbv->p = entpar;
+
+ PUSHMARK(sp);
+ EXTEND(sp, 2);
+ PUSHs(*pval);
+ PUSHs(result);
+ PUTBACK;
+ count = perl_call_pv("XML::Parser::Expat::Do_External_Parse",
+ G_SCALAR | G_EVAL);
+ SPAGAIN;
+
+ if (SvTRUE(ERRSV)) {
+ char *hold;
+ STRLEN len;
+
+ POPs;
+ hold = SvPV(ERRSV, len);
+ New(326, errmsg, len + 1, char);
+ if (len)
+ Copy(hold, errmsg, len, char);
+ goto Extparse_Cleanup;
+ }
+
+ if (count > 0)
+ ret = POPi;
+
+ parse_done = 1;
+
+ Extparse_Cleanup:
+ cbv->p = parser;
+ sv_setiv(*pval, (IV) parser);
+ XML_ParserFree(entpar);
+
+ if (cbv->extfin_sv) {
+ PUSHMARK(sp);
+ PUSHs(cbv->self_sv);
+ PUTBACK;
+ perl_call_sv(cbv->extfin_sv, G_DISCARD);
+ SPAGAIN;
+ }
+
+ if (SvTRUE(ERRSV))
+ append_error(parser, SvPV(ERRSV, PL_na));
+ }
+ }
+ }
+
+ if (! ret && ! parse_done)
+ append_error(parser, "Handler couldn't resolve external entity");
+
+ PUTBACK ;
+ FREETMPS ;
+ LEAVE ;
+
+ return ret;
+} /* End externalEntityRef */
+
+/*================================================================
+** This is the function that expat calls to convert multi-byte sequences
+** for external encodings. Each byte in the sequence is used to index
+** into the current map to either set the next map or, in the case of
+** the final byte, to get the corresponding Unicode scalar, which is
+** returned.
+*/
+
+static int
+convert_to_unicode(void *data, const char *seq) {
+ Encinfo *enc = (Encinfo *) data;
+ 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;
+} /* End convert_to_unicode */
+
+static int
+unknownEncoding(void *unused, const char *name, XML_Encoding *info)
+{
+ SV ** encinfptr;
+ Encinfo *enc;
+ int namelen;
+ int i;
+ char buff[42];
+
+ namelen = strlen(name);
+ if (namelen > 40)
+ return 0;
+
+ /* Make uppercase */
+ for (i = 0; i < namelen; i++) {
+ char c = name[i];
+ if (c >= 'a' && c <= 'z')
+ c -= 'a' - 'A';
+ buff[i] = c;
+ }
+
+ if (! EncodingTable) {
+ EncodingTable = perl_get_hv("XML::Parser::Expat::Encoding_Table", FALSE);
+ if (! EncodingTable)
+ croak("Can't find XML::Parser::Expat::Encoding_Table");
+ }
+
+ encinfptr = hv_fetch(EncodingTable, buff, namelen, 0);
+
+ if (! encinfptr || ! SvOK(*encinfptr)) {
+ /* Not found, so try to autoload */
+ dSP;
+ int count;
+
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(sp);
+ XPUSHs(sv_2mortal(newSVpvn(buff,namelen)));
+ PUTBACK;
+ perl_call_pv("XML::Parser::Expat::load_encoding", G_DISCARD);
+
+ encinfptr = hv_fetch(EncodingTable, buff, namelen, 0);
+ FREETMPS;
+ LEAVE;
+
+ if (! encinfptr || ! SvOK(*encinfptr))
+ return 0;
+ }
+
+ if (! sv_derived_from(*encinfptr, "XML::Parser::Encinfo"))
+ croak("Entry in XML::Parser::Expat::Encoding_Table not an Encinfo object");
+
+ enc = (Encinfo *) SvIV((SV*)SvRV(*encinfptr));
+ Copy(enc->firstmap, info->map, 256, int);
+ info->release = NULL;
+ if (enc->prefixes_size) {
+ info->data = (void *) enc;
+ info->convert = convert_to_unicode;
+ }
+ else {
+ info->data = NULL;
+ info->convert = NULL;
+ }
+
+ return 1;
+} /* End unknownEncoding */
+
+
+static void
+recString(void *userData, const char *string, int len)
+{
+ CallbackVector *cbv = (CallbackVector*) userData;
+
+ if (cbv->recstring) {
+ sv_catpvn(cbv->recstring, (char *) string, len);
+ }
+ else {
+ cbv->recstring = newUTF8SVpvn((char *) string, len);
+ }
+} /* End recString */
+
+static void
+suspend_callbacks(CallbackVector *cbv) {
+ if (SvTRUE(cbv->char_sv)) {
+ XML_SetCharacterDataHandler(cbv->p,
+ (XML_CharacterDataHandler) 0);
+ }
+
+ if (SvTRUE(cbv->proc_sv)) {
+ XML_SetProcessingInstructionHandler(cbv->p,
+ (XML_ProcessingInstructionHandler) 0);
+ }
+
+ if (SvTRUE(cbv->cmnt_sv)) {
+ XML_SetCommentHandler(cbv->p,
+ (XML_CommentHandler) 0);
+ }
+
+ if (SvTRUE(cbv->startcd_sv)
+ || SvTRUE(cbv->endcd_sv)) {
+ XML_SetCdataSectionHandler(cbv->p,
+ (XML_StartCdataSectionHandler) 0,
+ (XML_EndCdataSectionHandler) 0);
+ }
+
+ if (SvTRUE(cbv->unprsd_sv)) {
+ XML_SetUnparsedEntityDeclHandler(cbv->p,
+ (XML_UnparsedEntityDeclHandler) 0);
+ }
+
+ if (SvTRUE(cbv->notation_sv)) {
+ XML_SetNotationDeclHandler(cbv->p,
+ (XML_NotationDeclHandler) 0);
+ }
+
+ if (SvTRUE(cbv->extent_sv)) {
+ XML_SetExternalEntityRefHandler(cbv->p,
+ (XML_ExternalEntityRefHandler) 0);
+ }
+
+} /* End suspend_callbacks */
+
+static void
+resume_callbacks(CallbackVector *cbv) {
+ if (SvTRUE(cbv->char_sv)) {
+ XML_SetCharacterDataHandler(cbv->p, characterData);
+ }
+
+ if (SvTRUE(cbv->proc_sv)) {
+ XML_SetProcessingInstructionHandler(cbv->p, processingInstruction);
+ }
+
+ if (SvTRUE(cbv->cmnt_sv)) {
+ XML_SetCommentHandler(cbv->p, commenthandle);
+ }
+
+ if (SvTRUE(cbv->startcd_sv)
+ || SvTRUE(cbv->endcd_sv)) {
+ XML_SetCdataSectionHandler(cbv->p, startCdata, endCdata);
+ }
+
+ if (SvTRUE(cbv->unprsd_sv)) {
+ XML_SetUnparsedEntityDeclHandler(cbv->p, unparsedEntityDecl);
+ }
+
+ if (SvTRUE(cbv->notation_sv)) {
+ XML_SetNotationDeclHandler(cbv->p, notationDecl);
+ }
+
+ if (SvTRUE(cbv->extent_sv)) {
+ XML_SetExternalEntityRefHandler(cbv->p, externalEntityRef);
+ }
+
+} /* End resume_callbacks */
+
+
+MODULE = XML::Parser::Expat PACKAGE = XML::Parser::Expat PREFIX = XML_
+
+XML_Parser
+XML_ParserCreate(self_sv, enc_sv, namespaces)
+ SV * self_sv
+ SV * enc_sv
+ int namespaces
+ CODE:
+ {
+ CallbackVector *cbv;
+ enum XML_ParamEntityParsing pep = XML_PARAM_ENTITY_PARSING_NEVER;
+ char *enc = (char *) (SvTRUE(enc_sv) ? SvPV(enc_sv,PL_na) : 0);
+ SV ** spp;
+
+ Newz(320, cbv, 1, CallbackVector);
+ cbv->self_sv = SvREFCNT_inc(self_sv);
+ Newz(325, cbv->st_serial_stack, 1024, unsigned int);
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "NoExpand", 8, 0);
+ if (spp && SvTRUE(*spp))
+ cbv->no_expand = 1;
+
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "Context", 7, 0);
+ if (! spp || ! *spp || !SvROK(*spp))
+ croak("XML::Parser instance missing Context");
+
+ cbv->context = (AV*) SvRV(*spp);
+
+ cbv->ns = (unsigned) namespaces;
+ if (namespaces)
+ {
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "New_Prefixes", 12, 0);
+ if (! spp || ! *spp || !SvROK(*spp))
+ croak("XML::Parser instance missing New_Prefixes");
+
+ cbv->new_prefix_list = (AV *) SvRV(*spp);
+
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "Namespace_Table",
+ 15, FALSE);
+ if (! spp || ! *spp || !SvROK(*spp))
+ croak("XML::Parser instance missing Namespace_Table");
+
+ cbv->nstab = (HV *) SvRV(*spp);
+
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "Namespace_List",
+ 14, FALSE);
+ if (! spp || ! *spp || !SvROK(*spp))
+ croak("XML::Parser instance missing Namespace_List");
+
+ cbv->nslst = (AV *) SvRV(*spp);
+
+ RETVAL = XML_ParserCreate_MM(enc, &ms, nsdelim);
+ XML_SetNamespaceDeclHandler(RETVAL,nsStart, nsEnd);
+ }
+ else
+ {
+ RETVAL = XML_ParserCreate_MM(enc, &ms, NULL);
+ }
+
+ cbv->p = RETVAL;
+ XML_SetUserData(RETVAL, (void *) cbv);
+ XML_SetElementHandler(RETVAL, startElement, endElement);
+ XML_SetUnknownEncodingHandler(RETVAL, unknownEncoding, 0);
+
+ spp = hv_fetch((HV*)SvRV(cbv->self_sv), "ParseParamEnt",
+ 13, FALSE);
+
+ if (spp && SvTRUE(*spp)) {
+ pep = XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE;
+ cbv->parseparam = 1;
+ }
+
+ XML_SetParamEntityParsing(RETVAL, pep);
+ }
+ OUTPUT:
+ RETVAL
+
+void
+XML_ParserRelease(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ SvREFCNT_dec(cbv->self_sv);
+ }
+
+void
+XML_ParserFree(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ Safefree(cbv->st_serial_stack);
+
+
+ /* Clean up any SVs that we have */
+ /* (Note that self_sv must already be taken care of
+ or we couldn't be here */
+
+ if (cbv->recstring)
+ SvREFCNT_dec(cbv->recstring);
+
+ if (cbv->start_sv)
+ SvREFCNT_dec(cbv->start_sv);
+
+ if (cbv->end_sv)
+ SvREFCNT_dec(cbv->end_sv);
+
+ if (cbv->char_sv)
+ SvREFCNT_dec(cbv->char_sv);
+
+ if (cbv->proc_sv)
+ SvREFCNT_dec(cbv->proc_sv);
+
+ if (cbv->cmnt_sv)
+ SvREFCNT_dec(cbv->cmnt_sv);
+
+ if (cbv->dflt_sv)
+ SvREFCNT_dec(cbv->dflt_sv);
+
+ if (cbv->entdcl_sv)
+ SvREFCNT_dec(cbv->entdcl_sv);
+
+ if (cbv->eledcl_sv)
+ SvREFCNT_dec(cbv->eledcl_sv);
+
+ if (cbv->attdcl_sv)
+ SvREFCNT_dec(cbv->attdcl_sv);
+
+ if (cbv->doctyp_sv)
+ SvREFCNT_dec(cbv->doctyp_sv);
+
+ if (cbv->doctypfin_sv)
+ SvREFCNT_dec(cbv->doctypfin_sv);
+
+ if (cbv->xmldec_sv)
+ SvREFCNT_dec(cbv->xmldec_sv);
+
+ if (cbv->unprsd_sv)
+ SvREFCNT_dec(cbv->unprsd_sv);
+
+ if (cbv->notation_sv)
+ SvREFCNT_dec(cbv->notation_sv);
+
+ if (cbv->extent_sv)
+ SvREFCNT_dec(cbv->extent_sv);
+
+ if (cbv->extfin_sv)
+ SvREFCNT_dec(cbv->extfin_sv);
+
+ if (cbv->startcd_sv)
+ SvREFCNT_dec(cbv->startcd_sv);
+
+ if (cbv->endcd_sv)
+ SvREFCNT_dec(cbv->endcd_sv);
+
+ /* ================ */
+
+ Safefree(cbv);
+ XML_ParserFree(parser);
+ }
+
+int
+XML_ParseString(parser, sv)
+ XML_Parser parser
+ SV * sv
+ CODE:
+ {
+ CallbackVector * cbv;
+ STRLEN len;
+ char *s = SvPV(sv, len);
+
+ cbv = (CallbackVector *) XML_GetUserData(parser);
+
+
+ RETVAL = XML_Parse(parser, s, len, 1);
+ SPAGAIN; /* XML_Parse might have changed stack pointer */
+ if (! RETVAL)
+ append_error(parser, NULL);
+ }
+
+ OUTPUT:
+ RETVAL
+
+int
+XML_ParseStream(parser, ioref, delim)
+ XML_Parser parser
+ SV * ioref
+ SV * delim
+ CODE:
+ {
+ SV **delimsv;
+ CallbackVector * cbv;
+
+ cbv = (CallbackVector *) XML_GetUserData(parser);
+ if (SvOK(delim)) {
+ cbv->delim = SvPV(delim, cbv->delimlen);
+ }
+ else {
+ cbv->delim = (char *) 0;
+ }
+
+ RETVAL = parse_stream(parser, ioref);
+ SPAGAIN; /* parse_stream might have changed stack pointer */
+ }
+
+ OUTPUT:
+ RETVAL
+
+int
+XML_ParsePartial(parser, sv)
+ XML_Parser parser
+ SV * sv
+ CODE:
+ {
+ STRLEN len;
+ char *s = SvPV(sv, len);
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ RETVAL = XML_Parse(parser, s, len, 0);
+ if (! RETVAL)
+ append_error(parser, NULL);
+ }
+
+ OUTPUT:
+ RETVAL
+
+
+int
+XML_ParseDone(parser)
+ XML_Parser parser
+ CODE:
+ {
+ RETVAL = XML_Parse(parser, "", 0, 1);
+ if (! RETVAL)
+ append_error(parser, NULL);
+ }
+
+ OUTPUT:
+ RETVAL
+
+SV *
+XML_SetStartElementHandler(parser, start_sv)
+ XML_Parser parser
+ SV * start_sv
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+ XMLP_UPD(start_sv);
+ PUSHRET;
+ }
+
+SV *
+XML_SetEndElementHandler(parser, end_sv)
+ XML_Parser parser
+ SV * end_sv
+ CODE:
+ {
+ CallbackVector *cbv = (CallbackVector*) XML_GetUserData(parser);
+ XMLP_UPD(end_sv);
+ PUSHRET;
+ }
+
+SV *
+XML_SetCharacterDataHandler(parser, char_sv)
+ XML_Parser parser
+ SV * char_sv
+ CODE:
+ {
+ XML_CharacterDataHandler charhndl = (XML_CharacterDataHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(char_sv);
+ if (SvTRUE(char_sv))
+ charhndl = characterData;
+
+ XML_SetCharacterDataHandler(parser, charhndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetProcessingInstructionHandler(parser, proc_sv)
+ XML_Parser parser
+ SV * proc_sv
+ CODE:
+ {
+ XML_ProcessingInstructionHandler prochndl =
+ (XML_ProcessingInstructionHandler) 0;
+ CallbackVector* cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(proc_sv);
+ if (SvTRUE(proc_sv))
+ prochndl = processingInstruction;
+
+ XML_SetProcessingInstructionHandler(parser, prochndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetCommentHandler(parser, cmnt_sv)
+ XML_Parser parser
+ SV * cmnt_sv
+ CODE:
+ {
+ XML_CommentHandler cmnthndl = (XML_CommentHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(cmnt_sv);
+ if (SvTRUE(cmnt_sv))
+ cmnthndl = commenthandle;
+
+ XML_SetCommentHandler(parser, cmnthndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetDefaultHandler(parser, dflt_sv)
+ XML_Parser parser
+ SV * dflt_sv
+ CODE:
+ {
+ XML_DefaultHandler dflthndl = (XML_DefaultHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(dflt_sv);
+ if (SvTRUE(dflt_sv))
+ dflthndl = defaulthandle;
+
+ if (cbv->no_expand)
+ XML_SetDefaultHandler(parser, dflthndl);
+ else
+ XML_SetDefaultHandlerExpand(parser, dflthndl);
+
+ PUSHRET;
+ }
+
+SV *
+XML_SetUnparsedEntityDeclHandler(parser, unprsd_sv)
+ XML_Parser parser
+ SV * unprsd_sv
+ CODE:
+ {
+ XML_UnparsedEntityDeclHandler unprsdhndl =
+ (XML_UnparsedEntityDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(unprsd_sv);
+ if (SvTRUE(unprsd_sv))
+ unprsdhndl = unparsedEntityDecl;
+
+ XML_SetUnparsedEntityDeclHandler(parser, unprsdhndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetNotationDeclHandler(parser, notation_sv)
+ XML_Parser parser
+ SV * notation_sv
+ CODE:
+ {
+ XML_NotationDeclHandler nothndlr = (XML_NotationDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(notation_sv);
+ if (SvTRUE(notation_sv))
+ nothndlr = notationDecl;
+
+ XML_SetNotationDeclHandler(parser, nothndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetExternalEntityRefHandler(parser, extent_sv)
+ XML_Parser parser
+ SV * extent_sv
+ CODE:
+ {
+ XML_ExternalEntityRefHandler exthndlr =
+ (XML_ExternalEntityRefHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(extent_sv);
+ if (SvTRUE(extent_sv))
+ exthndlr = externalEntityRef;
+
+ XML_SetExternalEntityRefHandler(parser, exthndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetExtEntFinishHandler(parser, extfin_sv)
+ XML_Parser parser
+ SV * extfin_sv
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ /* There is no corresponding handler for this in expat. This is
+ called from the externalEntityRef function above after parsing
+ the external entity. */
+
+ XMLP_UPD(extfin_sv);
+ PUSHRET;
+ }
+
+
+SV *
+XML_SetEntityDeclHandler(parser, entdcl_sv)
+ XML_Parser parser
+ SV * entdcl_sv
+ CODE:
+ {
+ XML_EntityDeclHandler enthndlr =
+ (XML_EntityDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(entdcl_sv);
+ if (SvTRUE(entdcl_sv))
+ enthndlr = entityDecl;
+
+ XML_SetEntityDeclHandler(parser, enthndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetElementDeclHandler(parser, eledcl_sv)
+ XML_Parser parser
+ SV * eledcl_sv
+ CODE:
+ {
+ XML_ElementDeclHandler eldeclhndlr =
+ (XML_ElementDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(eledcl_sv);
+ if (SvTRUE(eledcl_sv))
+ eldeclhndlr = elementDecl;
+
+ XML_SetElementDeclHandler(parser, eldeclhndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetAttListDeclHandler(parser, attdcl_sv)
+ XML_Parser parser
+ SV * attdcl_sv
+ CODE:
+ {
+ XML_AttlistDeclHandler attdeclhndlr =
+ (XML_AttlistDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(attdcl_sv);
+ if (SvTRUE(attdcl_sv))
+ attdeclhndlr = attributeDecl;
+
+ XML_SetAttlistDeclHandler(parser, attdeclhndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetDoctypeHandler(parser, doctyp_sv)
+ XML_Parser parser
+ SV * doctyp_sv
+ CODE:
+ {
+ XML_StartDoctypeDeclHandler dtsthndlr =
+ (XML_StartDoctypeDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+ int set = 0;
+
+ XMLP_UPD(doctyp_sv);
+ if (SvTRUE(doctyp_sv))
+ dtsthndlr = doctypeStart;
+
+ XML_SetStartDoctypeDeclHandler(parser, dtsthndlr);
+ PUSHRET;
+ }
+
+SV *
+XML_SetEndDoctypeHandler(parser, doctypfin_sv)
+ XML_Parser parser
+ SV * doctypfin_sv
+ CODE:
+ {
+ XML_EndDoctypeDeclHandler dtendhndlr =
+ (XML_EndDoctypeDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector*) XML_GetUserData(parser);
+
+ XMLP_UPD(doctypfin_sv);
+ if (SvTRUE(doctypfin_sv))
+ dtendhndlr = doctypeEnd;
+
+ XML_SetEndDoctypeDeclHandler(parser, dtendhndlr);
+ PUSHRET;
+ }
+
+
+SV *
+XML_SetXMLDeclHandler(parser, xmldec_sv)
+ XML_Parser parser
+ SV * xmldec_sv
+ CODE:
+ {
+ XML_XmlDeclHandler xmldechndlr =
+ (XML_XmlDeclHandler) 0;
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ XMLP_UPD(xmldec_sv);
+ if (SvTRUE(xmldec_sv))
+ xmldechndlr = xmlDecl;
+
+ XML_SetXmlDeclHandler(parser, xmldechndlr);
+ PUSHRET;
+ }
+
+
+void
+XML_SetBase(parser, base)
+ XML_Parser parser
+ SV * base
+ CODE:
+ {
+ char * b;
+
+ if (! SvOK(base)) {
+ b = (char *) 0;
+ }
+ else {
+ b = SvPV(base, PL_na);
+ }
+
+ XML_SetBase(parser, b);
+ }
+
+
+SV *
+XML_GetBase(parser)
+ XML_Parser parser
+ CODE:
+ {
+ const char *ret = XML_GetBase(parser);
+ if (ret) {
+ ST(0) = sv_newmortal();
+ sv_setpv(ST(0), ret);
+ }
+ else {
+ ST(0) = &PL_sv_undef;
+ }
+ }
+
+void
+XML_PositionContext(parser, lines)
+ XML_Parser parser
+ int lines
+ PREINIT:
+ int parsepos;
+ int size;
+ const char *pos = XML_GetInputContext(parser, &parsepos, &size);
+ const char *markbeg;
+ const char *limit;
+ const char *markend;
+ int length, relpos;
+ int cnt;
+
+ PPCODE:
+ if (! pos)
+ return;
+
+ for (markbeg = &pos[parsepos], cnt = 0; markbeg >= pos; markbeg--)
+ {
+ if (*markbeg == '\n')
+ {
+ cnt++;
+ if (cnt > lines)
+ break;
+ }
+ }
+
+ markbeg++;
+
+ relpos = 0;
+ limit = &pos[size];
+ for (markend = &pos[parsepos + 1], cnt = 0;
+ markend < limit;
+ markend++)
+ {
+ if (*markend == '\n')
+ {
+ if (cnt == 0)
+ relpos = (markend - markbeg) + 1;
+ cnt++;
+ if (cnt > lines)
+ {
+ markend++;
+ break;
+ }
+ }
+ }
+
+ length = markend - markbeg;
+ if (relpos == 0)
+ relpos = length;
+
+ EXTEND(sp, 2);
+ PUSHs(sv_2mortal(newSVpvn((char *) markbeg, length)));
+ PUSHs(sv_2mortal(newSViv(relpos)));
+
+SV *
+GenerateNSName(name, xml_namespace, table, list)
+ SV * name
+ SV * xml_namespace
+ SV * table
+ SV * list
+ CODE:
+ {
+ STRLEN nmlen, nslen;
+ char * nmstr;
+ char * nsstr;
+ char * buff;
+ char * bp;
+ char * blim;
+
+ nmstr = SvPV(name, nmlen);
+ nsstr = SvPV(xml_namespace, nslen);
+
+ /* Form a namespace-name string that looks like expat's */
+ New(321, buff, nmlen + nslen + 2, char);
+ bp = buff;
+ blim = bp + nslen;
+ while (bp < blim)
+ *bp++ = *nsstr++;
+ *bp++ = NSDELIM;
+ blim = bp + nmlen;
+ while (bp < blim)
+ *bp++ = *nmstr++;
+ *bp = '\0';
+
+ RETVAL = gen_ns_name(buff, (HV *) SvRV(table), (AV *) SvRV(list));
+ Safefree(buff);
+ }
+ OUTPUT:
+ RETVAL
+
+void
+XML_DefaultCurrent(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ XML_DefaultCurrent(parser);
+ }
+
+SV *
+XML_RecognizedString(parser)
+ XML_Parser parser
+ CODE:
+ {
+ XML_DefaultHandler dflthndl = (XML_DefaultHandler) 0;
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ if (cbv->dflt_sv) {
+ dflthndl = defaulthandle;
+ }
+
+ if (cbv->recstring) {
+ sv_setpvn(cbv->recstring, "", 0);
+ }
+
+ if (cbv->no_expand)
+ XML_SetDefaultHandler(parser, recString);
+ else
+ XML_SetDefaultHandlerExpand(parser, recString);
+
+ XML_DefaultCurrent(parser);
+
+ if (cbv->no_expand)
+ XML_SetDefaultHandler(parser, dflthndl);
+ else
+ XML_SetDefaultHandlerExpand(parser, dflthndl);
+
+ RETVAL = newSVsv(cbv->recstring);
+ }
+ OUTPUT:
+ RETVAL
+
+int
+XML_GetErrorCode(parser)
+ XML_Parser parser
+
+int
+XML_GetCurrentLineNumber(parser)
+ XML_Parser parser
+
+
+int
+XML_GetCurrentColumnNumber(parser)
+ XML_Parser parser
+
+long
+XML_GetCurrentByteIndex(parser)
+ XML_Parser parser
+
+int
+XML_GetSpecifiedAttributeCount(parser)
+ XML_Parser parser
+
+char *
+XML_ErrorString(code)
+ int code
+ CODE:
+ const char *ret = XML_ErrorString(code);
+ ST(0) = sv_newmortal();
+ sv_setpv((SV*)ST(0), ret);
+
+SV *
+XML_LoadEncoding(data, size)
+ char * data
+ int size
+ CODE:
+ {
+ Encmap_Header *emh = (Encmap_Header *) data;
+ unsigned pfxsize, bmsize;
+
+ if (size < sizeof(Encmap_Header)
+ || ntohl(emh->magic) != ENCMAP_MAGIC) {
+ RETVAL = &PL_sv_undef;
+ }
+ else {
+ Encinfo *entry;
+ SV *sv;
+ PrefixMap *pfx;
+ unsigned short *bm;
+ int namelen;
+ int i;
+
+ pfxsize = ntohs(emh->pfsize);
+ bmsize = ntohs(emh->bmsize);
+
+ if (size != (sizeof(Encmap_Header)
+ + pfxsize * sizeof(PrefixMap)
+ + bmsize * sizeof(unsigned short))) {
+ RETVAL = &PL_sv_undef;
+ }
+ else {
+ /* Convert to uppercase and get name length */
+
+ for (i = 0; i < sizeof(emh->name); i++) {
+ char c = emh->name[i];
+
+ if (c == (char) 0)
+ break;
+
+ if (c >= 'a' && c <= 'z')
+ emh->name[i] -= 'a' - 'A';
+ }
+ namelen = i;
+
+ RETVAL = newSVpvn(emh->name, namelen);
+
+ New(322, entry, 1, Encinfo);
+ entry->prefixes_size = pfxsize;
+ entry->bytemap_size = bmsize;
+ for (i = 0; i < 256; i++) {
+ entry->firstmap[i] = ntohl(emh->map[i]);
+ }
+
+ pfx = (PrefixMap *) &data[sizeof(Encmap_Header)];
+ bm = (unsigned short *) (((char *) pfx)
+ + sizeof(PrefixMap) * pfxsize);
+
+ New(323, entry->prefixes, pfxsize, PrefixMap);
+ New(324, entry->bytemap, bmsize, unsigned short);
+
+ for (i = 0; i < pfxsize; i++, pfx++) {
+ PrefixMap *dest = &entry->prefixes[i];
+
+ dest->min = pfx->min;
+ dest->len = pfx->len;
+ dest->bmap_start = ntohs(pfx->bmap_start);
+ Copy(pfx->ispfx, dest->ispfx,
+ sizeof(pfx->ispfx) + sizeof(pfx->ischar), unsigned char);
+ }
+
+ for (i = 0; i < bmsize; i++)
+ entry->bytemap[i] = ntohs(bm[i]);
+
+ sv = newSViv(0);
+ sv_setref_pv(sv, "XML::Parser::Encinfo", (void *) entry);
+
+ if (! EncodingTable) {
+ EncodingTable
+ = perl_get_hv("XML::Parser::Expat::Encoding_Table",
+ FALSE);
+ if (! EncodingTable)
+ croak("Can't find XML::Parser::Expat::Encoding_Table");
+ }
+
+ hv_store(EncodingTable, emh->name, namelen, sv, 0);
+ }
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+void
+XML_FreeEncoding(enc)
+ Encinfo * enc
+ CODE:
+ Safefree(enc->bytemap);
+ Safefree(enc->prefixes);
+ Safefree(enc);
+
+SV *
+XML_OriginalString(parser)
+ XML_Parser parser
+ CODE:
+ {
+ int parsepos, size;
+ const char *buff = XML_GetInputContext(parser, &parsepos, &size);
+ if (buff) {
+ RETVAL = newSVpvn((char *) &buff[parsepos],
+ XML_GetCurrentByteCount(parser));
+ }
+ else {
+ RETVAL = newSVpv("", 0);
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+SV *
+XML_SetStartCdataHandler(parser, startcd_sv)
+ XML_Parser parser
+ SV * startcd_sv
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+ XML_StartCdataSectionHandler scdhndl =
+ (XML_StartCdataSectionHandler) 0;
+
+ XMLP_UPD(startcd_sv);
+ if (SvTRUE(startcd_sv))
+ scdhndl = startCdata;
+
+ XML_SetStartCdataSectionHandler(parser, scdhndl);
+ PUSHRET;
+ }
+
+SV *
+XML_SetEndCdataHandler(parser, endcd_sv)
+ XML_Parser parser
+ SV * endcd_sv
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+ XML_EndCdataSectionHandler ecdhndl =
+ (XML_EndCdataSectionHandler) 0;
+
+ XMLP_UPD(endcd_sv);
+ if (SvTRUE(endcd_sv))
+ ecdhndl = endCdata;
+
+ XML_SetEndCdataSectionHandler(parser, ecdhndl);
+ PUSHRET;
+ }
+
+void
+XML_UnsetAllHandlers(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ suspend_callbacks(cbv);
+ if (cbv->ns) {
+ XML_SetNamespaceDeclHandler(cbv->p,
+ (XML_StartNamespaceDeclHandler) 0,
+ (XML_EndNamespaceDeclHandler) 0);
+ }
+
+ XML_SetElementHandler(parser,
+ (XML_StartElementHandler) 0,
+ (XML_EndElementHandler) 0);
+
+ XML_SetUnknownEncodingHandler(parser,
+ (XML_UnknownEncodingHandler) 0,
+ (void *) 0);
+ }
+
+int
+XML_ElementIndex(parser)
+ XML_Parser parser
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+ RETVAL = cbv->st_serial_stack[cbv->st_serial_stackptr];
+ }
+ OUTPUT:
+ RETVAL
+
+void
+XML_SkipUntil(parser, index)
+ XML_Parser parser
+ unsigned int index
+ CODE:
+ {
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+ if (index <= cbv->st_serial)
+ return;
+ cbv->skip_until = index;
+ suspend_callbacks(cbv);
+ }
+
+int
+XML_Do_External_Parse(parser, result)
+ XML_Parser parser
+ SV * result
+ CODE:
+ {
+ int type;
+
+ CallbackVector * cbv = (CallbackVector *) XML_GetUserData(parser);
+
+ if (SvROK(result) && SvOBJECT(SvRV(result))) {
+ RETVAL = parse_stream(parser, result);
+ }
+ else if (isGV(result)) {
+ RETVAL = parse_stream(parser,
+ sv_2mortal(newRV((SV*) GvIOp(result))));
+ }
+ else if (SvPOK(result)) {
+ STRLEN eslen;
+ int pret;
+ char *entstr = SvPV(result, eslen);
+
+ RETVAL = XML_Parse(parser, entstr, eslen, 1);
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+
diff --git a/Expat/Makefile.PL b/Expat/Makefile.PL
new file mode 100644
index 0000000..6d5111c
--- /dev/null
+++ b/Expat/Makefile.PL
@@ -0,0 +1,29 @@
+use ExtUtils::MakeMaker;
+use Config;
+use English;
+
+my $libs = "-lexpat";
+my @extras = ();
+
+push(@extras, INC => "-I$expat_incpath") if $expat_incpath;
+
+$libs = "-L$expat_libpath $libs" if $expat_libpath;
+
+push(@extras, CAPI => 'TRUE')
+ if (($PERL_VERSION >= 5.005) and ($OSNAME eq 'MSWin32')
+ and ($Config{archname} =~ /-object\b/i));
+
+push(@extras,
+ ABSTRACT => "Lowlevel access to James Clark's expat XML parser",
+ AUTHOR => 'Matt Sergeant (matt@sergeant.org)')
+ if ($ExtUtils::MakeMaker::VERSION >= 5.4301);
+
+WriteMakefile(
+ NAME => 'XML::Parser::Expat',
+ C => ['Expat.c'],
+ LIBS => $libs,
+ XSPROTOARG => '-noprototypes',
+ VERSION_FROM => 'Expat.pm',
+ @extras
+);
+
diff --git a/Expat/encoding.h b/Expat/encoding.h
new file mode 100644
index 0000000..4e0374b
--- /dev/null
+++ b/Expat/encoding.h
@@ -0,0 +1,91 @@
+/*****************************************************************
+** 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 */
diff --git a/Expat/typemap b/Expat/typemap
new file mode 100644
index 0000000..47d7dc5
--- /dev/null
+++ b/Expat/typemap
@@ -0,0 +1,24 @@
+#
+##### XML::Parser::Expat typemap
+#
+
+XML_Parser T_PTR
+Encinfo * T_ENCOBJ
+
+################################################################
+INPUT
+T_ENCOBJ
+ if (sv_derived_from($arg, \"XML::Parser::Encinfo\")) {
+ IV tmp = SvIV((SV*)SvRV($arg));
+ $var = ($type) tmp;
+ }
+ else
+ croak(\"$var is not of type XML::Parser::Encinfo\")
+################################################################
+OUTPUT
+T_ENCOBJ
+ if ($var) {
+ sv_setref_pv($arg, \"XML::Parser::Encinfo\", (void*)$var);
+ }
+ else
+ $arg = &PL_sv_undef;
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..6fd6a32
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,60 @@
+Changes Change log
+Expat/Expat.pm XML::Parser::Expat module
+Expat/Expat.xs Extension library
+Expat/Makefile.PL perl MakeMaker script for XML::Parser::Expat
+Expat/encoding.h Header file; describes *.enc structure
+Expat/typemap XS typemap
+MANIFEST This file
+Makefile.PL perl MakeMaker script for XML::Parser
+Parser.pm XML::Parser module
+Parser/LWPExternEnt.pl LWP based external entity handler
+Parser/Encodings/Japanese_Encodings.msg Message about Japanese encodings.
+Parser/Encodings/README Info about encoding maps
+Parser/Encodings/big5.enc Big5 binary encoding map
+Parser/Encodings/euc-kr.enc EUC-KR binary encoding map
+Parser/Encodings/iso-8859-2.enc ISO-8859-2 binary encoding map
+Parser/Encodings/iso-8859-3.enc ISO-8859-3 binary encoding map
+Parser/Encodings/iso-8859-4.enc ISO-8859-4 binary encoding map
+Parser/Encodings/iso-8859-5.enc ISO-8859-5 binary encoding map
+Parser/Encodings/iso-8859-7.enc ISO-8859-7 binary encoding map
+Parser/Encodings/iso-8859-8.enc ISO-8859-8 binary encoding map
+Parser/Encodings/iso-8859-9.enc ISO-8859-9 binary encoding map
+Parser/Encodings/windows-1250.enc cp1250-WinLatin2 binary encoding map
+Parser/Encodings/windows-1252.enc cp1252-WinLatin1 binary encoding map
+Parser/Encodings/x-euc-jp-jisx0221.enc X-euc-jp-jisx0221 encoding map
+Parser/Encodings/x-euc-jp-unicode.enc X-euc-jp-unicde encoding map
+Parser/Encodings/x-sjis-cp932.enc x-sjis-cp932 encoding map
+Parser/Encodings/x-sjis-jdk117.enc x-sjis-jdk117 encoding map
+Parser/Encodings/x-sjis-jisx0221.enc x-sjis-jisx0221 encoding map
+Parser/Encodings/x-sjis-unicode.enc x-sjis-unicode encoding map
+Parser/Style/Debug.pm Debug style parser
+Parser/Style/Objects.pm Objects style parser
+Parser/Style/Stream.pm Stream style parser
+Parser/Style/Subs.pm Subs style parser
+Parser/Style/Tree.pm Tree style parser
+README Short explanation
+samples/canonical A utility to generate canonical XML
+samples/canontst.xml An xml document to demonstrate canonical
+samples/ctest.dtd An external DTD used by canontst.xml
+samples/REC-xml-19980210.xml The XML spec in xml form
+samples/xmlcomments A utility to extract comments
+samples/xmlfilter A utility to filter elements
+samples/xmlstats A utility to report on element statistics
+t/astress.t Test script
+t/cdata.t Test script
+t/decl.t Test script
+t/defaulted.t Test script
+t/encoding.t Test script
+t/external_ent.t Test script
+t/file.t Test script
+t/finish.t Test script
+t/ext.ent External entity for parament.t test
+t/ext2.ent External entity for parament.t test
+t/foo.dtd External DTD for parament.t test
+t/namespaces.t Test script
+t/parament.t Test script
+t/partial.t Test script
+t/skip.t Test script
+t/stream.t Test script
+t/styles.t Test script
+META.yml Module meta-data (added by MakeMaker)
diff --git a/META.yml b/META.yml
new file mode 100644
index 0000000..6bd7583
--- /dev/null
+++ b/META.yml
@@ -0,0 +1,11 @@
+# http://module-build.sourceforge.net/META-spec.html
+#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
+name: XML-Parser
+version: 2.36
+version_from: Parser.pm
+installdirs: site
+requires:
+ LWP: 0
+
+distribution_type: module
+generated_by: ExtUtils::MakeMaker version 6.17
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644
index 0000000..33af549
--- /dev/null
+++ b/Makefile.PL
@@ -0,0 +1,114 @@
+use 5.004;
+use ExtUtils::MakeMaker;
+use Config;
+
+$expat_libpath = '';
+$expat_incpath = '';
+
+my @replacement_args;
+
+foreach (@ARGV) {
+ if (/^EXPAT(LIB|INC)PATH=(.+)/) {
+ if ($1 eq 'LIB') {
+ $expat_libpath = $2;
+ }
+ else {
+ $expat_incpath = $2;
+ }
+ }
+ else {
+ push(@replacement_args, $_);
+ }
+}
+
+@ARGV = @replacement_args;
+if (not $expat_libpath and $] >= 5.006001 and $^O ne 'MSWin32') {
+ require ExtUtils::Liblist; # Buggy before this
+ ($expat_libpath) = ExtUtils::Liblist->ext('-lexpat');
+}
+
+unless ($expat_libpath) {
+ # Test for existence of libexpat
+ my $found = 0;
+ foreach (split(/\s+/, $Config{libpth})) {
+ if (-f "$_/libexpat." . $Config{so}) {
+ $found = 1;
+ last;
+ }
+ }
+
+ if (!$found and $^O eq 'MSWin32') {
+ if (-f 'C:/lib/Expat-2.0.0/Libs/libexpat.dll') {
+ $expat_libpath = 'C:/lib/Expat-2.0.0/Libs';
+ $expat_incpath = 'C:/lib/Expat-2.0.0/Source/lib';
+ $found = 1;
+ }
+
+ }
+
+ unless ($found) {
+ die <<'Expat_Not_Installed;';
+
+Expat must be installed prior to building XML::Parser and I can't find
+it in the standard library directories. You can download expat from:
+
+http://sourceforge.net/projects/expat/
+
+If expat is installed, but in a non-standard directory, then use the
+following options to Makefile.PL:
+
+ EXPATLIBPATH=... To set the directory in which to find libexpat
+
+ EXPATINCPATH=... To set the directory in which to find expat.h
+
+For example:
+
+ perl Makefile.PL EXPATLIBPATH=/home/me/lib EXPATINCPATH=/home/me/include
+
+Note that if you build against a shareable library in a non-standard location
+you may (on some platforms) also have to set your LD_LIBRARY_PATH environment
+variable at run time for perl to find the library.
+
+Expat_Not_Installed;
+ }
+}
+
+# Don't try to descend into Expat directory for testing
+
+sub MY::test
+{
+ my $self = shift;
+
+ my $hold = delete $self->{DIR};
+ my $ret = $self->MM::test(@_);
+ $self->{DIR} = $hold if defined($hold);
+ $ret;
+}
+
+my @extras = ();
+
+push(@extras,
+ CAPI => 'TRUE')
+ if ($PERL_VERSION >= 5.005 and $OSNAME eq 'MSWin32'
+ and $Config{archname} =~ /-object\b/i);
+
+push(@extras,
+ ABSTRACT_FROM => 'Parser.pm',
+ AUTHOR => 'Clark Cooper (coopercc@netheaven.com)')
+ if ($ExtUtils::MakeMaker::VERSION >= 5.4301);
+
+push(@extras,
+ LICENSE => 'perl')
+ if ($ExtUtils::MakeMaker::VERSION gt '6.30');
+
+WriteMakefile(
+ NAME => 'XML::Parser',
+ DIR => [qw(Expat)],
+ dist => {COMPRESS => 'gzip', SUFFIX => '.gz'},
+ VERSION_FROM => 'Parser.pm',
+ PREREQ_PM => {
+ LWP => 0, #for tests
+ },
+ @extras
+ );
+
diff --git a/Parser.pm b/Parser.pm
new file mode 100644
index 0000000..064b021
--- /dev/null
+++ b/Parser.pm
@@ -0,0 +1,840 @@
+# XML::Parser
+#
+# Copyright (c) 1998-2000 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.
+
+package XML::Parser;
+
+use Carp;
+
+BEGIN {
+ require XML::Parser::Expat;
+ $VERSION = '2.36';
+ die "Parser.pm and Expat.pm versions don't match"
+ unless $VERSION eq $XML::Parser::Expat::VERSION;
+}
+
+use strict;
+
+use vars qw($VERSION $LWP_load_failed);
+
+$LWP_load_failed = 0;
+
+sub new {
+ my ($class, %args) = @_;
+ my $style = $args{Style};
+
+ my $nonexopt = $args{Non_Expat_Options} ||= {};
+
+ $nonexopt->{Style} = 1;
+ $nonexopt->{Non_Expat_Options} = 1;
+ $nonexopt->{Handlers} = 1;
+ $nonexopt->{_HNDL_TYPES} = 1;
+ $nonexopt->{NoLWP} = 1;
+
+ $args{_HNDL_TYPES} = {%XML::Parser::Expat::Handler_Setters};
+ $args{_HNDL_TYPES}->{Init} = 1;
+ $args{_HNDL_TYPES}->{Final} = 1;
+
+ $args{Handlers} ||= {};
+ my $handlers = $args{Handlers};
+
+ if (defined($style)) {
+ my $stylepkg = $style;
+
+ if ($stylepkg !~ /::/) {
+ $stylepkg = "\u$style";
+
+ eval {
+ my $fullpkg = 'XML::Parser::Style::' . $stylepkg;
+ my $stylefile = $fullpkg;
+ $stylefile =~ s/::/\//g;
+ require "$stylefile.pm";
+ $stylepkg = $fullpkg;
+ };
+ if ($@) {
+ # fallback to old behaviour
+ $stylepkg = 'XML::Parser::' . $stylepkg;
+ }
+ }
+
+ my $htype;
+ foreach $htype (keys %{$args{_HNDL_TYPES}}) {
+ # Handlers explicity given override
+ # handlers from the Style package
+ unless (defined($handlers->{$htype})) {
+
+ # A handler in the style package must either have
+ # exactly the right case as the type name or a
+ # completely lower case version of it.
+
+ my $hname = "${stylepkg}::$htype";
+ if (defined(&$hname)) {
+ $handlers->{$htype} = \&$hname;
+ next;
+ }
+
+ $hname = "${stylepkg}::\L$htype";
+ if (defined(&$hname)) {
+ $handlers->{$htype} = \&$hname;
+ next;
+ }
+ }
+ }
+ }
+
+ unless (defined($handlers->{ExternEnt})
+ or defined ($handlers->{ExternEntFin})) {
+
+ if ($args{NoLWP} or $LWP_load_failed) {
+ $handlers->{ExternEnt} = \&file_ext_ent_handler;
+ $handlers->{ExternEntFin} = \&file_ext_ent_cleanup;
+ }
+ else {
+ # The following just bootstraps the real LWP external entity
+ # handler
+
+ $handlers->{ExternEnt} = \&initial_ext_ent_handler;
+
+ # No cleanup function available until LWPExternEnt.pl loaded
+ }
+ }
+
+ $args{Pkg} ||= caller;
+ bless \%args, $class;
+} # End of new
+
+sub setHandlers {
+ my ($self, @handler_pairs) = @_;
+
+ croak("Uneven number of arguments to setHandlers method")
+ if (int(@handler_pairs) & 1);
+
+ my @ret;
+ while (@handler_pairs) {
+ my $type = shift @handler_pairs;
+ my $handler = shift @handler_pairs;
+ unless (defined($self->{_HNDL_TYPES}->{$type})) {
+ my @types = sort keys %{$self->{_HNDL_TYPES}};
+
+ croak("Unknown Parser handler type: $type\n Valid types: @types");
+ }
+ push(@ret, $type, $self->{Handlers}->{$type});
+ $self->{Handlers}->{$type} = $handler;
+ }
+
+ return @ret;
+}
+
+sub parse_start {
+ my $self = shift;
+ my @expat_options = ();
+
+ my ($key, $val);
+ while (($key, $val) = each %{$self}) {
+ push (@expat_options, $key, $val)
+ unless exists $self->{Non_Expat_Options}->{$key};
+ }
+
+ my %handlers = %{$self->{Handlers}};
+ my $init = delete $handlers{Init};
+ my $final = delete $handlers{Final};
+
+ my $expatnb = new XML::Parser::ExpatNB(@expat_options, @_);
+ $expatnb->setHandlers(%handlers);
+
+ &$init($expatnb)
+ if defined($init);
+
+ $expatnb->{_State_} = 1;
+
+ $expatnb->{FinalHandler} = $final
+ if defined($final);
+
+ return $expatnb;
+}
+
+sub parse {
+ my $self = shift;
+ my $arg = shift;
+ my @expat_options = ();
+ my ($key, $val);
+ while (($key, $val) = each %{$self}) {
+ push(@expat_options, $key, $val)
+ unless exists $self->{Non_Expat_Options}->{$key};
+ }
+
+ my $expat = new XML::Parser::Expat(@expat_options, @_);
+ my %handlers = %{$self->{Handlers}};
+ my $init = delete $handlers{Init};
+ my $final = delete $handlers{Final};
+
+ $expat->setHandlers(%handlers);
+
+ if ($self->{Base}) {
+ $expat->base($self->{Base});
+ }
+
+ &$init($expat)
+ if defined($init);
+
+ my @result = ();
+ my $result;
+ eval {
+ $result = $expat->parse($arg);
+ };
+ my $err = $@;
+ if ($err) {
+ $expat->release;
+ die $err;
+ }
+
+ if ($result and defined($final)) {
+ if (wantarray) {
+ @result = &$final($expat);
+ }
+ else {
+ $result = &$final($expat);
+ }
+ }
+
+ $expat->release;
+
+ return unless defined wantarray;
+ return wantarray ? @result : $result;
+}
+
+sub parsestring {
+ my $self = shift;
+ $self->parse(@_);
+}
+
+sub parsefile {
+ my $self = shift;
+ my $file = shift;
+ local(*FILE);
+ open(FILE, $file) or croak "Couldn't open $file:\n$!";
+ binmode(FILE);
+ my @ret;
+ my $ret;
+
+ $self->{Base} = $file;
+
+ if (wantarray) {
+ eval {
+ @ret = $self->parse(*FILE, @_);
+ };
+ }
+ else {
+ eval {
+ $ret = $self->parse(*FILE, @_);
+ };
+ }
+ my $err = $@;
+ close(FILE);
+ die $err if $err;
+
+ return unless defined wantarray;
+ return wantarray ? @ret : $ret;
+}
+
+sub initial_ext_ent_handler {
+ # This just bootstraps in the real lwp_ext_ent_handler which
+ # also loads the URI and LWP modules.
+
+ unless ($LWP_load_failed) {
+ local($^W) = 0;
+
+ my $stat =
+ eval {
+ require('XML/Parser/LWPExternEnt.pl');
+ };
+
+ if ($stat) {
+ $_[0]->setHandlers(ExternEnt => \&lwp_ext_ent_handler,
+ ExternEntFin => \&lwp_ext_ent_cleanup);
+
+ goto &lwp_ext_ent_handler;
+ }
+
+ # Failed to load lwp handler, act as if NoLWP
+
+ $LWP_load_failed = 1;
+
+ my $cmsg = "Couldn't load LWP based external entity handler\n";
+ $cmsg .= "Switching to file-based external entity handler\n";
+ $cmsg .= " (To avoid this message, use NoLWP option to XML::Parser)\n";
+ warn($cmsg);
+ }
+
+ $_[0]->setHandlers(ExternEnt => \&file_ext_ent_handler,
+ ExternEntFin => \&file_ext_ent_cleanup);
+ goto &file_ext_ent_handler;
+
+}
+
+sub file_ext_ent_handler {
+ my ($xp, $base, $path) = @_;
+
+ # Prepend base only for relative paths
+
+ if (defined($base)
+ and not ($path =~ m!^(?:[\\/]|\w+:)!))
+ {
+ my $newpath = $base;
+ $newpath =~ s![^\\/:]*$!$path!;
+ $path = $newpath;
+ }
+
+ if ($path =~ /^\s*[|>+]/
+ or $path =~ /\|\s*$/) {
+ $xp->{ErrorMessage}
+ .= "System ID ($path) contains Perl IO control characters";
+ return undef;
+ }
+
+ require IO::File;
+ my $fh = new IO::File($path);
+ unless (defined $fh) {
+ $xp->{ErrorMessage}
+ .= "Failed to open $path:\n$!";
+ return undef;
+ }
+
+ $xp->{_BaseStack} ||= [];
+ $xp->{_FhStack} ||= [];
+
+ push(@{$xp->{_BaseStack}}, $base);
+ push(@{$xp->{_FhStack}}, $fh);
+
+ $xp->base($path);
+
+ return $fh;
+}
+
+sub file_ext_ent_cleanup {
+ my ($xp) = @_;
+
+ my $fh = pop(@{$xp->{_FhStack}});
+ $fh->close;
+
+ my $base = pop(@{$xp->{_BaseStack}});
+ $xp->base($base);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+XML::Parser - A perl module for parsing XML documents
+
+=head1 SYNOPSIS
+
+ use XML::Parser;
+
+ $p1 = new XML::Parser(Style => 'Debug');
+ $p1->parsefile('REC-xml-19980210.xml');
+ $p1->parse('<foo id="me">Hello World</foo>');
+
+ # Alternative
+ $p2 = new XML::Parser(Handlers => {Start => \&handle_start,
+ End => \&handle_end,
+ Char => \&handle_char});
+ $p2->parse($socket);
+
+ # Another alternative
+ $p3 = new XML::Parser(ErrorContext => 2);
+
+ $p3->setHandlers(Char => \&text,
+ Default => \&other);
+
+ open(FOO, 'xmlgenerator |');
+ $p3->parse(*FOO, ProtocolEncoding => 'ISO-8859-1');
+ close(FOO);
+
+ $p3->parsefile('junk.xml', ErrorContext => 3);
+
+=begin man
+.ds PI PI
+
+=end man
+
+=head1 DESCRIPTION
+
+This module provides ways to parse XML documents. It is built on top of
+L<XML::Parser::Expat>, which is a lower level interface to James Clark's
+expat library. Each call to one of the parsing methods creates a new
+instance of XML::Parser::Expat which is then used to parse the document.
+Expat options may be provided when the XML::Parser object is created.
+These options are then passed on to the Expat object on each parse call.
+They can also be given as extra arguments to the parse methods, in which
+case they override options given at XML::Parser creation time.
+
+The behavior of the parser is controlled either by C<L</Style>> and/or
+C<L</Handlers>> options, or by L</setHandlers> method. These all provide
+mechanisms for XML::Parser to set the handlers needed by XML::Parser::Expat.
+If neither C<Style> nor C<Handlers> are specified, then parsing just
+checks the document for being well-formed.
+
+When underlying handlers get called, they receive as their first parameter
+the I<Expat> object, not the Parser object.
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+This is a class method, the constructor for XML::Parser. Options are passed
+as keyword value pairs. Recognized options are:
+
+=over 4
+
+=item * Style
+
+This option provides an easy way to create a given style of parser. The
+built in styles are: L<"Debug">, L<"Subs">, L<"Tree">, L<"Objects">,
+and L<"Stream">. These are all defined in separate packages under
+C<XML::Parser::Style::*>, and you can find further documentation for
+each style both below, and in those packages.
+
+Custom styles can be provided by giving a full package name containing
+at least one '::'. This package should then have subs defined for each
+handler it wishes to have installed. See L<"STYLES"> below
+for a discussion of each built in style.
+
+=item * Handlers
+
+When provided, this option should be an anonymous hash containing as
+keys the type of handler and as values a sub reference to handle that
+type of event. All the handlers get passed as their 1st parameter the
+instance of expat that is parsing the document. Further details on
+handlers can be found in L<"HANDLERS">. Any handler set here
+overrides the corresponding handler set with the Style option.
+
+=item * Pkg
+
+Some styles will refer to subs defined in this package. If not provided,
+it defaults to the package which called the constructor.
+
+=item * ErrorContext
+
+This is an Expat option. When this option is defined, errors are reported
+in context. The value should be the number of lines to show on either side
+of the line in which the error occurred.
+
+=item * ProtocolEncoding
+
+This is an Expat option. This sets the protocol encoding name. It defaults
+to none. The built-in encodings are: C<UTF-8>, C<ISO-8859-1>, C<UTF-16>, and
+C<US-ASCII>. Other encodings may be used if they have encoding maps in one
+of the directories in the @Encoding_Path list. Check L<"ENCODINGS"> for
+more information on encoding maps. Setting the protocol encoding overrides
+any encoding in the XML declaration.
+
+=item * Namespaces
+
+This is an Expat option. If this is set to a true value, then namespace
+processing is done during the parse. See L<XML::Parser::Expat/"Namespaces">
+for further discussion of namespace processing.
+
+=item * NoExpand
+
+This is an Expat option. Normally, the parser will try to expand references
+to entities defined in the internal subset. If this option is set to a true
+value, and a default handler is also set, then the default handler will be
+called when an entity reference is seen in text. This has no effect if a
+default handler has not been registered, and it has no effect on the expansion
+of entity references inside attribute values.
+
+=item * Stream_Delimiter
+
+This is an Expat option. It takes a string value. When this string is found
+alone on a line while parsing from a stream, then the parse is ended as if it
+saw an end of file. The intended use is with a stream of xml documents in a
+MIME multipart format. The string should not contain a trailing newline.
+
+=item * ParseParamEnt
+
+This is an Expat option. Unless standalone is set to "yes" in the XML
+declaration, setting this to a true value allows the external DTD to be read,
+and parameter entities to be parsed and expanded.
+
+=item * NoLWP
+
+This option has no effect if the ExternEnt or ExternEntFin handlers are
+directly set. Otherwise, if true, it forces the use of a file based external
+entity handler.
+
+=item * Non-Expat-Options
+
+If provided, this should be an anonymous hash whose keys are options that
+shouldn't be passed to Expat. This should only be of concern to those
+subclassing XML::Parser.
+
+=back
+
+=item setHandlers(TYPE, HANDLER [, TYPE, HANDLER [...]])
+
+This method registers handlers for various parser events. It overrides any
+previous handlers registered through the Style or Handler options or through
+earlier calls to setHandlers. By providing a false or undefined value as
+the handler, the existing handler can be unset.
+
+This method returns a list of type, handler pairs corresponding to the
+input. The handlers returned are the ones that were in effect prior to
+the call.
+
+See a description of the handler types in L<"HANDLERS">.
+
+=item parse(SOURCE [, OPT => OPT_VALUE [...]])
+
+The SOURCE parameter should either be a string containing the whole XML
+document, or it should be an open IO::Handle. Constructor options to
+XML::Parser::Expat given as keyword-value pairs may follow the SOURCE
+parameter. These override, for this call, any options or attributes passed
+through from the XML::Parser instance.
+
+A die call is thrown if a parse error occurs. Otherwise it will return 1
+or whatever is returned from the B<Final> handler, if one is installed.
+In other words, what parse may return depends on the style.
+
+=item parsestring
+
+This is just an alias for parse for backwards compatibility.
+
+=item parsefile(FILE [, OPT => OPT_VALUE [...]])
+
+Open FILE for reading, then call parse with the open handle. The file
+is closed no matter how parse returns. Returns what parse returns.
+
+=item parse_start([ OPT => OPT_VALUE [...]])
+
+Create and return a new instance of XML::Parser::ExpatNB. Constructor
+options may be provided. If an init handler has been provided, it is
+called before returning the ExpatNB object. Documents are parsed by
+making incremental calls to the parse_more method of this object, which
+takes a string. A single call to the parse_done method of this object,
+which takes no arguments, indicates that the document is finished.
+
+If there is a final handler installed, it is executed by the parse_done
+method before returning and the parse_done method returns whatever is
+returned by the final handler.
+
+=back
+
+=head1 HANDLERS
+
+Expat is an event based parser. As the parser recognizes parts of the
+document (say the start or end tag for an XML element), then any handlers
+registered for that type of an event are called with suitable parameters.
+All handlers receive an instance of XML::Parser::Expat as their first
+argument. See L<XML::Parser::Expat/"METHODS"> for a discussion of the
+methods that can be called on this object.
+
+=head2 Init (Expat)
+
+This is called just before the parsing of the document starts.
+
+=head2 Final (Expat)
+
+This is called just after parsing has finished, but only if no errors
+occurred during the parse. Parse returns what this returns.
+
+=head2 Start (Expat, Element [, Attr, Val [,...]])
+
+This event is generated when an XML start tag is recognized. Element is the
+name of the XML element type that is opened with the start tag. The Attr &
+Val pairs are generated for each attribute in the start tag.
+
+=head2 End (Expat, Element)
+
+This event is generated when an XML end tag is recognized. Note that
+an XML empty tag (<foo/>) generates both a start and an end event.
+
+=head2 Char (Expat, String)
+
+This event is generated when non-markup is recognized. The non-markup
+sequence of characters is in String. A single non-markup sequence of
+characters may generate multiple calls to this handler. Whatever the
+encoding of the string in the original document, this is given to the
+handler in UTF-8.
+
+=head2 Proc (Expat, Target, Data)
+
+This event is generated when a processing instruction is recognized.
+
+=head2 Comment (Expat, Data)
+
+This event is generated when a comment is recognized.
+
+=head2 CdataStart (Expat)
+
+This is called at the start of a CDATA section.
+
+=head2 CdataEnd (Expat)
+
+This is called at the end of a CDATA section.
+
+=head2 Default (Expat, String)
+
+This is called for any characters that don't have a registered handler.
+This includes both characters that are part of markup for which no
+events are generated (markup declarations) and characters that
+could generate events, but for which no handler has been registered.
+
+Whatever the encoding in the original document, the string is returned to
+the handler in UTF-8.
+
+=head2 Unparsed (Expat, Entity, Base, Sysid, Pubid, Notation)
+
+This is called for a declaration of an unparsed entity. Entity is the name
+of the entity. Base is the base to be used for resolving a relative URI.
+Sysid is the system id. Pubid is the public id. Notation is the notation
+name. Base and Pubid may be undefined.
+
+=head2 Notation (Expat, Notation, Base, Sysid, Pubid)
+
+This is called for a declaration of notation. Notation is the notation name.
+Base is the base to be used for resolving a relative URI. Sysid is the system
+id. Pubid is the public id. Base, Sysid, and Pubid may all be undefined.
+
+=head2 ExternEnt (Expat, Base, Sysid, Pubid)
+
+This is called when an external entity is referenced. Base is the base to be
+used for resolving a relative URI. Sysid is the system id. Pubid is the public
+id. Base, and Pubid may be undefined.
+
+This handler should either return a string, which represents the contents of
+the external entity, or return an open filehandle that can be read to obtain
+the contents of the external entity, or return undef, which indicates the
+external entity couldn't be found and will generate a parse error.
+
+If an open filehandle is returned, it must be returned as either a glob
+(*FOO) or as a reference to a glob (e.g. an instance of IO::Handle).
+
+A default handler is installed for this event. The default handler is
+XML::Parser::lwp_ext_ent_handler unless the NoLWP option was provided with
+a true value, otherwise XML::Parser::file_ext_ent_handler is the default
+handler for external entities. Even without the NoLWP option, if the
+URI or LWP modules are missing, the file based handler ends up being used
+after giving a warning on the first external entity reference.
+
+The LWP external entity handler will use proxies defined in the environment
+(http_proxy, ftp_proxy, etc.).
+
+Please note that the LWP external entity handler reads the entire
+entity into a string and returns it, where as the file handler opens a
+filehandle.
+
+Also note that the file external entity handler will likely choke on
+absolute URIs or file names that don't fit the conventions of the local
+operating system.
+
+The expat base method can be used to set a basename for
+relative pathnames. If no basename is given, or if the basename is itself
+a relative name, then it is relative to the current working directory.
+
+=head2 ExternEntFin (Expat)
+
+This is called after parsing an external entity. It's not called unless
+an ExternEnt handler is also set. There is a default handler installed
+that pairs with the default ExternEnt handler.
+
+If you're going to install your own ExternEnt handler, then you should
+set (or unset) this handler too.
+
+=head2 Entity (Expat, Name, Val, Sysid, Pubid, Ndata, IsParam)
+
+This is called when an entity is declared. For internal entities, the Val
+parameter will contain the value and the remaining three parameters will be
+undefined. For external entities, the Val parameter will be undefined, the
+Sysid parameter will have the system id, the Pubid parameter will have the
+public id if it was provided (it will be undefined otherwise), the Ndata
+parameter will contain the notation for unparsed entities. If this is a
+parameter entity declaration, then the IsParam parameter is true.
+
+Note that this handler and the Unparsed handler above overlap. If both are
+set, then this handler will not be called for unparsed entities.
+
+=head2 Element (Expat, Name, Model)
+
+The element handler is called when an element declaration is found. Name
+is the element name, and Model is the content model as an XML::Parser::Content
+object. See L<XML::Parser::Expat/"XML::Parser::ContentModel Methods">
+for methods available for this class.
+
+=head2 Attlist (Expat, Elname, Attname, Type, Default, Fixed)
+
+This handler is called for each attribute in an ATTLIST declaration.
+So an ATTLIST declaration that has multiple attributes will generate multiple
+calls to this handler. The Elname parameter is the name of the element with
+which the attribute is being associated. The Attname parameter is the name
+of the attribute. Type is the attribute type, given as a string. Default is
+the default value, which will either be "#REQUIRED", "#IMPLIED" or a quoted
+string (i.e. the returned string will begin and end with a quote character).
+If Fixed is true, then this is a fixed attribute.
+
+=head2 Doctype (Expat, Name, Sysid, Pubid, Internal)
+
+This handler is called for DOCTYPE declarations. Name is the document type
+name. Sysid is the system id of the document type, if it was provided,
+otherwise it's undefined. Pubid is the public id of the document type,
+which will be undefined if no public id was given. Internal is the internal
+subset, given as a string. If there was no internal subset, it will be
+undefined. Internal will contain all whitespace, comments, processing
+instructions, and declarations seen in the internal subset. The declarations
+will be there whether or not they have been processed by another handler
+(except for unparsed entities processed by the Unparsed handler). However,
+comments and processing instructions will not appear if they've been processed
+by their respective handlers.
+
+=head2 * DoctypeFin (Parser)
+
+This handler is called after parsing of the DOCTYPE declaration has finished,
+including any internal or external DTD declarations.
+
+=head2 XMLDecl (Expat, Version, Encoding, Standalone)
+
+This handler is called for xml declarations. Version is a string containg
+the version. Encoding is either undefined or contains an encoding string.
+Standalone will be either true, false, or undefined if the standalone attribute
+is yes, no, or not made respectively.
+
+=head1 STYLES
+
+=head2 Debug
+
+This just prints out the document in outline form. Nothing special is
+returned by parse.
+
+=head2 Subs
+
+Each time an element starts, a sub by that name in the package specified
+by the Pkg option is called with the same parameters that the Start
+handler gets called with.
+
+Each time an element ends, a sub with that name appended with an underscore
+("_"), is called with the same parameters that the End handler gets called
+with.
+
+Nothing special is returned by parse.
+
+=head2 Tree
+
+Parse will return a parse tree for the document. Each node in the tree
+takes the form of a tag, content pair. Text nodes are represented with
+a pseudo-tag of "0" and the string that is their content. For elements,
+the content is an array reference. The first item in the array is a
+(possibly empty) hash reference containing attributes. The remainder of
+the array is a sequence of tag-content pairs representing the content
+of the element.
+
+So for example the result of parsing:
+
+ <foo><head id="a">Hello <em>there</em></head><bar>Howdy<ref/></bar>do</foo>
+
+would be:
+
+ Tag Content
+ ==================================================================
+ [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]],
+ bar, [ {}, 0, "Howdy", ref, [{}]],
+ 0, "do"
+ ]
+ ]
+
+The root document "foo", has 3 children: a "head" element, a "bar"
+element and the text "do". After the empty attribute hash, these are
+represented in it's contents by 3 tag-content pairs.
+
+=head2 Objects
+
+This is similar to the Tree style, except that a hash object is created for
+each element. The corresponding object will be in the class whose name
+is created by appending "::" and the element name to the package set with
+the Pkg option. Non-markup text will be in the ::Characters class. The
+contents of the corresponding object will be in an anonymous array that
+is the value of the Kids property for that object.
+
+=head2 Stream
+
+This style also uses the Pkg package. If none of the subs that this
+style looks for is there, then the effect of parsing with this style is
+to print a canonical copy of the document without comments or declarations.
+All the subs receive as their 1st parameter the Expat instance for the
+document they're parsing.
+
+It looks for the following routines:
+
+=over 4
+
+=item * StartDocument
+
+Called at the start of the parse .
+
+=item * StartTag
+
+Called for every start tag with a second parameter of the element type. The $_
+variable will contain a copy of the tag and the %_ variable will contain
+attribute values supplied for that element.
+
+=item * EndTag
+
+Called for every end tag with a second parameter of the element type. The $_
+variable will contain a copy of the end tag.
+
+=item * Text
+
+Called just before start or end tags with accumulated non-markup text in
+the $_ variable.
+
+=item * PI
+
+Called for processing instructions. The $_ variable will contain a copy of
+the PI and the target and data are sent as 2nd and 3rd parameters
+respectively.
+
+=item * EndDocument
+
+Called at conclusion of the parse.
+
+=back
+
+=head1 ENCODINGS
+
+XML documents may be encoded in character sets other than Unicode as
+long as they may be mapped into the Unicode character set. Expat has
+further restrictions on encodings. Read the xmlparse.h header file in
+the expat distribution to see details on these restrictions.
+
+Expat has built-in encodings for: C<UTF-8>, C<ISO-8859-1>, C<UTF-16>, and
+C<US-ASCII>. Encodings are set either through the XML declaration
+encoding attribute or through the ProtocolEncoding option to XML::Parser
+or XML::Parser::Expat.
+
+For encodings other than the built-ins, expat calls the function
+load_encoding in the Expat package with the encoding name. This function
+looks for a file in the path list @XML::Parser::Expat::Encoding_Path, that
+matches the lower-cased name with a '.enc' extension. The first one it
+finds, it loads.
+
+If you wish to build your own encoding maps, check out the XML::Encoding
+module from CPAN.
+
+=head1 AUTHORS
+
+Larry Wall <F<larry@wall.org>> wrote version 1.0.
+
+Clark Cooper <F<coopercc@netheaven.com>> picked up support, changed the API
+for this version (2.x), provided documentation,
+and added some standard package features.
+
+Matt Sergeant <F<matt@sergeant.org>> is now maintaining XML::Parser
+
+=cut
diff --git a/Parser/Encodings/Japanese_Encodings.msg b/Parser/Encodings/Japanese_Encodings.msg
new file mode 100644
index 0000000..6912e70
--- /dev/null
+++ b/Parser/Encodings/Japanese_Encodings.msg
@@ -0,0 +1,117 @@
+Mapping files for Japanese encodings
+
+1998 12/25
+
+Fuji Xerox Information Systems
+MURATA Makoto
+
+1. Overview
+
+This version of XML::Parser and XML::Encoding does not come with map files for
+the charset "Shift_JIS" and the charset "euc-jp". Unfortunately, each of these
+charsets has more than one mapping. None of these mappings are
+considered as authoritative.
+
+Therefore, we have come to believe that it is dangerous to provide map files
+for these charsets. Rather, we introduce several private charsets and map
+files for these private charsets. If IANA, Unicode Consoritum, and JIS
+eventually reach a consensus, we will be able to provide map files for
+"Shift_JIS" and "euc-jp".
+
+2. Different mappings from existing charsets to Unicode
+
+1) Different mappings in JIS X0221 and Unicode
+
+The mapping between JIS X0208:1990 and Unicode 1.1 and the mapping
+between JIS X0212:1990 and Unicode 1.1 are published from Unicode
+consortium. They are available at
+ftp://ftp.unicode.org/Public/MAPPINGS/EASTASIA/JIS/JIS0208.TXT and
+ftp://ftp.unicode.org/Public/MAPPINGS/EASTASIA/JIS/JIS0212.TXT,
+respectively.) These mapping files have a note as below:
+
+# The kanji mappings are a normative part of ISO/IEC 10646. The
+# non-kanji mappings are provisional, pending definition of
+# official mappings by Japanese standards bodies.
+
+Unfortunately, the non-kanji mappings in the Japanese standard for ISO 10646/1,
+namely JIS X 0221:1995, is different from the Unicode Consortium mapping since
+0x213D of JIS X 0208 is mapped to U+2014 (em dash) rather than U+2015
+(horizontal bar). Furthermore, JIS X 0221 clearly says that the mapping is
+informational and non-normative. As a result, some companies (e.g., Microsoft and
+Apple) have introduced slightly different mappings. Therefore, neither the
+Unicode consortium mapping nor the JIS X 0221 mapping are considered as
+authoritative.
+
+2) Shift-JIS
+
+This charset is especially problematic, since its definition has been unclear
+since its inception.
+
+The current registration of the charset "Shift_JIS" is as below:
+
+>Name: Shift_JIS (preferred MIME name)
+>MIBenum: 17
+>Source: A Microsoft code that extends csHalfWidthKatakana to include
+> kanji by adding a second byte when the value of the first
+> byte is in the ranges 81-9F or E0-EF.
+>Alias: MS_Kanji
+>Alias: csShiftJIS
+
+First, this does not reference to the mapping "Shift-JIS to Unicode"
+published by the Unicode consortium (available at
+ftp://ftp.unicode.org/Public/MAPPINGS/EASTASIA/JIS/SHIFTJIS.TXT).
+
+Second, "kanji" in this registration can be interepreted in different ways.
+Does this "kanji" reference to JIS X0208:1978, JIS X0208:1983, or JIS
+X0208:1990(== JIS X0208:1997)? These three standards are *incompatible* with
+each other. Moreover, we can even argue that "kanji" refers to JIS X0212 or
+ideographic characters in other countries.
+
+Third, each company has extended Shift JIS. For example, Microsoft introduced
+OEM extensions (NEC extensionsand IBM extensions).
+
+Forth, Shift JIS uses JIS X0201, which is almost upper-compatible with US-ASCII
+but is not quite. 5C and 7E of JIS X 0201 are different from backslash and
+tilde, respectively. However, many programming languages (e.g., Java)
+ignore this difference and assumes that 5C and 7E of Shift JIS are backslash
+and tilde.
+
+
+3. Proposed charsets and mappings
+
+As a tentative solution, we introduce two private charsets for EUC-JP and four
+priviate charsets for Shift JIS.
+
+1) EUC-JP
+
+We have two charsets, namely "x-eucjp-unicode" and "x-eucjp-jisx0221". Their
+difference is only one code point. The mapping for the former is based
+on the Unicode Consortium mapping, while the latter is based on the JIS X0221
+mapping.
+
+2) Shift JIS
+
+We have four charsets, namely x-sjis-unicode, x-sjis-jisx0221,
+x-sjis-jdk117, and x-sjis-cp932.
+
+The mapping for the charset x-sjis-unicode is the one published by the Unicode
+consortium. The mapping for x-sjis-jisx0221 is almost equivalent to
+x-sjis-unicode, but 0x213D of JIS X 0208 is mapped to U+2014 (em dash) rather
+than U+2015. The charset x-sjis-jdk117 is again almost equivalent to
+x-sjis-unicode, but 0x5C and 0x7E of JIS X0201 are mapped to backslash and
+tilde.
+
+The charset x-sjis-cp932 is used by Microsoft Windows, and its mapping is
+published from the Unicode Consortium (available at:
+ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP932.txt). The
+coded character set for this charset includes NEC-extensions and
+IBM-extensions. 0x5C and 0x7E of JIS X0201 are mapped to backslash and tilde;
+0x213D is mapped to U+2015; and 0x2140, 0x2141, 0x2142, and 0x215E of JIS X
+0208 are mapped to compatibility characters.
+
+Makoto
+
+Fuji Xerox Information Systems
+
+Tel: +81-44-812-7230 Fax: +81-44-812-7231
+E-mail: murata@apsdc.ksp.fujixerox.co.jp
diff --git a/Parser/Encodings/README b/Parser/Encodings/README
new file mode 100644
index 0000000..576323c
--- /dev/null
+++ b/Parser/Encodings/README
@@ -0,0 +1,51 @@
+This directory contains binary encoding maps for some selected encodings.
+If they are placed in a directoy listed in @XML::Parser::Expat::Encoding_Path,
+then they are automaticly loaded by the XML::Parser::Expat::load_encoding
+function as needed. Otherwise you may load what you need directly by
+explicity calling this function.
+
+These maps were generated by a perl script that comes with the module
+XML::Encoding, compile_encoding, from XML formatted encoding maps that
+are distributed with that module. These XML encoding maps were generated
+in turn with a different script, domap, from mapping information contained
+on the Unicode version 2.0 CD-ROM. This CD-ROM comes with the Unicode
+Standard reference manual and can be ordered from the Unicode Consortium
+at http://www.unicode.org. The identical information is available on the
+internet at ftp://ftp.unicode.org/Public/MAPPINGS.
+
+See the encoding.h header in the Expat sub-directory for a description of
+the structure of these files.
+
+Clark Cooper
+December 12, 1998
+
+================================================================
+
+Contributed maps
+
+This distribution contains four contributed encodings from MURATA Makoto
+<murata@apsdc.ksp.fujixerox.co.jp> that are variations on the encoding
+commonly called Shift_JIS:
+
+x-sjis-cp932.enc
+x-sjis-jdk117.enc
+x-sjis-jisx0221.enc
+x-sjis-unicode.enc (This is the same encoding as the shift_jis.enc that
+ was distributed with this module in version 2.17)
+
+Please read his message (Japanese_Encodings.msg) about why these are here
+and why I've removed the shift_jis.enc encoding.
+
+We also have two contributed encodings that are variations of the EUC-JP
+encoding from Yoshida Masato <yoshidam@inse.co.jp>:
+
+x-euc-jp-jisx0221.enc
+x-euc-jp-unicode.enc
+
+The comments that MURATA Makoto made in his message apply to these
+encodings too.
+
+KangChan Lee <dolphin@comeng.chungnam.ac.kr> supplied the euc-kr encoding.
+
+Clark Cooper
+December 26, 1998
diff --git a/Parser/Encodings/big5.enc b/Parser/Encodings/big5.enc
new file mode 100644
index 0000000..94b2bd4
--- /dev/null
+++ b/Parser/Encodings/big5.enc
Binary files differ
diff --git a/Parser/Encodings/euc-kr.enc b/Parser/Encodings/euc-kr.enc
new file mode 100644
index 0000000..3da8a13
--- /dev/null
+++ b/Parser/Encodings/euc-kr.enc
Binary files differ
diff --git a/Parser/Encodings/iso-8859-2.enc b/Parser/Encodings/iso-8859-2.enc
new file mode 100644
index 0000000..d320d7f
--- /dev/null
+++ b/Parser/Encodings/iso-8859-2.enc
Binary files differ
diff --git a/Parser/Encodings/iso-8859-3.enc b/Parser/Encodings/iso-8859-3.enc
new file mode 100644
index 0000000..ba48378
--- /dev/null
+++ b/Parser/Encodings/iso-8859-3.enc
Binary files differ
diff --git a/Parser/Encodings/iso-8859-4.enc b/Parser/Encodings/iso-8859-4.enc
new file mode 100644
index 0000000..0294a24
--- /dev/null
+++ b/Parser/Encodings/iso-8859-4.enc
Binary files differ
diff --git a/Parser/Encodings/iso-8859-5.enc b/Parser/Encodings/iso-8859-5.enc
new file mode 100644
index 0000000..6dbd169
--- /dev/null
+++ b/Parser/Encodings/iso-8859-5.enc
Binary files differ
diff --git a/Parser/Encodings/iso-8859-7.enc b/Parser/Encodings/iso-8859-7.enc
new file mode 100644
index 0000000..02a4aee
--- /dev/null
+++ b/Parser/Encodings/iso-8859-7.enc
Binary files differ
diff --git a/Parser/Encodings/iso-8859-8.enc b/Parser/Encodings/iso-8859-8.enc
new file mode 100644
index 0000000..f211bd5
--- /dev/null
+++ b/Parser/Encodings/iso-8859-8.enc
Binary files differ
diff --git a/Parser/Encodings/iso-8859-9.enc b/Parser/Encodings/iso-8859-9.enc
new file mode 100644
index 0000000..fdc574b
--- /dev/null
+++ b/Parser/Encodings/iso-8859-9.enc
Binary files differ
diff --git a/Parser/Encodings/windows-1250.enc b/Parser/Encodings/windows-1250.enc
new file mode 100644
index 0000000..d4a64b5
--- /dev/null
+++ b/Parser/Encodings/windows-1250.enc
Binary files differ
diff --git a/Parser/Encodings/windows-1252.enc b/Parser/Encodings/windows-1252.enc
new file mode 100644
index 0000000..ab2d57c
--- /dev/null
+++ b/Parser/Encodings/windows-1252.enc
Binary files differ
diff --git a/Parser/Encodings/x-euc-jp-jisx0221.enc b/Parser/Encodings/x-euc-jp-jisx0221.enc
new file mode 100644
index 0000000..ca79c07
--- /dev/null
+++ b/Parser/Encodings/x-euc-jp-jisx0221.enc
Binary files differ
diff --git a/Parser/Encodings/x-euc-jp-unicode.enc b/Parser/Encodings/x-euc-jp-unicode.enc
new file mode 100644
index 0000000..34d4d0d
--- /dev/null
+++ b/Parser/Encodings/x-euc-jp-unicode.enc
Binary files differ
diff --git a/Parser/Encodings/x-sjis-cp932.enc b/Parser/Encodings/x-sjis-cp932.enc
new file mode 100644
index 0000000..c2a6bc4
--- /dev/null
+++ b/Parser/Encodings/x-sjis-cp932.enc
Binary files differ
diff --git a/Parser/Encodings/x-sjis-jdk117.enc b/Parser/Encodings/x-sjis-jdk117.enc
new file mode 100644
index 0000000..b6c2c07
--- /dev/null
+++ b/Parser/Encodings/x-sjis-jdk117.enc
Binary files differ
diff --git a/Parser/Encodings/x-sjis-jisx0221.enc b/Parser/Encodings/x-sjis-jisx0221.enc
new file mode 100644
index 0000000..cbb2db5
--- /dev/null
+++ b/Parser/Encodings/x-sjis-jisx0221.enc
Binary files differ
diff --git a/Parser/Encodings/x-sjis-unicode.enc b/Parser/Encodings/x-sjis-unicode.enc
new file mode 100644
index 0000000..6f88a06
--- /dev/null
+++ b/Parser/Encodings/x-sjis-unicode.enc
Binary files differ
diff --git a/Parser/LWPExternEnt.pl b/Parser/LWPExternEnt.pl
new file mode 100644
index 0000000..d0c940b
--- /dev/null
+++ b/Parser/LWPExternEnt.pl
@@ -0,0 +1,71 @@
+# LWPExternEnt.pl
+#
+# Copyright (c) 2000 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.
+
+package XML::Parser;
+
+use URI;
+use URI::file;
+use LWP;
+
+##
+## Note that this external entity handler reads the entire entity into
+## memory, so it will choke on huge ones. It would be really nice if
+## LWP::UserAgent optionally returned us an IO::Handle.
+##
+
+sub lwp_ext_ent_handler {
+ my ($xp, $base, $sys) = @_; # We don't use public id
+
+ my $uri;
+
+ if (defined $base) {
+ # Base may have been set by parsefile, which is agnostic about
+ # whether its a file or URI.
+ my $base_uri = new URI($base);
+ unless (defined $base_uri->scheme) {
+ $base_uri = URI->new_abs($base_uri, URI::file->cwd);
+ }
+
+ $uri = URI->new_abs($sys, $base_uri);
+ }
+ else {
+ $uri = new URI($sys);
+ unless (defined $uri->scheme) {
+ $uri = URI->new_abs($uri, URI::file->cwd);
+ }
+ }
+
+ my $ua = $xp->{_lwpagent};
+ unless (defined $ua) {
+ $ua = $xp->{_lwpagent} = new LWP::UserAgent();
+ $ua->env_proxy();
+ }
+
+ my $req = new HTTP::Request('GET', $uri);
+
+ my $res = $ua->request($req);
+ if ($res->is_error) {
+ $xp->{ErrorMessage} .= "\n" . $res->status_line . " $uri";
+ return undef;
+ }
+
+ $xp->{_BaseStack} ||= [];
+ push(@{$xp->{_BaseStack}}, $base);
+
+ $xp->base($uri);
+
+ return $res->content;
+} # End lwp_ext_ent_handler
+
+sub lwp_ext_ent_cleanup {
+ my ($xp) = @_;
+
+ $xp->base(pop(@{$xp->{_BaseStack}}));
+} # End lwp_ext_ent_cleanup
+
+1;
diff --git a/Parser/Style/Debug.pm b/Parser/Style/Debug.pm
new file mode 100644
index 0000000..89fcd8b
--- /dev/null
+++ b/Parser/Style/Debug.pm
@@ -0,0 +1,52 @@
+# $Id: Debug.pm,v 1.1 2003/07/27 16:07:49 matt Exp $
+
+package XML::Parser::Style::Debug;
+use strict;
+
+sub Start {
+ my $expat = shift;
+ my $tag = shift;
+ print STDERR "@{$expat->{Context}} \\\\ (@_)\n";
+}
+
+sub End {
+ my $expat = shift;
+ my $tag = shift;
+ print STDERR "@{$expat->{Context}} //\n";
+}
+
+sub Char {
+ my $expat = shift;
+ my $text = shift;
+ $text =~ s/([\x80-\xff])/sprintf "#x%X;", ord $1/eg;
+ $text =~ s/([\t\n])/sprintf "#%d;", ord $1/eg;
+ print STDERR "@{$expat->{Context}} || $text\n";
+}
+
+sub Proc {
+ my $expat = shift;
+ my $target = shift;
+ my $text = shift;
+ my @foo = @{$expat->{Context}};
+ print STDERR "@foo $target($text)\n";
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::Parser::Style::Debug - Debug style for XML::Parser
+
+=head1 SYNOPSIS
+
+ use XML::Parser;
+ my $p = XML::Parser->new(Style => 'Debug');
+ $p->parsefile('foo.xml');
+
+=head1 DESCRIPTION
+
+This just prints out the document in outline form to STDERR. Nothing special is
+returned by parse.
+
+=cut \ No newline at end of file
diff --git a/Parser/Style/Objects.pm b/Parser/Style/Objects.pm
new file mode 100644
index 0000000..8603db0
--- /dev/null
+++ b/Parser/Style/Objects.pm
@@ -0,0 +1,78 @@
+# $Id: Objects.pm,v 1.1 2003/08/18 20:20:51 matt Exp $
+
+package XML::Parser::Style::Objects;
+use strict;
+
+sub Init {
+ my $expat = shift;
+ $expat->{Lists} = [];
+ $expat->{Curlist} = $expat->{Tree} = [];
+}
+
+sub Start {
+ my $expat = shift;
+ my $tag = shift;
+ my $newlist = [ ];
+ my $class = "${$expat}{Pkg}::$tag";
+ my $newobj = bless { @_, Kids => $newlist }, $class;
+ push @{ $expat->{Lists} }, $expat->{Curlist};
+ push @{ $expat->{Curlist} }, $newobj;
+ $expat->{Curlist} = $newlist;
+}
+
+sub End {
+ my $expat = shift;
+ my $tag = shift;
+ $expat->{Curlist} = pop @{ $expat->{Lists} };
+}
+
+sub Char {
+ my $expat = shift;
+ my $text = shift;
+ my $class = "${$expat}{Pkg}::Characters";
+ my $clist = $expat->{Curlist};
+ my $pos = $#$clist;
+
+ if ($pos >= 0 and ref($clist->[$pos]) eq $class) {
+ $clist->[$pos]->{Text} .= $text;
+ } else {
+ push @$clist, bless { Text => $text }, $class;
+ }
+}
+
+sub Final {
+ my $expat = shift;
+ delete $expat->{Curlist};
+ delete $expat->{Lists};
+ $expat->{Tree};
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::Parser::Style::Objects
+
+=head1 SYNOPSIS
+
+ use XML::Parser;
+ my $p = XML::Parser->new(Style => 'Objects', Pkg => 'MyNode');
+ my $tree = $p->parsefile('foo.xml');
+
+=head1 DESCRIPTION
+
+This module implements XML::Parser's Objects style parser.
+
+This is similar to the Tree style, except that a hash object is created for
+each element. The corresponding object will be in the class whose name
+is created by appending "::" and the element name to the package set with
+the Pkg option. Non-markup text will be in the ::Characters class. The
+contents of the corresponding object will be in an anonymous array that
+is the value of the Kids property for that object.
+
+=head1 SEE ALSO
+
+L<XML::Parser::Style::Tree>
+
+=cut \ No newline at end of file
diff --git a/Parser/Style/Stream.pm b/Parser/Style/Stream.pm
new file mode 100644
index 0000000..1e2e3f7
--- /dev/null
+++ b/Parser/Style/Stream.pm
@@ -0,0 +1,184 @@
+# $Id: Stream.pm,v 1.1 2003/07/27 16:07:49 matt Exp $
+
+package XML::Parser::Style::Stream;
+use strict;
+
+# This style invented by Tim Bray <tbray@textuality.com>
+
+sub Init {
+ no strict 'refs';
+ my $expat = shift;
+ $expat->{Text} = '';
+ my $sub = $expat->{Pkg} ."::StartDocument";
+ &$sub($expat)
+ if defined(&$sub);
+}
+
+sub Start {
+ no strict 'refs';
+ my $expat = shift;
+ my $type = shift;
+
+ doText($expat);
+ $_ = "<$type";
+
+ %_ = @_;
+ while (@_) {
+ $_ .= ' ' . shift() . '="' . shift() . '"';
+ }
+ $_ .= '>';
+
+ my $sub = $expat->{Pkg} . "::StartTag";
+ if (defined(&$sub)) {
+ &$sub($expat, $type);
+ } else {
+ print;
+ }
+}
+
+sub End {
+ no strict 'refs';
+ my $expat = shift;
+ my $type = shift;
+
+ # Set right context for Text handler
+ push(@{$expat->{Context}}, $type);
+ doText($expat);
+ pop(@{$expat->{Context}});
+
+ $_ = "</$type>";
+
+ my $sub = $expat->{Pkg} . "::EndTag";
+ if (defined(&$sub)) {
+ &$sub($expat, $type);
+ } else {
+ print;
+ }
+}
+
+sub Char {
+ my $expat = shift;
+ $expat->{Text} .= shift;
+}
+
+sub Proc {
+ no strict 'refs';
+ my $expat = shift;
+ my $target = shift;
+ my $text = shift;
+
+ doText($expat);
+
+ $_ = "<?$target $text?>";
+
+ my $sub = $expat->{Pkg} . "::PI";
+ if (defined(&$sub)) {
+ &$sub($expat, $target, $text);
+ } else {
+ print;
+ }
+}
+
+sub Final {
+ no strict 'refs';
+ my $expat = shift;
+ my $sub = $expat->{Pkg} . "::EndDocument";
+ &$sub($expat)
+ if defined(&$sub);
+}
+
+sub doText {
+ no strict 'refs';
+ my $expat = shift;
+ $_ = $expat->{Text};
+
+ if (length($_)) {
+ my $sub = $expat->{Pkg} . "::Text";
+ if (defined(&$sub)) {
+ &$sub($expat);
+ } else {
+ print;
+ }
+
+ $expat->{Text} = '';
+ }
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::Parser::Style::Stream - Stream style for XML::Parser
+
+=head1 SYNOPSIS
+
+ use XML::Parser;
+ my $p = XML::Parser->new(Style => 'Stream', Pkg => 'MySubs');
+ $p->parsefile('foo.xml');
+
+ {
+ package MySubs;
+
+ sub StartTag {
+ my ($e, $name) = @_;
+ # do something with start tags
+ }
+
+ sub EndTag {
+ my ($e, $name) = @_;
+ # do something with end tags
+ }
+
+ sub Characters {
+ my ($e, $data) = @_;
+ # do something with text nodes
+ }
+ }
+
+=head1 DESCRIPTION
+
+This style uses the Pkg option to find subs in a given package to call for each event.
+If none of the subs that this
+style looks for is there, then the effect of parsing with this style is
+to print a canonical copy of the document without comments or declarations.
+All the subs receive as their 1st parameter the Expat instance for the
+document they're parsing.
+
+It looks for the following routines:
+
+=over 4
+
+=item * StartDocument
+
+Called at the start of the parse .
+
+=item * StartTag
+
+Called for every start tag with a second parameter of the element type. The $_
+variable will contain a copy of the tag and the %_ variable will contain
+attribute values supplied for that element.
+
+=item * EndTag
+
+Called for every end tag with a second parameter of the element type. The $_
+variable will contain a copy of the end tag.
+
+=item * Text
+
+Called just before start or end tags with accumulated non-markup text in
+the $_ variable.
+
+=item * PI
+
+Called for processing instructions. The $_ variable will contain a copy of
+the PI and the target and data are sent as 2nd and 3rd parameters
+respectively.
+
+=item * EndDocument
+
+Called at conclusion of the parse.
+
+=back
+
+=cut \ No newline at end of file
diff --git a/Parser/Style/Subs.pm b/Parser/Style/Subs.pm
new file mode 100644
index 0000000..15a2143
--- /dev/null
+++ b/Parser/Style/Subs.pm
@@ -0,0 +1,58 @@
+# $Id: Subs.pm,v 1.1 2003/07/27 16:07:49 matt Exp $
+
+package XML::Parser::Style::Subs;
+
+sub Start {
+ no strict 'refs';
+ my $expat = shift;
+ my $tag = shift;
+ my $sub = $expat->{Pkg} . "::$tag";
+ eval { &$sub($expat, $tag, @_) };
+}
+
+sub End {
+ no strict 'refs';
+ my $expat = shift;
+ my $tag = shift;
+ my $sub = $expat->{Pkg} . "::${tag}_";
+ eval { &$sub($expat, $tag) };
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::Parser::Style::Subs
+
+=head1 SYNOPSIS
+
+ use XML::Parser;
+ my $p = XML::Parser->new(Style => 'Subs', Pkg => 'MySubs');
+ $p->parsefile('foo.xml');
+
+ {
+ package MySubs;
+
+ sub foo {
+ # start of foo tag
+ }
+
+ sub foo_ {
+ # end of foo tag
+ }
+ }
+
+=head1 DESCRIPTION
+
+Each time an element starts, a sub by that name in the package specified
+by the Pkg option is called with the same parameters that the Start
+handler gets called with.
+
+Each time an element ends, a sub with that name appended with an underscore
+("_"), is called with the same parameters that the End handler gets called
+with.
+
+Nothing special is returned by parse.
+
+=cut \ No newline at end of file
diff --git a/Parser/Style/Tree.pm b/Parser/Style/Tree.pm
new file mode 100644
index 0000000..c0e69f1
--- /dev/null
+++ b/Parser/Style/Tree.pm
@@ -0,0 +1,90 @@
+# $Id: Tree.pm,v 1.2 2003/07/31 07:54:51 matt Exp $
+
+package XML::Parser::Style::Tree;
+$XML::Parser::Built_In_Styles{Tree} = 1;
+
+sub Init {
+ my $expat = shift;
+ $expat->{Lists} = [];
+ $expat->{Curlist} = $expat->{Tree} = [];
+}
+
+sub Start {
+ my $expat = shift;
+ my $tag = shift;
+ my $newlist = [ { @_ } ];
+ push @{ $expat->{Lists} }, $expat->{Curlist};
+ push @{ $expat->{Curlist} }, $tag => $newlist;
+ $expat->{Curlist} = $newlist;
+}
+
+sub End {
+ my $expat = shift;
+ my $tag = shift;
+ $expat->{Curlist} = pop @{ $expat->{Lists} };
+}
+
+sub Char {
+ my $expat = shift;
+ my $text = shift;
+ my $clist = $expat->{Curlist};
+ my $pos = $#$clist;
+
+ if ($pos > 0 and $clist->[$pos - 1] eq '0') {
+ $clist->[$pos] .= $text;
+ } else {
+ push @$clist, 0 => $text;
+ }
+}
+
+sub Final {
+ my $expat = shift;
+ delete $expat->{Curlist};
+ delete $expat->{Lists};
+ $expat->{Tree};
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::Parser::Style::Tree
+
+=head1 SYNOPSIS
+
+ use XML::Parser;
+ my $p = XML::Parser->new(Style => 'Tree');
+ my $tree = $p->parsefile('foo.xml');
+
+=head1 DESCRIPTION
+
+This module implements XML::Parser's Tree style parser.
+
+When parsing a document, C<parse()> will return a parse tree for the
+document. Each node in the tree
+takes the form of a tag, content pair. Text nodes are represented with
+a pseudo-tag of "0" and the string that is their content. For elements,
+the content is an array reference. The first item in the array is a
+(possibly empty) hash reference containing attributes. The remainder of
+the array is a sequence of tag-content pairs representing the content
+of the element.
+
+So for example the result of parsing:
+
+ <foo><head id="a">Hello <em>there</em></head><bar>Howdy<ref/></bar>do</foo>
+
+would be:
+ Tag Content
+ ==================================================================
+ [foo, [{}, head, [{id => "a"}, 0, "Hello ", em, [{}, 0, "there"]],
+ bar, [ {}, 0, "Howdy", ref, [{}]],
+ 0, "do"
+ ]
+ ]
+
+The root document "foo", has 3 children: a "head" element, a "bar"
+element and the text "do". After the empty attribute hash, these are
+represented in it's contents by 3 tag-content pairs.
+
+=cut
diff --git a/README b/README
new file mode 100644
index 0000000..7fbbb22
--- /dev/null
+++ b/README
@@ -0,0 +1,86 @@
+ XML::Parser Version 2.31
+
+Copyright (c) 1998-2000 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.
+
+This is a Perl extension interface to James Clark's XML parser, expat.
+It requires at least version 5.004 of perl and it requires that you have
+release 1.95.0 or greater of expat installed. You can download expat
+from:
+
+ http://sourceforge.net/projects/expat/
+
+The documentation for this extension can be found in pod format at the end
+of the files Parser.pm and Expat/Expat.pm. The perldoc program, provided with
+the perl distribution, can be used to view this documentation.
+
+This was modified from the original XML::Parser created by Larry Wall.
+
+To configure this module, cd to the directory that contains this README file
+and type the following:
+
+ perl Makefile.PL
+
+Alternatively, if you plan to install XML::Parser somewhere other than
+your system's perl library directory. You can type something like this:
+
+ perl Makefile.PL PREFIX=/home/me/perl INSTALLDIRS=perl
+
+Then to build you run make.
+
+ make
+
+You can then test the module by typing:
+
+ make test
+
+There are some sample utilities in the samples directory along with an
+xml form of the XML specification to test them on. You may need to change
+the '#!' line at the top of these utilities to what is appropriate for
+your system. If you're going to play around with them prior to installing
+the module, you would need to add the blib paths to your perl search
+path, like this (assuming your current directory is samples):
+
+ perl -I../blib/lib -I../blib/arch xmlcomments REC-xml-19980210.xml
+
+or set your PERLLIB environment variable.
+
+If you have write access to the installation directories, you may then
+install by typing:
+
+ make install
+
+Discussion on features and bugs of this software and general discussion
+on topics relating to perl and XML takes place on the perl-xml mailing
+list, to which you can subscribe by sending mail to:
+
+ subscribe-perl-xml@lyris.activestate.com
+
+Differences from Version 2.30
+=============================
+
+Version 2.31 is a minor bugfix release to allow XML::Parser to
+work under the forthcoming Perl 5.8.0 release. There are no functional
+changes.
+
+Differences from Version 2.29
+=============================
+
+Expat is no longer included with this package. It must now be already
+installed on your system as a library. You may download the library
+version of expat from http://sourceforge.net/projects/expat/. After
+downloading, expat must be configured (an automatic script does this),
+built and installed.
+
+A workaround has been provided for those people who couldn't compile
+Expat.xs with a perl 5.6.0 with USE_5005THREADS on.
+
+A bug that prevented IO::Handler from being read by the parse method
+has been fixed.
+
+Fixed a bug in reading external entities with incremental parsing.
+
+Clark Cooper
+ coopercc@netheaven.com
diff --git a/samples/REC-xml-19980210.xml b/samples/REC-xml-19980210.xml
new file mode 100644
index 0000000..c108ff5
--- /dev/null
+++ b/samples/REC-xml-19980210.xml
@@ -0,0 +1,4197 @@
+<?xml version='1.0' encoding='ISO-8859-1' standalone='no'?>
+<!DOCTYPE spec SYSTEM "spec.dtd" [
+
+<!-- LAST TOUCHED BY: Tim Bray, 8 February 1997 -->
+
+<!-- The words 'FINAL EDIT' in comments mark places where changes
+need to be made after approval of the document by the ERB, before
+publication. -->
+
+<!ENTITY XML.version "1.0">
+<!ENTITY doc.date "10 February 1998">
+<!ENTITY iso6.doc.date "19980210">
+<!ENTITY w3c.doc.date "02-Feb-1998">
+<!ENTITY draft.day '10'>
+<!ENTITY draft.month 'February'>
+<!ENTITY draft.year '1998'>
+
+<!ENTITY WebSGML
+ 'WebSGML Adaptations Annex to ISO 8879'>
+
+<!ENTITY lt "<">
+<!ENTITY gt ">">
+<!ENTITY xmlpio "'&lt;?xml'">
+<!ENTITY pic "'?>'">
+<!ENTITY br "\n">
+<!ENTITY cellback '#c0d9c0'>
+<!ENTITY mdash "--"> <!-- &#x2014, but nsgmls doesn't grok hex -->
+<!ENTITY com "--">
+<!ENTITY como "--">
+<!ENTITY comc "--">
+<!ENTITY hcro "&amp;#x">
+<!-- <!ENTITY nbsp " "> -->
+<!ENTITY nbsp "&#160;">
+<!ENTITY magicents "<code>amp</code>,
+<code>lt</code>,
+<code>gt</code>,
+<code>apos</code>,
+<code>quot</code>">
+
+<!-- audience and distribution status: for use at publication time -->
+<!ENTITY doc.audience "public review and discussion">
+<!ENTITY doc.distribution "may be distributed freely, as long as
+all text and legal notices remain intact">
+
+]>
+
+<!-- for Panorama *-->
+<?VERBATIM "eg" ?>
+
+<spec>
+<header>
+<title>Extensible Markup Language (XML) 1.0</title>
+<version></version>
+<w3c-designation>REC-xml-&iso6.doc.date;</w3c-designation>
+<w3c-doctype>W3C Recommendation</w3c-doctype>
+<pubdate><day>&draft.day;</day><month>&draft.month;</month><year>&draft.year;</year></pubdate>
+
+<publoc>
+<loc href="http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;">
+http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;</loc>
+<loc href="http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;.xml">
+http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;.xml</loc>
+<loc href="http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;.html">
+http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;.html</loc>
+<loc href="http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;.pdf">
+http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;.pdf</loc>
+<loc href="http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;.ps">
+http://www.w3.org/TR/1998/REC-xml-&iso6.doc.date;.ps</loc>
+</publoc>
+<latestloc>
+<loc href="http://www.w3.org/TR/REC-xml">
+http://www.w3.org/TR/REC-xml</loc>
+</latestloc>
+<prevlocs>
+<loc href="http://www.w3.org/TR/PR-xml-971208">
+http://www.w3.org/TR/PR-xml-971208</loc>
+<!--
+<loc href='http://www.w3.org/TR/WD-xml-961114'>
+http://www.w3.org/TR/WD-xml-961114</loc>
+<loc href='http://www.w3.org/TR/WD-xml-lang-970331'>
+http://www.w3.org/TR/WD-xml-lang-970331</loc>
+<loc href='http://www.w3.org/TR/WD-xml-lang-970630'>
+http://www.w3.org/TR/WD-xml-lang-970630</loc>
+<loc href='http://www.w3.org/TR/WD-xml-970807'>
+http://www.w3.org/TR/WD-xml-970807</loc>
+<loc href='http://www.w3.org/TR/WD-xml-971117'>
+http://www.w3.org/TR/WD-xml-971117</loc>-->
+</prevlocs>
+<authlist>
+<author><name>Tim Bray</name>
+<affiliation>Textuality and Netscape</affiliation>
+<email
+href="mailto:tbray@textuality.com">tbray@textuality.com</email></author>
+<author><name>Jean Paoli</name>
+<affiliation>Microsoft</affiliation>
+<email href="mailto:jeanpa@microsoft.com">jeanpa@microsoft.com</email></author>
+<author><name>C. M. Sperberg-McQueen</name>
+<affiliation>University of Illinois at Chicago</affiliation>
+<email href="mailto:cmsmcq@uic.edu">cmsmcq@uic.edu</email></author>
+</authlist>
+<abstract>
+<p>The Extensible Markup Language (XML) is a subset of
+SGML that is completely described in this document. Its goal is to
+enable generic SGML to be served, received, and processed on the Web
+in the way that is now possible with HTML. XML has been designed for
+ease of implementation and for interoperability with both SGML and
+HTML.</p>
+</abstract>
+<status>
+<p>This document has been reviewed by W3C Members and
+other interested parties and has been endorsed by the
+Director as a W3C Recommendation. It is a stable
+document and may be used as reference material or cited
+as a normative reference from another document. W3C's
+role in making the Recommendation is to draw attention
+to the specification and to promote its widespread
+deployment. This enhances the functionality and
+interoperability of the Web.</p>
+<p>
+This document specifies a syntax created by subsetting an existing,
+widely used international text processing standard (Standard
+Generalized Markup Language, ISO 8879:1986(E) as amended and
+corrected) for use on the World Wide Web. It is a product of the W3C
+XML Activity, details of which can be found at <loc
+href='http://www.w3.org/XML'>http://www.w3.org/XML</loc>. A list of
+current W3C Recommendations and other technical documents can be found
+at <loc href='http://www.w3.org/TR'>http://www.w3.org/TR</loc>.
+</p>
+<p>This specification uses the term URI, which is defined by <bibref
+ref="Berners-Lee"/>, a work in progress expected to update <bibref
+ref="RFC1738"/> and <bibref ref="RFC1808"/>.
+</p>
+<p>The list of known errors in this specification is
+available at
+<loc href='http://www.w3.org/XML/xml-19980210-errata'>http://www.w3.org/XML/xml-19980210-errata</loc>.</p>
+<p>Please report errors in this document to
+<loc href='mailto:xml-editor@w3.org'>xml-editor@w3.org</loc>.
+</p>
+</status>
+
+
+<pubstmt>
+<p>Chicago, Vancouver, Mountain View, et al.:
+World-Wide Web Consortium, XML Working Group, 1996, 1997.</p>
+</pubstmt>
+<sourcedesc>
+<p>Created in electronic form.</p>
+</sourcedesc>
+<langusage>
+<language id='EN'>English</language>
+<language id='ebnf'>Extended Backus-Naur Form (formal grammar)</language>
+</langusage>
+<revisiondesc>
+<slist>
+<sitem>1997-12-03 : CMSMcQ : yet further changes</sitem>
+<sitem>1997-12-02 : TB : further changes (see TB to XML WG,
+2 December 1997)</sitem>
+<sitem>1997-12-02 : CMSMcQ : deal with as many corrections and
+comments from the proofreaders as possible:
+entify hard-coded document date in pubdate element,
+change expansion of entity WebSGML,
+update status description as per Dan Connolly (am not sure
+about refernece to Berners-Lee et al.),
+add 'The' to abstract as per WG decision,
+move Relationship to Existing Standards to back matter and
+combine with References,
+re-order back matter so normative appendices come first,
+re-tag back matter so informative appendices are tagged informdiv1,
+remove XXX XXX from list of 'normative' specs in prose,
+move some references from Other References to Normative References,
+add RFC 1738, 1808, and 2141 to Other References (they are not
+normative since we do not require the processor to enforce any
+rules based on them),
+add reference to 'Fielding draft' (Berners-Lee et al.),
+move notation section to end of body,
+drop URIchar non-terminal and use SkipLit instead,
+lose stray reference to defunct nonterminal 'markupdecls',
+move reference to Aho et al. into appendix (Tim's right),
+add prose note saying that hash marks and fragment identifiers are
+NOT part of the URI formally speaking, and are NOT legal in
+system identifiers (processor 'may' signal an error).
+Work through:
+Tim Bray reacting to James Clark,
+Tim Bray on his own,
+Eve Maler,
+
+NOT DONE YET:
+change binary / text to unparsed / parsed.
+handle James's suggestion about &lt; in attriubte values
+uppercase hex characters,
+namechar list,
+</sitem>
+<sitem>1997-12-01 : JB : add some column-width parameters</sitem>
+<sitem>1997-12-01 : CMSMcQ : begin round of changes to incorporate
+recent WG decisions and other corrections:
+binding sources of character encoding info (27 Aug / 3 Sept),
+correct wording of Faust quotation (restore dropped line),
+drop SDD from EncodingDecl,
+change text at version number 1.0,
+drop misleading (wrong!) sentence about ignorables and extenders,
+modify definition of PCData to make bar on msc grammatical,
+change grammar's handling of internal subset (drop non-terminal markupdecls),
+change definition of includeSect to allow conditional sections,
+add integral-declaration constraint on internal subset,
+drop misleading / dangerous sentence about relationship of
+entities with system storage objects,
+change table body tag to htbody as per EM change to DTD,
+add rule about space normalization in public identifiers,
+add description of how to generate our name-space rules from
+Unicode character database (needs further work!).
+</sitem>
+<sitem>1997-10-08 : TB : Removed %-constructs again, new rules
+for PE appearance.</sitem>
+<sitem>1997-10-01 : TB : Case-sensitive markup; cleaned up
+element-type defs, lotsa little edits for style</sitem>
+<sitem>1997-09-25 : TB : Change to elm's new DTD, with
+substantial detail cleanup as a side-effect</sitem>
+<sitem>1997-07-24 : CMSMcQ : correct error (lost *) in definition
+of ignoreSectContents (thanks to Makoto Murata)</sitem>
+<sitem>Allow all empty elements to have end-tags, consistent with
+SGML TC (as per JJC).</sitem>
+<sitem>1997-07-23 : CMSMcQ : pre-emptive strike on pending corrections:
+introduce the term 'empty-element tag', note that all empty elements
+may use it, and elements declared EMPTY must use it.
+Add WFC requiring encoding decl to come first in an entity.
+Redefine notations to point to PIs as well as binary entities.
+Change autodetection table by removing bytes 3 and 4 from
+examples with Byte Order Mark.
+Add content model as a term and clarify that it applies to both
+mixed and element content.
+</sitem>
+<sitem>1997-06-30 : CMSMcQ : change date, some cosmetic changes,
+changes to productions for choice, seq, Mixed, NotationType,
+Enumeration. Follow James Clark's suggestion and prohibit
+conditional sections in internal subset. TO DO: simplify
+production for ignored sections as a result, since we don't
+need to worry about parsers which don't expand PErefs finding
+a conditional section.</sitem>
+<sitem>1997-06-29 : TB : various edits</sitem>
+<sitem>1997-06-29 : CMSMcQ : further changes:
+Suppress old FINAL EDIT comments and some dead material.
+Revise occurrences of % in grammar to exploit Henry Thompson's pun,
+especially markupdecl and attdef.
+Remove RMD requirement relating to element content (?).
+</sitem>
+<sitem>1997-06-28 : CMSMcQ : Various changes for 1 July draft:
+Add text for draconian error handling (introduce
+the term Fatal Error).
+RE deleta est (changing wording from
+original announcement to restrict the requirement to validating
+parsers).
+Tag definition of validating processor and link to it.
+Add colon as name character.
+Change def of %operator.
+Change standard definitions of lt, gt, amp.
+Strip leading zeros from #x00nn forms.</sitem>
+<sitem>1997-04-02 : CMSMcQ : final corrections of editorial errors
+found in last night's proofreading. Reverse course once more on
+well-formed: Webster's Second hyphenates it, and that's enough
+for me.</sitem>
+<sitem>1997-04-01 : CMSMcQ : corrections from JJC, EM, HT, and self</sitem>
+<sitem>1997-03-31 : Tim Bray : many changes</sitem>
+<sitem>1997-03-29 : CMSMcQ : some Henry Thompson (on entity handling),
+some Charles Goldfarb, some ERB decisions (PE handling in miscellaneous
+declarations. Changed Ident element to accept def attribute.
+Allow normalization of Unicode characters. move def of systemliteral
+into section on literals.</sitem>
+<sitem>1997-03-28 : CMSMcQ : make as many corrections as possible, from
+Terry Allen, Norbert Mikula, James Clark, Jon Bosak, Henry Thompson,
+Paul Grosso, and self. Among other things: give in on "well formed"
+(Terry is right), tentatively rename QuotedCData as AttValue
+and Literal as EntityValue to be more informative, since attribute
+values are the <emph>only</emph> place QuotedCData was used, and
+vice versa for entity text and Literal. (I'd call it Entity Text,
+but 8879 uses that name for both internal and external entities.)</sitem>
+<sitem>1997-03-26 : CMSMcQ : resynch the two forks of this draft, reapply
+my changes dated 03-20 and 03-21. Normalize old 'may not' to 'must not'
+except in the one case where it meant 'may or may not'.</sitem>
+<sitem>1997-03-21 : TB : massive changes on plane flight from Chicago
+to Vancouver</sitem>
+<sitem>1997-03-21 : CMSMcQ : correct as many reported errors as possible.
+</sitem>
+<sitem>1997-03-20 : CMSMcQ : correct typos listed in CMSMcQ hand copy of spec.</sitem>
+<sitem>1997-03-20 : CMSMcQ : cosmetic changes preparatory to revision for
+WWW conference April 1997: restore some of the internal entity
+references (e.g. to docdate, etc.), change character xA0 to &amp;nbsp;
+and define nbsp as &amp;#160;, and refill a lot of paragraphs for
+legibility.</sitem>
+<sitem>1996-11-12 : CMSMcQ : revise using Tim's edits:
+Add list type of NUMBERED and change most lists either to
+BULLETS or to NUMBERED.
+Suppress QuotedNames, Names (not used).
+Correct trivial-grammar doc type decl.
+Rename 'marked section' as 'CDATA section' passim.
+Also edits from James Clark:
+Define the set of characters from which [^abc] subtracts.
+Charref should use just [0-9] not Digit.
+Location info needs cleaner treatment: remove? (ERB
+question).
+One example of a PI has wrong pic.
+Clarify discussion of encoding names.
+Encoding failure should lead to unspecified results; don't
+prescribe error recovery.
+Don't require exposure of entity boundaries.
+Ignore white space in element content.
+Reserve entity names of the form u-NNNN.
+Clarify relative URLs.
+And some of my own:
+Correct productions for content model: model cannot
+consist of a name, so "elements ::= cp" is no good.
+</sitem>
+<sitem>1996-11-11 : CMSMcQ : revise for style.
+Add new rhs to entity declaration, for parameter entities.</sitem>
+<sitem>1996-11-10 : CMSMcQ : revise for style.
+Fix / complete section on names, characters.
+Add sections on parameter entities, conditional sections.
+Still to do: Add compatibility note on deterministic content models.
+Finish stylistic revision.</sitem>
+<sitem>1996-10-31 : TB : Add Entity Handling section</sitem>
+<sitem>1996-10-30 : TB : Clean up term &amp; termdef. Slip in
+ERB decision re EMPTY.</sitem>
+<sitem>1996-10-28 : TB : Change DTD. Implement some of Michael's
+suggestions. Change comments back to //. Introduce language for
+XML namespace reservation. Add section on white-space handling.
+Lots more cleanup.</sitem>
+<sitem>1996-10-24 : CMSMcQ : quick tweaks, implement some ERB
+decisions. Characters are not integers. Comments are /* */ not //.
+Add bibliographic refs to 10646, HyTime, Unicode.
+Rename old Cdata as MsData since it's <emph>only</emph> seen
+in marked sections. Call them attribute-value pairs not
+name-value pairs, except once. Internal subset is optional, needs
+'?'. Implied attributes should be signaled to the app, not
+have values supplied by processor.</sitem>
+<sitem>1996-10-16 : TB : track down &amp; excise all DSD references;
+introduce some EBNF for entity declarations.</sitem>
+<sitem>1996-10-?? : TB : consistency check, fix up scraps so
+they all parse, get formatter working, correct a few productions.</sitem>
+<sitem>1996-10-10/11 : CMSMcQ : various maintenance, stylistic, and
+organizational changes:
+Replace a few literals with xmlpio and
+pic entities, to make them consistent and ensure we can change pic
+reliably when the ERB votes.
+Drop paragraph on recognizers from notation section.
+Add match, exact match to terminology.
+Move old 2.2 XML Processors and Apps into intro.
+Mention comments, PIs, and marked sections in discussion of
+delimiter escaping.
+Streamline discussion of doctype decl syntax.
+Drop old section of 'PI syntax' for doctype decl, and add
+section on partial-DTD summary PIs to end of Logical Structures
+section.
+Revise DSD syntax section to use Tim's subset-in-a-PI
+mechanism.</sitem>
+<sitem>1996-10-10 : TB : eliminate name recognizers (and more?)</sitem>
+<sitem>1996-10-09 : CMSMcQ : revise for style, consistency through 2.3
+(Characters)</sitem>
+<sitem>1996-10-09 : CMSMcQ : re-unite everything for convenience,
+at least temporarily, and revise quickly</sitem>
+<sitem>1996-10-08 : TB : first major homogenization pass</sitem>
+<sitem>1996-10-08 : TB : turn "current" attribute on div type into
+CDATA</sitem>
+<sitem>1996-10-02 : TB : remould into skeleton + entities</sitem>
+<sitem>1996-09-30 : CMSMcQ : add a few more sections prior to exchange
+ with Tim.</sitem>
+<sitem>1996-09-20 : CMSMcQ : finish transcribing notes.</sitem>
+<sitem>1996-09-19 : CMSMcQ : begin transcribing notes for draft.</sitem>
+<sitem>1996-09-13 : CMSMcQ : made outline from notes of 09-06,
+do some housekeeping</sitem>
+</slist>
+</revisiondesc>
+</header>
+<body>
+<div1 id='sec-intro'>
+<head>Introduction</head>
+<p>Extensible Markup Language, abbreviated XML, describes a class of
+data objects called <termref def="dt-xml-doc">XML documents</termref> and
+partially describes the behavior of
+computer programs which process them. XML is an application profile or
+restricted form of SGML, the Standard Generalized Markup
+Language <bibref ref='ISO8879'/>.
+By construction, XML documents
+are conforming SGML documents.
+</p>
+<p>XML documents are made up of storage units called <termref
+def="dt-entity">entities</termref>, which contain either parsed
+or unparsed data.
+Parsed data is made up of <termref def="dt-character">characters</termref>,
+some
+of which form <termref def="dt-chardata">character data</termref>,
+and some of which form <termref def="dt-markup">markup</termref>.
+Markup encodes a description of the document's storage layout and
+logical structure. XML provides a mechanism to impose constraints on
+the storage layout and logical structure.</p>
+<p><termdef id="dt-xml-proc" term="XML Processor">A software module
+called an <term>XML processor</term> is used to read XML documents
+and provide access to their content and structure.</termdef> <termdef
+id="dt-app" term="Application">It is assumed that an XML processor is
+doing its work on behalf of another module, called the
+<term>application</term>.</termdef> This specification describes the
+required behavior of an XML processor in terms of how it must read XML
+data and the information it must provide to the application.</p>
+
+<div2 id='sec-origin-goals'>
+<head>Origin and Goals</head>
+<p>XML was developed by an XML Working Group (originally known as the
+SGML Editorial Review Board) formed under the auspices of the World
+Wide Web Consortium (W3C) in 1996.
+It was chaired by Jon Bosak of Sun
+Microsystems with the active participation of an XML Special
+Interest Group (previously known as the SGML Working Group) also
+organized by the W3C. The membership of the XML Working Group is given
+in an appendix. Dan Connolly served as the WG's contact with the W3C.
+</p>
+<p>The design goals for XML are:<olist>
+<item><p>XML shall be straightforwardly usable over the
+Internet.</p></item>
+<item><p>XML shall support a wide variety of applications.</p></item>
+<item><p>XML shall be compatible with SGML.</p></item>
+<item><p>It shall be easy to write programs which process XML
+documents.</p></item>
+<item><p>The number of optional features in XML is to be kept to the
+absolute minimum, ideally zero.</p></item>
+<item><p>XML documents should be human-legible and reasonably
+clear.</p></item>
+<item><p>The XML design should be prepared quickly.</p></item>
+<item><p>The design of XML shall be formal and concise.</p></item>
+<item><p>XML documents shall be easy to create.</p></item>
+<item><p>Terseness in XML markup is of minimal importance.</p></item></olist>
+</p>
+<p>This specification,
+together with associated standards
+(Unicode and ISO/IEC 10646 for characters,
+Internet RFC 1766 for language identification tags,
+ISO 639 for language name codes, and
+ISO 3166 for country name codes),
+provides all the information necessary to understand
+XML Version &XML.version;
+and construct computer programs to process it.</p>
+<p>This version of the XML specification
+<!-- is for &doc.audience;.-->
+&doc.distribution;.</p>
+
+</div2>
+
+
+
+
+<div2 id='sec-terminology'>
+<head>Terminology</head>
+
+<p>The terminology used to describe XML documents is defined in the body of
+this specification.
+The terms defined in the following list are used in building those
+definitions and in describing the actions of an XML processor:
+<glist>
+<gitem>
+<label>may</label>
+<def><p><termdef id="dt-may" term="May">Conforming documents and XML
+processors are permitted to but need not behave as
+described.</termdef></p></def>
+</gitem>
+<gitem>
+<label>must</label>
+<def><p>Conforming documents and XML processors
+are required to behave as described; otherwise they are in error.
+<!-- do NOT change this! this is what defines a violation of
+a 'must' clause as 'an error'. -MSM -->
+</p></def>
+</gitem>
+<gitem>
+<label>error</label>
+<def><p><termdef id='dt-error' term='Error'
+>A violation of the rules of this
+specification; results are
+undefined. Conforming software may detect and report an error and may
+recover from it.</termdef></p></def>
+</gitem>
+<gitem>
+<label>fatal error</label>
+<def><p><termdef id="dt-fatal" term="Fatal Error">An error
+which a conforming <termref def="dt-xml-proc">XML processor</termref>
+must detect and report to the application.
+After encountering a fatal error, the
+processor may continue
+processing the data to search for further errors and may report such
+errors to the application. In order to support correction of errors,
+the processor may make unprocessed data from the document (with
+intermingled character data and markup) available to the application.
+Once a fatal error is detected, however, the processor must not
+continue normal processing (i.e., it must not
+continue to pass character data and information about the document's
+logical structure to the application in the normal way).
+</termdef></p></def>
+</gitem>
+<gitem>
+<label>at user option</label>
+<def><p>Conforming software may or must (depending on the modal verb in the
+sentence) behave as described; if it does, it must
+provide users a means to enable or disable the behavior
+described.</p></def>
+</gitem>
+<gitem>
+<label>validity constraint</label>
+<def><p>A rule which applies to all
+<termref def="dt-valid">valid</termref> XML documents.
+Violations of validity constraints are errors; they must, at user option,
+be reported by
+<termref def="dt-validating">validating XML processors</termref>.</p></def>
+</gitem>
+<gitem>
+<label>well-formedness constraint</label>
+<def><p>A rule which applies to all <termref
+def="dt-wellformed">well-formed</termref> XML documents.
+Violations of well-formedness constraints are
+<termref def="dt-fatal">fatal errors</termref>.</p></def>
+</gitem>
+
+<gitem>
+<label>match</label>
+<def><p><termdef id="dt-match" term="match">(Of strings or names:)
+Two strings or names being compared must be identical.
+Characters with multiple possible representations in ISO/IEC 10646 (e.g.
+characters with
+both precomposed and base+diacritic forms) match only if they have the
+same representation in both strings.
+At user option, processors may normalize such characters to
+some canonical form.
+No case folding is performed.
+(Of strings and rules in the grammar:)
+A string matches a grammatical production if it belongs to the
+language generated by that production.
+(Of content and content models:)
+An element matches its declaration when it conforms
+in the fashion described in the constraint
+<specref ref='elementvalid'/>.
+</termdef>
+</p></def>
+</gitem>
+<gitem>
+<label>for compatibility</label>
+<def><p><termdef id="dt-compat" term="For Compatibility">A feature of
+XML included solely to ensure that XML remains compatible with SGML.
+</termdef></p></def>
+</gitem>
+<gitem>
+<label>for interoperability</label>
+<def><p><termdef id="dt-interop" term="For interoperability">A
+non-binding recommendation included to increase the chances that XML
+documents can be processed by the existing installed base of SGML
+processors which predate the
+&WebSGML;.</termdef></p></def>
+</gitem>
+</glist>
+</p>
+</div2>
+
+
+</div1>
+<!-- &Docs; -->
+
+<div1 id='sec-documents'>
+<head>Documents</head>
+
+<p><termdef id="dt-xml-doc" term="XML Document">
+A data object is an
+<term>XML document</term> if it is
+<termref def="dt-wellformed">well-formed</termref>, as
+defined in this specification.
+A well-formed XML document may in addition be
+<termref def="dt-valid">valid</termref> if it meets certain further
+constraints.</termdef></p>
+
+<p>Each XML document has both a logical and a physical structure.
+Physically, the document is composed of units called <termref
+def="dt-entity">entities</termref>. An entity may <termref
+def="dt-entref">refer</termref> to other entities to cause their
+inclusion in the document. A document begins in a "root" or <termref
+def="dt-docent">document entity</termref>.
+Logically, the document is composed of declarations, elements,
+comments,
+character references, and
+processing
+instructions, all of which are indicated in the document by explicit
+markup.
+The logical and physical structures must nest properly, as described
+in <specref ref='wf-entities'/>.
+</p>
+
+<div2 id='sec-well-formed'>
+<head>Well-Formed XML Documents</head>
+
+<p><termdef id="dt-wellformed" term="Well-Formed">
+A textual object is
+a well-formed XML document if:</termdef>
+<olist>
+<item><p>Taken as a whole, it
+matches the production labeled <nt def='NT-document'>document</nt>.</p></item>
+<item><p>It
+meets all the well-formedness constraints given in this specification.</p>
+</item>
+<item><p>Each of the <termref def='dt-parsedent'>parsed entities</termref>
+which is referenced directly or indirectly within the document is
+<titleref href='wf-entities'>well-formed</titleref>.</p></item>
+</olist></p>
+<p>
+<scrap lang='ebnf' id='document'>
+<head>Document</head>
+<prod id='NT-document'><lhs>document</lhs>
+<rhs><nt def='NT-prolog'>prolog</nt>
+<nt def='NT-element'>element</nt>
+<nt def='NT-Misc'>Misc</nt>*</rhs></prod>
+</scrap>
+</p>
+<p>Matching the <nt def="NT-document">document</nt> production
+implies that:
+<olist>
+<item><p>It contains one or more
+<termref def="dt-element">elements</termref>.</p>
+</item>
+<!--* N.B. some readers (notably JC) find the following
+paragraph awkward and redundant. I agree it's logically redundant:
+it *says* it is summarizing the logical implications of
+matching the grammar, and that means by definition it's
+logically redundant. I don't think it's rhetorically
+redundant or unnecessary, though, so I'm keeping it. It
+could however use some recasting when the editors are feeling
+stronger. -MSM *-->
+<item><p><termdef id="dt-root" term="Root Element">There is exactly
+one element, called the <term>root</term>, or document element, no
+part of which appears in the <termref
+def="dt-content">content</termref> of any other element.</termdef>
+For all other elements, if the start-tag is in the content of another
+element, the end-tag is in the content of the same element. More
+simply stated, the elements, delimited by start- and end-tags, nest
+properly within each other.
+</p></item>
+</olist>
+</p>
+<p><termdef id="dt-parentchild" term="Parent/Child">As a consequence
+of this,
+for each non-root element
+<code>C</code> in the document, there is one other element <code>P</code>
+in the document such that
+<code>C</code> is in the content of <code>P</code>, but is not in
+the content of any other element that is in the content of
+<code>P</code>.
+<code>P</code> is referred to as the
+<term>parent</term> of <code>C</code>, and <code>C</code> as a
+<term>child</term> of <code>P</code>.</termdef></p></div2>
+
+<div2 id="charsets">
+<head>Characters</head>
+
+<p><termdef id="dt-text" term="Text">A parsed entity contains
+<term>text</term>, a sequence of
+<termref def="dt-character">characters</termref>,
+which may represent markup or character data.</termdef>
+<termdef id="dt-character" term="Character">A <term>character</term>
+is an atomic unit of text as specified by
+ISO/IEC 10646 <bibref ref="ISO10646"/>.
+Legal characters are tab, carriage return, line feed, and the legal
+graphic characters of Unicode and ISO/IEC 10646.
+The use of "compatibility characters", as defined in section 6.8
+of <bibref ref='Unicode'/>, is discouraged.
+</termdef>
+<scrap lang="ebnf" id="char32">
+<head>Character Range</head>
+<prodgroup pcw2="4" pcw4="17.5" pcw5="11">
+<prod id="NT-Char"><lhs>Char</lhs>
+<rhs>#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
+| [#x10000-#x10FFFF]</rhs>
+<com>any Unicode character, excluding the
+surrogate blocks, FFFE, and FFFF.</com> </prod>
+</prodgroup>
+</scrap>
+</p>
+
+<p>The mechanism for encoding character code points into bit patterns may
+vary from entity to entity. All XML processors must accept the UTF-8
+and UTF-16 encodings of 10646; the mechanisms for signaling which of
+the two is in use, or for bringing other encodings into play, are
+discussed later, in <specref ref='charencoding'/>.
+</p>
+<!--
+<p>Regardless of the specific encoding used, any character in the ISO/IEC
+10646 character set may be referred to by the decimal or hexadecimal
+equivalent of its
+UCS-4 code value.
+</p>-->
+</div2>
+
+<div2 id='sec-common-syn'>
+<head>Common Syntactic Constructs</head>
+
+<p>This section defines some symbols used widely in the grammar.</p>
+<p><nt def="NT-S">S</nt> (white space) consists of one or more space (#x20)
+characters, carriage returns, line feeds, or tabs.
+
+<scrap lang="ebnf" id='white'>
+<head>White Space</head>
+<prodgroup pcw2="4" pcw4="17.5" pcw5="11">
+<prod id='NT-S'><lhs>S</lhs>
+<rhs>(#x20 | #x9 | #xD | #xA)+</rhs>
+</prod>
+</prodgroup>
+</scrap></p>
+<p>Characters are classified for convenience as letters, digits, or other
+characters. Letters consist of an alphabetic or syllabic
+base character possibly
+followed by one or more combining characters, or of an ideographic
+character.
+Full definitions of the specific characters in each class
+are given in <specref ref='CharClasses'/>.</p>
+<p><termdef id="dt-name" term="Name">A <term>Name</term> is a token
+beginning with a letter or one of a few punctuation characters, and continuing
+with letters, digits, hyphens, underscores, colons, or full stops, together
+known as name characters.</termdef>
+Names beginning with the string "<code>xml</code>", or any string
+which would match <code>(('X'|'x') ('M'|'m') ('L'|'l'))</code>, are
+reserved for standardization in this or future versions of this
+specification.
+</p>
+<note>
+<p>The colon character within XML names is reserved for experimentation with
+name spaces.
+Its meaning is expected to be
+standardized at some future point, at which point those documents
+using the colon for experimental purposes may need to be updated.
+(There is no guarantee that any name-space mechanism
+adopted for XML will in fact use the colon as a name-space delimiter.)
+In practice, this means that authors should not use the colon in XML
+names except as part of name-space experiments, but that XML processors
+should accept the colon as a name character.</p>
+</note>
+<p>An
+<nt def='NT-Nmtoken'>Nmtoken</nt> (name token) is any mixture of
+name characters.
+<scrap lang='ebnf'>
+<head>Names and Tokens</head>
+<prod id='NT-NameChar'><lhs>NameChar</lhs>
+<rhs><nt def="NT-Letter">Letter</nt>
+| <nt def='NT-Digit'>Digit</nt>
+| '.' | '-' | '_' | ':'
+| <nt def='NT-CombiningChar'>CombiningChar</nt>
+| <nt def='NT-Extender'>Extender</nt></rhs>
+</prod>
+<prod id='NT-Name'><lhs>Name</lhs>
+<rhs>(<nt def='NT-Letter'>Letter</nt> | '_' | ':')
+(<nt def='NT-NameChar'>NameChar</nt>)*</rhs></prod>
+<prod id='NT-Names'><lhs>Names</lhs>
+<rhs><nt def='NT-Name'>Name</nt>
+(<nt def='NT-S'>S</nt> <nt def='NT-Name'>Name</nt>)*</rhs></prod>
+<prod id='NT-Nmtoken'><lhs>Nmtoken</lhs>
+<rhs>(<nt def='NT-NameChar'>NameChar</nt>)+</rhs></prod>
+<prod id='NT-Nmtokens'><lhs>Nmtokens</lhs>
+<rhs><nt def='NT-Nmtoken'>Nmtoken</nt> (<nt def='NT-S'>S</nt> <nt def='NT-Nmtoken'>Nmtoken</nt>)*</rhs></prod>
+</scrap>
+</p>
+<p>Literal data is any quoted string not containing
+the quotation mark used as a delimiter for that string.
+Literals are used
+for specifying the content of internal entities
+(<nt def='NT-EntityValue'>EntityValue</nt>),
+the values of attributes (<nt def='NT-AttValue'>AttValue</nt>),
+and external identifiers
+(<nt def="NT-SystemLiteral">SystemLiteral</nt>).
+Note that a <nt def='NT-SystemLiteral'>SystemLiteral</nt>
+can be parsed without scanning for markup.
+<scrap lang='ebnf'>
+<head>Literals</head>
+<prod id='NT-EntityValue'><lhs>EntityValue</lhs>
+<rhs>'"'
+([^%&amp;"]
+| <nt def='NT-PEReference'>PEReference</nt>
+| <nt def='NT-Reference'>Reference</nt>)*
+'"'
+</rhs>
+<rhs>|&nbsp;
+"'"
+([^%&amp;']
+| <nt def='NT-PEReference'>PEReference</nt>
+| <nt def='NT-Reference'>Reference</nt>)*
+"'"</rhs>
+</prod>
+<prod id='NT-AttValue'><lhs>AttValue</lhs>
+<rhs>'"'
+([^&lt;&amp;"]
+| <nt def='NT-Reference'>Reference</nt>)*
+'"'
+</rhs>
+<rhs>|&nbsp;
+"'"
+([^&lt;&amp;']
+| <nt def='NT-Reference'>Reference</nt>)*
+"'"</rhs>
+</prod>
+<prod id="NT-SystemLiteral"><lhs>SystemLiteral</lhs>
+<rhs>('"' [^"]* '"') |&nbsp;("'" [^']* "'")
+</rhs>
+</prod>
+<prod id="NT-PubidLiteral"><lhs>PubidLiteral</lhs>
+<rhs>'"' <nt def='NT-PubidChar'>PubidChar</nt>*
+'"'
+| "'" (<nt def='NT-PubidChar'>PubidChar</nt> - "'")* "'"</rhs>
+</prod>
+<prod id="NT-PubidChar"><lhs>PubidChar</lhs>
+<rhs>#x20 | #xD | #xA
+|&nbsp;[a-zA-Z0-9]
+|&nbsp;[-'()+,./:=?;!*#@$_%]</rhs>
+</prod>
+</scrap>
+</p>
+
+</div2>
+
+<div2 id='syntax'>
+<head>Character Data and Markup</head>
+
+<p><termref def='dt-text'>Text</termref> consists of intermingled
+<termref def="dt-chardata">character
+data</termref> and markup.
+<termdef id="dt-markup" term="Markup"><term>Markup</term> takes the form of
+<termref def="dt-stag">start-tags</termref>,
+<termref def="dt-etag">end-tags</termref>,
+<termref def="dt-empty">empty-element tags</termref>,
+<termref def="dt-entref">entity references</termref>,
+<termref def="dt-charref">character references</termref>,
+<termref def="dt-comment">comments</termref>,
+<termref def="dt-cdsection">CDATA section</termref> delimiters,
+<termref def="dt-doctype">document type declarations</termref>, and
+<termref def="dt-pi">processing instructions</termref>.
+</termdef>
+</p>
+<p><termdef id="dt-chardata" term="Character Data">All text that is not markup
+constitutes the <term>character data</term> of
+the document.</termdef></p>
+<p>The ampersand character (&amp;) and the left angle bracket (&lt;)
+may appear in their literal form <emph>only</emph> when used as markup
+delimiters, or within a <termref def="dt-comment">comment</termref>, a
+<termref def="dt-pi">processing instruction</termref>,
+or a <termref def="dt-cdsection">CDATA section</termref>.
+
+They are also legal within the <termref def='dt-litentval'>literal entity
+value</termref> of an internal entity declaration; see
+<specref ref='wf-entities'/>.
+<!-- FINAL EDIT: restore internal entity decl or leave it out. -->
+If they are needed elsewhere,
+they must be <termref def="dt-escape">escaped</termref>
+using either <termref def='dt-charref'>numeric character references</termref>
+or the strings
+"<code>&amp;amp;</code>" and "<code>&amp;lt;</code>" respectively.
+The right angle
+bracket (>) may be represented using the string
+"<code>&amp;gt;</code>", and must, <termref def='dt-compat'>for
+compatibility</termref>,
+be escaped using
+"<code>&amp;gt;</code>" or a character reference
+when it appears in the string
+"<code>]]&gt;</code>"
+in content,
+when that string is not marking the end of
+a <termref def="dt-cdsection">CDATA section</termref>.
+</p>
+<p>
+In the content of elements, character data
+is any string of characters which does
+not contain the start-delimiter of any markup.
+In a CDATA section, character data
+is any string of characters not including the CDATA-section-close
+delimiter, "<code>]]&gt;</code>".</p>
+<p>
+To allow attribute values to contain both single and double quotes, the
+apostrophe or single-quote character (') may be represented as
+"<code>&amp;apos;</code>", and the double-quote character (") as
+"<code>&amp;quot;</code>".
+<scrap lang="ebnf">
+<head>Character Data</head>
+<prod id='NT-CharData'>
+<lhs>CharData</lhs>
+<rhs>[^&lt;&amp;]* - ([^&lt;&amp;]* ']]&gt;' [^&lt;&amp;]*)</rhs>
+</prod>
+</scrap>
+</p>
+</div2>
+
+<div2 id='sec-comments'>
+<head>Comments</head>
+
+<p><termdef id="dt-comment" term="Comment"><term>Comments</term> may
+appear anywhere in a document outside other
+<termref def='dt-markup'>markup</termref>; in addition,
+they may appear within the document type declaration
+at places allowed by the grammar.
+They are not part of the document's <termref def="dt-chardata">character
+data</termref>; an XML
+processor may, but need not, make it possible for an application to
+retrieve the text of comments.
+<termref def="dt-compat">For compatibility</termref>, the string
+"<code>--</code>" (double-hyphen) must not occur within
+comments.
+<scrap lang="ebnf">
+<head>Comments</head>
+<prod id='NT-Comment'><lhs>Comment</lhs>
+<rhs>'&lt;!--'
+((<nt def='NT-Char'>Char</nt> - '-')
+| ('-' (<nt def='NT-Char'>Char</nt> - '-')))*
+'-->'</rhs>
+</prod>
+</scrap>
+</termdef></p>
+<p>An example of a comment:
+<eg>&lt;!&como; declarations for &lt;head> &amp; &lt;body> &comc;&gt;</eg>
+</p>
+</div2>
+
+<div2 id='sec-pi'>
+<head>Processing Instructions</head>
+
+<p><termdef id="dt-pi" term="Processing instruction"><term>Processing
+instructions</term> (PIs) allow documents to contain instructions
+for applications.
+
+<scrap lang="ebnf">
+<head>Processing Instructions</head>
+<prod id='NT-PI'><lhs>PI</lhs>
+<rhs>'&lt;?' <nt def='NT-PITarget'>PITarget</nt>
+(<nt def='NT-S'>S</nt>
+(<nt def='NT-Char'>Char</nt>* -
+(<nt def='NT-Char'>Char</nt>* &pic; <nt def='NT-Char'>Char</nt>*)))?
+&pic;</rhs></prod>
+<prod id='NT-PITarget'><lhs>PITarget</lhs>
+<rhs><nt def='NT-Name'>Name</nt> -
+(('X' | 'x') ('M' | 'm') ('L' | 'l'))</rhs>
+</prod>
+</scrap></termdef>
+PIs are not part of the document's <termref def="dt-chardata">character
+data</termref>, but must be passed through to the application. The
+PI begins with a target (<nt def='NT-PITarget'>PITarget</nt>) used
+to identify the application to which the instruction is directed.
+The target names "<code>XML</code>", "<code>xml</code>", and so on are
+reserved for standardization in this or future versions of this
+specification.
+The
+XML <termref def='dt-notation'>Notation</termref> mechanism
+may be used for
+formal declaration of PI targets.
+</p>
+</div2>
+
+<div2 id='sec-cdata-sect'>
+<head>CDATA Sections</head>
+
+<p><termdef id="dt-cdsection" term="CDATA Section"><term>CDATA sections</term>
+may occur
+anywhere character data may occur; they are
+used to escape blocks of text containing characters which would
+otherwise be recognized as markup. CDATA sections begin with the
+string "<code>&lt;![CDATA[</code>" and end with the string
+"<code>]]&gt;</code>":
+<scrap lang="ebnf">
+<head>CDATA Sections</head>
+<prod id='NT-CDSect'><lhs>CDSect</lhs>
+<rhs><nt def='NT-CDStart'>CDStart</nt>
+<nt def='NT-CData'>CData</nt>
+<nt def='NT-CDEnd'>CDEnd</nt></rhs></prod>
+<prod id='NT-CDStart'><lhs>CDStart</lhs>
+<rhs>'&lt;![CDATA['</rhs>
+</prod>
+<prod id='NT-CData'><lhs>CData</lhs>
+<rhs>(<nt def='NT-Char'>Char</nt>* -
+(<nt def='NT-Char'>Char</nt>* ']]&gt;' <nt def='NT-Char'>Char</nt>*))
+</rhs>
+</prod>
+<prod id='NT-CDEnd'><lhs>CDEnd</lhs>
+<rhs>']]&gt;'</rhs>
+</prod>
+</scrap>
+
+Within a CDATA section, only the <nt def='NT-CDEnd'>CDEnd</nt> string is
+recognized as markup, so that left angle brackets and ampersands may occur in
+their literal form; they need not (and cannot) be escaped using
+"<code>&amp;lt;</code>" and "<code>&amp;amp;</code>". CDATA sections
+cannot nest.</termdef>
+</p>
+
+<p>An example of a CDATA section, in which "<code>&lt;greeting></code>" and
+"<code>&lt;/greeting></code>"
+are recognized as <termref def='dt-chardata'>character data</termref>, not
+<termref def='dt-markup'>markup</termref>:
+<eg>&lt;![CDATA[&lt;greeting>Hello, world!&lt;/greeting>]]&gt;</eg>
+</p>
+</div2>
+
+<div2 id='sec-prolog-dtd'>
+<head>Prolog and Document Type Declaration</head>
+
+<p><termdef id='dt-xmldecl' term='XML Declaration'>XML documents
+may, and should,
+begin with an <term>XML declaration</term> which specifies
+the version of
+XML being used.</termdef>
+For example, the following is a complete XML document, <termref
+def="dt-wellformed">well-formed</termref> but not
+<termref def="dt-valid">valid</termref>:
+<eg><![CDATA[<?xml version="1.0"?>
+<greeting>Hello, world!</greeting>
+]]></eg>
+and so is this:
+<eg><![CDATA[<greeting>Hello, world!</greeting>
+]]></eg>
+</p>
+
+<p>The version number "<code>1.0</code>" should be used to indicate
+conformance to this version of this specification; it is an error
+for a document to use the value "<code>1.0</code>"
+if it does not conform to this version of this specification.
+It is the intent
+of the XML working group to give later versions of this specification
+numbers other than "<code>1.0</code>", but this intent does not
+indicate a
+commitment to produce any future versions of XML, nor if any are produced, to
+use any particular numbering scheme.
+Since future versions are not ruled out, this construct is provided
+as a means to allow the possibility of automatic version recognition, should
+it become necessary.
+Processors may signal an error if they receive documents labeled with
+versions they do not support.
+</p>
+<p>The function of the markup in an XML document is to describe its
+storage and logical structure and to associate attribute-value pairs
+with its logical structures. XML provides a mechanism, the <termref
+def="dt-doctype">document type declaration</termref>, to define
+constraints on the logical structure and to support the use of
+predefined storage units.
+
+<termdef id="dt-valid" term="Validity">An XML document is
+<term>valid</term> if it has an associated document type
+declaration and if the document
+complies with the constraints expressed in it.</termdef></p>
+<p>The document type declaration must appear before
+the first <termref def="dt-element">element</termref> in the document.
+<scrap lang="ebnf" id='xmldoc'>
+<head>Prolog</head>
+<prodgroup pcw2="6" pcw4="17.5" pcw5="9">
+<prod id='NT-prolog'><lhs>prolog</lhs>
+<rhs><nt def='NT-XMLDecl'>XMLDecl</nt>?
+<nt def='NT-Misc'>Misc</nt>*
+(<nt def='NT-doctypedecl'>doctypedecl</nt>
+<nt def='NT-Misc'>Misc</nt>*)?</rhs></prod>
+<prod id='NT-XMLDecl'><lhs>XMLDecl</lhs>
+<rhs>&xmlpio;
+<nt def='NT-VersionInfo'>VersionInfo</nt>
+<nt def='NT-EncodingDecl'>EncodingDecl</nt>?
+<nt def='NT-SDDecl'>SDDecl</nt>?
+<nt def="NT-S">S</nt>?
+&pic;</rhs>
+</prod>
+<prod id='NT-VersionInfo'><lhs>VersionInfo</lhs>
+<rhs><nt def="NT-S">S</nt> 'version' <nt def='NT-Eq'>Eq</nt>
+(' <nt def="NT-VersionNum">VersionNum</nt> '
+| " <nt def="NT-VersionNum">VersionNum</nt> ")</rhs>
+</prod>
+<prod id='NT-Eq'><lhs>Eq</lhs>
+<rhs><nt def='NT-S'>S</nt>? '=' <nt def='NT-S'>S</nt>?</rhs></prod>
+<prod id="NT-VersionNum">
+<lhs>VersionNum</lhs>
+<rhs>([a-zA-Z0-9_.:] | '-')+</rhs>
+</prod>
+<prod id='NT-Misc'><lhs>Misc</lhs>
+<rhs><nt def='NT-Comment'>Comment</nt> | <nt def='NT-PI'>PI</nt> |
+<nt def='NT-S'>S</nt></rhs></prod>
+</prodgroup>
+</scrap></p>
+
+<p><termdef id="dt-doctype" term="Document Type Declaration">The XML
+<term>document type declaration</term>
+contains or points to
+<termref def='dt-markupdecl'>markup declarations</termref>
+that provide a grammar for a
+class of documents.
+This grammar is known as a document type definition,
+or <term>DTD</term>.
+The document type declaration can point to an external subset (a
+special kind of
+<termref def='dt-extent'>external entity</termref>) containing markup
+declarations, or can
+contain the markup declarations directly in an internal subset, or can do
+both.
+The DTD for a document consists of both subsets taken
+together.</termdef>
+</p>
+<p><termdef id="dt-markupdecl" term="markup declaration">
+A <term>markup declaration</term> is
+an <termref def="dt-eldecl">element type declaration</termref>,
+an <termref def="dt-attdecl">attribute-list declaration</termref>,
+an <termref def="dt-entdecl">entity declaration</termref>, or
+a <termref def="dt-notdecl">notation declaration</termref>.
+</termdef>
+These declarations may be contained in whole or in part
+within <termref def='dt-PE'>parameter entities</termref>,
+as described in the well-formedness and validity constraints below.
+For fuller information, see
+<specref ref="sec-physical-struct"/>.</p>
+<scrap lang="ebnf" id='dtd'>
+<head>Document Type Definition</head>
+<prodgroup pcw2="6" pcw4="17.5" pcw5="9">
+<prod id='NT-doctypedecl'><lhs>doctypedecl</lhs>
+<rhs>'&lt;!DOCTYPE' <nt def='NT-S'>S</nt>
+<nt def='NT-Name'>Name</nt> (<nt def='NT-S'>S</nt>
+<nt def='NT-ExternalID'>ExternalID</nt>)?
+<nt def='NT-S'>S</nt>? ('['
+(<nt def='NT-markupdecl'>markupdecl</nt>
+| <nt def='NT-PEReference'>PEReference</nt>
+| <nt def='NT-S'>S</nt>)*
+']'
+<nt def='NT-S'>S</nt>?)? '>'</rhs>
+<vc def="vc-roottype"/>
+</prod>
+<prod id='NT-markupdecl'><lhs>markupdecl</lhs>
+<rhs><nt def='NT-elementdecl'>elementdecl</nt>
+| <nt def='NT-AttlistDecl'>AttlistDecl</nt>
+| <nt def='NT-EntityDecl'>EntityDecl</nt>
+| <nt def='NT-NotationDecl'>NotationDecl</nt>
+| <nt def='NT-PI'>PI</nt>
+| <nt def='NT-Comment'>Comment</nt>
+</rhs>
+<vc def='vc-PEinMarkupDecl'/>
+<wfc def="wfc-PEinInternalSubset"/>
+</prod>
+
+</prodgroup>
+</scrap>
+
+<p>The markup declarations may be made up in whole or in part of
+the <termref def='dt-repltext'>replacement text</termref> of
+<termref def='dt-PE'>parameter entities</termref>.
+The productions later in this specification for
+individual nonterminals (<nt def='NT-elementdecl'>elementdecl</nt>,
+<nt def='NT-AttlistDecl'>AttlistDecl</nt>, and so on) describe
+the declarations <emph>after</emph> all the parameter entities have been
+<termref def='dt-include'>included</termref>.</p>
+
+<vcnote id="vc-roottype">
+<head>Root Element Type</head>
+<p>
+The <nt def='NT-Name'>Name</nt> in the document type declaration must
+match the element type of the <termref def='dt-root'>root element</termref>.
+</p>
+</vcnote>
+
+<vcnote id='vc-PEinMarkupDecl'>
+<head>Proper Declaration/PE Nesting</head>
+<p>Parameter-entity
+<termref def='dt-repltext'>replacement text</termref> must be properly nested
+with markup declarations.
+That is to say, if either the first character
+or the last character of a markup
+declaration (<nt def='NT-markupdecl'>markupdecl</nt> above)
+is contained in the replacement text for a
+<termref def='dt-PERef'>parameter-entity reference</termref>,
+both must be contained in the same replacement text.</p>
+</vcnote>
+<wfcnote id="wfc-PEinInternalSubset">
+<head>PEs in Internal Subset</head>
+<p>In the internal DTD subset,
+<termref def='dt-PERef'>parameter-entity references</termref>
+can occur only where markup declarations can occur, not
+within markup declarations. (This does not apply to
+references that occur in
+external parameter entities or to the external subset.)
+</p>
+</wfcnote>
+<p>
+Like the internal subset, the external subset and
+any external parameter entities referred to in the DTD
+must consist of a series of complete markup declarations of the types
+allowed by the non-terminal symbol
+<nt def="NT-markupdecl">markupdecl</nt>, interspersed with white space
+or <termref def="dt-PERef">parameter-entity references</termref>.
+However, portions of the contents
+of the
+external subset or of external parameter entities may conditionally be ignored
+by using
+the <termref def="dt-cond-section">conditional section</termref>
+construct; this is not allowed in the internal subset.
+
+<scrap id="ext-Subset">
+<head>External Subset</head>
+<prodgroup pcw2="6" pcw4="17.5" pcw5="9">
+<prod id='NT-extSubset'><lhs>extSubset</lhs>
+<rhs><nt def='NT-TextDecl'>TextDecl</nt>?
+<nt def='NT-extSubsetDecl'>extSubsetDecl</nt></rhs></prod>
+<prod id='NT-extSubsetDecl'><lhs>extSubsetDecl</lhs>
+<rhs>(
+<nt def='NT-markupdecl'>markupdecl</nt>
+| <nt def='NT-conditionalSect'>conditionalSect</nt>
+| <nt def='NT-PEReference'>PEReference</nt>
+| <nt def='NT-S'>S</nt>
+)*</rhs>
+</prod>
+</prodgroup>
+</scrap></p>
+<p>The external subset and external parameter entities also differ
+from the internal subset in that in them,
+<termref def="dt-PERef">parameter-entity references</termref>
+are permitted <emph>within</emph> markup declarations,
+not only <emph>between</emph> markup declarations.</p>
+<p>An example of an XML document with a document type declaration:
+<eg><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE greeting SYSTEM "hello.dtd">
+<greeting>Hello, world!</greeting>
+]]></eg>
+The <termref def="dt-sysid">system identifier</termref>
+"<code>hello.dtd</code>" gives the URI of a DTD for the document.</p>
+<p>The declarations can also be given locally, as in this
+example:
+<eg><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE greeting [
+ <!ELEMENT greeting (#PCDATA)>
+]>
+<greeting>Hello, world!</greeting>
+]]></eg>
+If both the external and internal subsets are used, the
+internal subset is considered to occur before the external subset.
+<!-- 'is considered to'? boo. whazzat mean? -->
+This has the effect that entity and attribute-list declarations in the
+internal subset take precedence over those in the external subset.
+</p>
+</div2>
+
+<div2 id='sec-rmd'>
+<head>Standalone Document Declaration</head>
+<p>Markup declarations can affect the content of the document,
+as passed from an <termref def="dt-xml-proc">XML processor</termref>
+to an application; examples are attribute defaults and entity
+declarations.
+The standalone document declaration,
+which may appear as a component of the XML declaration, signals
+whether or not there are such declarations which appear external to
+the <termref def='dt-docent'>document entity</termref>.
+<scrap lang="ebnf" id='fulldtd'>
+<head>Standalone Document Declaration</head>
+<prodgroup pcw2="4" pcw4="19.5" pcw5="9">
+<prod id='NT-SDDecl'><lhs>SDDecl</lhs>
+<rhs>
+<nt def="NT-S">S</nt>
+'standalone' <nt def='NT-Eq'>Eq</nt>
+(("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
+</rhs>
+<vc def='vc-check-rmd'/></prod>
+</prodgroup>
+</scrap></p>
+<p>
+In a standalone document declaration, the value "<code>yes</code>" indicates
+that there
+are no markup declarations external to the <termref def='dt-docent'>document
+entity</termref> (either in the DTD external subset, or in an
+external parameter entity referenced from the internal subset)
+which affect the information passed from the XML processor to
+the application.
+The value "<code>no</code>" indicates that there are or may be such
+external markup declarations.
+Note that the standalone document declaration only
+denotes the presence of external <emph>declarations</emph>; the presence, in a
+document, of
+references to external <emph>entities</emph>, when those entities are
+internally declared,
+does not change its standalone status.</p>
+<p>If there are no external markup declarations, the standalone document
+declaration has no meaning.
+If there are external markup declarations but there is no standalone
+document declaration, the value "<code>no</code>" is assumed.</p>
+<p>Any XML document for which <code>standalone="no"</code> holds can
+be converted algorithmically to a standalone document,
+which may be desirable for some network delivery applications.</p>
+<vcnote id='vc-check-rmd'>
+<head>Standalone Document Declaration</head>
+<p>The standalone document declaration must have
+the value "<code>no</code>" if any external markup declarations
+contain declarations of:</p><ulist>
+<item><p>attributes with <termref def="dt-default">default</termref> values, if
+elements to which
+these attributes apply appear in the document without
+specifications of values for these attributes, or</p></item>
+<item><p>entities (other than &magicents;),
+if <termref def="dt-entref">references</termref> to those
+entities appear in the document, or</p>
+</item>
+<item><p>attributes with values subject to
+<titleref href='AVNormalize'>normalization</titleref>, where the
+attribute appears in the document with a value which will
+change as a result of normalization, or</p>
+</item>
+<item>
+<p>element types with <termref def="dt-elemcontent">element content</termref>,
+if white space occurs
+directly within any instance of those types.
+</p></item>
+</ulist>
+
+</vcnote>
+<p>An example XML declaration with a standalone document declaration:<eg
+>&lt;?xml version="&XML.version;" standalone='yes'?></eg></p>
+</div2>
+<div2 id='sec-white-space'>
+<head>White Space Handling</head>
+
+<p>In editing XML documents, it is often convenient to use "white space"
+(spaces, tabs, and blank lines, denoted by the nonterminal
+<nt def='NT-S'>S</nt> in this specification) to
+set apart the markup for greater readability. Such white space is typically
+not intended for inclusion in the delivered version of the document.
+On the other hand, "significant" white space that should be preserved in the
+delivered version is common, for example in poetry and
+source code.</p>
+<p>An <termref def='dt-xml-proc'>XML processor</termref>
+must always pass all characters in a document that are not
+markup through to the application. A <termref def='dt-validating'>
+validating XML processor</termref> must also inform the application
+which of these characters constitute white space appearing
+in <termref def="dt-elemcontent">element content</termref>.
+</p>
+<p>A special <termref def='dt-attr'>attribute</termref>
+named <kw>xml:space</kw> may be attached to an element
+to signal an intention that in that element,
+white space should be preserved by applications.
+In valid documents, this attribute, like any other, must be
+<termref def="dt-attdecl">declared</termref> if it is used.
+When declared, it must be given as an
+<termref def='dt-enumerated'>enumerated type</termref> whose only
+possible values are "<code>default</code>" and "<code>preserve</code>".
+For example:<eg><![CDATA[ <!ATTLIST poem xml:space (default|preserve) 'preserve'>]]></eg></p>
+<p>The value "<code>default</code>" signals that applications'
+default white-space processing modes are acceptable for this element; the
+value "<code>preserve</code>" indicates the intent that applications preserve
+all the white space.
+This declared intent is considered to apply to all elements within the content
+of the element where it is specified, unless overriden with another instance
+of the <kw>xml:space</kw> attribute.
+</p>
+<p>The <termref def='dt-root'>root element</termref> of any document
+is considered to have signaled no intentions as regards application space
+handling, unless it provides a value for
+this attribute or the attribute is declared with a default value.
+</p>
+
+</div2>
+<div2 id='sec-line-ends'>
+<head>End-of-Line Handling</head>
+<p>XML <termref def='dt-parsedent'>parsed entities</termref> are often stored in
+computer files which, for editing convenience, are organized into lines.
+These lines are typically separated by some combination of the characters
+carriage-return (#xD) and line-feed (#xA).</p>
+<p>To simplify the tasks of <termref def='dt-app'>applications</termref>,
+wherever an external parsed entity or the literal entity value
+of an internal parsed entity contains either the literal
+two-character sequence "#xD#xA" or a standalone literal
+#xD, an <termref def='dt-xml-proc'>XML processor</termref> must
+pass to the application the single character #xA.
+(This behavior can
+conveniently be produced by normalizing all
+line breaks to #xA on input, before parsing.)
+</p>
+</div2>
+<div2 id='sec-lang-tag'>
+<head>Language Identification</head>
+<p>In document processing, it is often useful to
+identify the natural or formal language
+in which the content is
+written.
+A special <termref def="dt-attr">attribute</termref> named
+<kw>xml:lang</kw> may be inserted in
+documents to specify the
+language used in the contents and attribute values
+of any element in an XML document.
+In valid documents, this attribute, like any other, must be
+<termref def="dt-attdecl">declared</termref> if it is used.
+The values of the attribute are language identifiers as defined
+by <bibref ref="RFC1766"/>, "Tags for the Identification of Languages":
+<scrap lang='ebnf'>
+<head>Language Identification</head>
+<prod id='NT-LanguageID'><lhs>LanguageID</lhs>
+<rhs><nt def='NT-Langcode'>Langcode</nt>
+('-' <nt def='NT-Subcode'>Subcode</nt>)*</rhs></prod>
+<prod id='NT-Langcode'><lhs>Langcode</lhs>
+<rhs><nt def='NT-ISO639Code'>ISO639Code</nt> |
+<nt def='NT-IanaCode'>IanaCode</nt> |
+<nt def='NT-UserCode'>UserCode</nt></rhs>
+</prod>
+<prod id='NT-ISO639Code'><lhs>ISO639Code</lhs>
+<rhs>([a-z] | [A-Z]) ([a-z] | [A-Z])</rhs></prod>
+<prod id='NT-IanaCode'><lhs>IanaCode</lhs>
+<rhs>('i' | 'I') '-' ([a-z] | [A-Z])+</rhs></prod>
+<prod id='NT-UserCode'><lhs>UserCode</lhs>
+<rhs>('x' | 'X') '-' ([a-z] | [A-Z])+</rhs></prod>
+<prod id='NT-Subcode'><lhs>Subcode</lhs>
+<rhs>([a-z] | [A-Z])+</rhs></prod>
+</scrap>
+The <nt def='NT-Langcode'>Langcode</nt> may be any of the following:
+<ulist>
+<item><p>a two-letter language code as defined by
+<bibref ref="ISO639"/>, "Codes
+for the representation of names of languages"</p></item>
+<item><p>a language identifier registered with the Internet
+Assigned Numbers Authority <bibref ref='IANA'/>; these begin with the
+prefix "<code>i-</code>" (or "<code>I-</code>")</p></item>
+<item><p>a language identifier assigned by the user, or agreed on
+between parties in private use; these must begin with the
+prefix "<code>x-</code>" or "<code>X-</code>" in order to ensure that they do not conflict
+with names later standardized or registered with IANA</p></item>
+</ulist></p>
+<p>There may be any number of <nt def='NT-Subcode'>Subcode</nt> segments; if
+the first
+subcode segment exists and the Subcode consists of two
+letters, then it must be a country code from
+<bibref ref="ISO3166"/>, "Codes
+for the representation of names of countries."
+If the first
+subcode consists of more than two letters, it must be
+a subcode for the language in question registered with IANA,
+unless the <nt def='NT-Langcode'>Langcode</nt> begins with the prefix
+"<code>x-</code>" or
+"<code>X-</code>". </p>
+<p>It is customary to give the language code in lower case, and
+the country code (if any) in upper case.
+Note that these values, unlike other names in XML documents,
+are case insensitive.</p>
+<p>For example:
+<eg><![CDATA[<p xml:lang="en">The quick brown fox jumps over the lazy dog.</p>
+<p xml:lang="en-GB">What colour is it?</p>
+<p xml:lang="en-US">What color is it?</p>
+<sp who="Faust" desc='leise' xml:lang="de">
+ <l>Habe nun, ach! Philosophie,</l>
+ <l>Juristerei, und Medizin</l>
+ <l>und leider auch Theologie</l>
+ <l>durchaus studiert mit heißem Bemüh'n.</l>
+ </sp>]]></eg></p>
+<!--<p>The xml:lang value is considered to apply both to the contents of an
+element and
+(unless otherwise via attribute default values) to the
+values of all of its attributes with free-text (CDATA) values. -->
+<p>The intent declared with <kw>xml:lang</kw> is considered to apply to
+all attributes and content of the element where it is specified,
+unless overridden with an instance of <kw>xml:lang</kw>
+on another element within that content.</p>
+<!--
+If no
+value is specified for xml:lang on an element, and no default value is
+defined for it in the DTD, then the xml:lang attribute of any element
+takes the same value it has in the parent element, if any. The two
+technical terms in the following example both have the same effective
+value for xml:lang:
+
+ <p xml:lang="en">Here the keywords are
+ <term xml:lang="en">shift</term> and
+ <term>reduce</term>. ...</p>
+
+The application, not the XML processor, is responsible for this '
+inheritance' of attribute values.
+-->
+<p>A simple declaration for <kw>xml:lang</kw> might take
+the form
+<eg>xml:lang NMTOKEN #IMPLIED</eg>
+but specific default values may also be given, if appropriate. In a
+collection of French poems for English students, with glosses and
+notes in English, the xml:lang attribute might be declared this way:
+<eg><![CDATA[ <!ATTLIST poem xml:lang NMTOKEN 'fr'>
+ <!ATTLIST gloss xml:lang NMTOKEN 'en'>
+ <!ATTLIST note xml:lang NMTOKEN 'en'>]]></eg>
+</p>
+
+</div2>
+</div1>
+<!-- &Elements; -->
+
+<div1 id='sec-logical-struct'>
+<head>Logical Structures</head>
+
+<p><termdef id="dt-element" term="Element">Each <termref
+def="dt-xml-doc">XML document</termref> contains one or more
+<term>elements</term>, the boundaries of which are
+either delimited by <termref def="dt-stag">start-tags</termref>
+and <termref def="dt-etag">end-tags</termref>, or, for <termref
+def="dt-empty">empty</termref> elements, by an <termref
+def="dt-eetag">empty-element tag</termref>. Each element has a type,
+identified by name, sometimes called its "generic
+identifier" (GI), and may have a set of
+attribute specifications.</termdef> Each attribute specification
+has a <termref
+def="dt-attrname">name</termref> and a <termref
+def="dt-attrval">value</termref>.
+</p>
+<scrap lang='ebnf'><head>Element</head>
+<prod id='NT-element'><lhs>element</lhs>
+<rhs><nt def='NT-EmptyElemTag'>EmptyElemTag</nt></rhs>
+<rhs>| <nt def='NT-STag'>STag</nt> <nt def='NT-content'>content</nt>
+<nt def='NT-ETag'>ETag</nt></rhs>
+<wfc def='GIMatch'/>
+<vc def='elementvalid'/>
+</prod>
+</scrap>
+<p>This specification does not constrain the semantics, use, or (beyond
+syntax) names of the element types and attributes, except that names
+beginning with a match to <code>(('X'|'x')('M'|'m')('L'|'l'))</code>
+are reserved for standardization in this or future versions of this
+specification.
+</p>
+<wfcnote id='GIMatch'>
+<head>Element Type Match</head>
+<p>
+The <nt def='NT-Name'>Name</nt> in an element's end-tag must match
+the element type in
+the start-tag.
+</p>
+</wfcnote>
+<vcnote id='elementvalid'>
+<head>Element Valid</head>
+<p>An element is
+valid if
+there is a declaration matching
+<nt def='NT-elementdecl'>elementdecl</nt> where the
+<nt def='NT-Name'>Name</nt> matches the element type, and
+one of the following holds:</p>
+<olist>
+<item><p>The declaration matches <kw>EMPTY</kw> and the element has no
+<termref def='dt-content'>content</termref>.</p></item>
+<item><p>The declaration matches <nt def='NT-children'>children</nt> and
+the sequence of
+<termref def="dt-parentchild">child elements</termref>
+belongs to the language generated by the regular expression in
+the content model, with optional white space (characters
+matching the nonterminal <nt def='NT-S'>S</nt>) between each pair
+of child elements.</p></item>
+<item><p>The declaration matches <nt def='NT-Mixed'>Mixed</nt> and
+the content consists of <termref def='dt-chardata'>character
+data</termref> and <termref def='dt-parentchild'>child elements</termref>
+whose types match names in the content model.</p></item>
+<item><p>The declaration matches <kw>ANY</kw>, and the types
+of any <termref def='dt-parentchild'>child elements</termref> have
+been declared.</p></item>
+</olist>
+</vcnote>
+
+<div2 id='sec-starttags'>
+<head>Start-Tags, End-Tags, and Empty-Element Tags</head>
+
+<p><termdef id="dt-stag" term="Start-Tag">The beginning of every
+non-empty XML element is marked by a <term>start-tag</term>.
+<scrap lang='ebnf'>
+<head>Start-tag</head>
+<prodgroup pcw2="6" pcw4="15" pcw5="11.5">
+<prod id='NT-STag'><lhs>STag</lhs>
+<rhs>'&lt;' <nt def='NT-Name'>Name</nt>
+(<nt def='NT-S'>S</nt> <nt def='NT-Attribute'>Attribute</nt>)*
+<nt def='NT-S'>S</nt>? '>'</rhs>
+<wfc def="uniqattspec"/>
+</prod>
+<prod id='NT-Attribute'><lhs>Attribute</lhs>
+<rhs><nt def='NT-Name'>Name</nt> <nt def='NT-Eq'>Eq</nt>
+<nt def='NT-AttValue'>AttValue</nt></rhs>
+<vc def='ValueType'/>
+<wfc def='NoExternalRefs'/>
+<wfc def='CleanAttrVals'/></prod>
+</prodgroup>
+</scrap>
+The <nt def='NT-Name'>Name</nt> in
+the start- and end-tags gives the
+element's <term>type</term>.</termdef>
+<termdef id="dt-attr" term="Attribute">
+The <nt def='NT-Name'>Name</nt>-<nt def='NT-AttValue'>AttValue</nt> pairs are
+referred to as
+the <term>attribute specifications</term> of the element</termdef>,
+<termdef id="dt-attrname" term="Attribute Name">with the
+<nt def='NT-Name'>Name</nt> in each pair
+referred to as the <term>attribute name</term></termdef> and
+<termdef id="dt-attrval" term="Attribute Value">the content of the
+<nt def='NT-AttValue'>AttValue</nt> (the text between the
+<code>'</code> or <code>"</code> delimiters)
+as the <term>attribute value</term>.</termdef>
+</p>
+<wfcnote id='uniqattspec'>
+<head>Unique Att Spec</head>
+<p>
+No attribute name may appear more than once in the same start-tag
+or empty-element tag.
+</p>
+</wfcnote>
+<vcnote id='ValueType'>
+<head>Attribute Value Type</head>
+<p>
+The attribute must have been declared; the value must be of the type
+declared for it.
+(For attribute types, see <specref ref='attdecls'/>.)
+</p>
+</vcnote>
+<wfcnote id='NoExternalRefs'>
+<head>No External Entity References</head>
+<p>
+Attribute values cannot contain direct or indirect entity references
+to external entities.
+</p>
+</wfcnote>
+<wfcnote id='CleanAttrVals'>
+<head>No <code>&lt;</code> in Attribute Values</head>
+<p>The <termref def='dt-repltext'>replacement text</termref> of any entity
+referred to directly or indirectly in an attribute
+value (other than "<code>&amp;lt;</code>") must not contain
+a <code>&lt;</code>.
+</p></wfcnote>
+<p>An example of a start-tag:
+<eg>&lt;termdef id="dt-dog" term="dog"></eg></p>
+<p><termdef id="dt-etag" term="End Tag">The end of every element
+that begins with a start-tag must
+be marked by an <term>end-tag</term>
+containing a name that echoes the element's type as given in the
+start-tag:
+<scrap lang='ebnf'>
+<head>End-tag</head>
+<prodgroup pcw2="6" pcw4="15" pcw5="11.5">
+<prod id='NT-ETag'><lhs>ETag</lhs>
+<rhs>'&lt;/' <nt def='NT-Name'>Name</nt>
+<nt def='NT-S'>S</nt>? '>'</rhs></prod>
+</prodgroup>
+</scrap>
+</termdef></p>
+<p>An example of an end-tag:<eg>&lt;/termdef></eg></p>
+<p><termdef id="dt-content" term="Content">The
+<termref def='dt-text'>text</termref> between the start-tag and
+end-tag is called the element's
+<term>content</term>:
+<scrap lang='ebnf'>
+<head>Content of Elements</head>
+<prodgroup pcw2="6" pcw4="15" pcw5="11.5">
+<prod id='NT-content'><lhs>content</lhs>
+<rhs>(<nt def='NT-element'>element</nt> | <nt def='NT-CharData'>CharData</nt>
+| <nt def='NT-Reference'>Reference</nt> | <nt def='NT-CDSect'>CDSect</nt>
+| <nt def='NT-PI'>PI</nt> | <nt def='NT-Comment'>Comment</nt>)*</rhs>
+</prod>
+</prodgroup>
+</scrap>
+</termdef></p>
+<p><termdef id="dt-empty" term="Empty">If an element is <term>empty</term>,
+it must be represented either by a start-tag immediately followed
+by an end-tag or by an empty-element tag.</termdef>
+<termdef id="dt-eetag" term="empty-element tag">An
+<term>empty-element tag</term> takes a special form:
+<scrap lang='ebnf'>
+<head>Tags for Empty Elements</head>
+<prodgroup pcw2="6" pcw4="15" pcw5="11.5">
+<prod id='NT-EmptyElemTag'><lhs>EmptyElemTag</lhs>
+<rhs>'&lt;' <nt def='NT-Name'>Name</nt> (<nt def='NT-S'>S</nt>
+<nt def='NT-Attribute'>Attribute</nt>)* <nt def='NT-S'>S</nt>?
+'/&gt;'</rhs>
+<wfc def="uniqattspec"/>
+</prod>
+</prodgroup>
+</scrap>
+</termdef></p>
+<p>Empty-element tags may be used for any element which has no
+content, whether or not it is declared using the keyword
+<kw>EMPTY</kw>.
+<termref def='dt-interop'>For interoperability</termref>, the empty-element
+tag must be used, and can only be used, for elements which are
+<termref def='dt-eldecl'>declared</termref> <kw>EMPTY</kw>.</p>
+<p>Examples of empty elements:
+<eg>&lt;IMG align="left"
+ src="http://www.w3.org/Icons/WWW/w3c_home" />
+&lt;br>&lt;/br>
+&lt;br/></eg></p>
+</div2>
+
+<div2 id='elemdecls'>
+<head>Element Type Declarations</head>
+
+<p>The <termref def="dt-element">element</termref> structure of an
+<termref def="dt-xml-doc">XML document</termref> may, for
+<termref def="dt-valid">validation</termref> purposes,
+be constrained
+using element type and attribute-list declarations.
+An element type declaration constrains the element's
+<termref def="dt-content">content</termref>.
+</p>
+
+<p>Element type declarations often constrain which element types can
+appear as <termref def="dt-parentchild">children</termref> of the element.
+At user option, an XML processor may issue a warning
+when a declaration mentions an element type for which no declaration
+is provided, but this is not an error.</p>
+<p><termdef id="dt-eldecl" term="Element Type declaration">An <term>element
+type declaration</term> takes the form:
+<scrap lang='ebnf'>
+<head>Element Type Declaration</head>
+<prodgroup pcw2="5.5" pcw4="18" pcw5="9">
+<prod id='NT-elementdecl'><lhs>elementdecl</lhs>
+<rhs>'&lt;!ELEMENT' <nt def='NT-S'>S</nt>
+<nt def='NT-Name'>Name</nt>
+<nt def='NT-S'>S</nt>
+<nt def='NT-contentspec'>contentspec</nt>
+<nt def='NT-S'>S</nt>? '>'</rhs>
+<vc def='EDUnique'/></prod>
+<prod id='NT-contentspec'><lhs>contentspec</lhs>
+<rhs>'EMPTY'
+| 'ANY'
+| <nt def='NT-Mixed'>Mixed</nt>
+| <nt def='NT-children'>children</nt>
+</rhs>
+</prod>
+</prodgroup>
+</scrap>
+where the <nt def='NT-Name'>Name</nt> gives the element type
+being declared.</termdef>
+</p>
+
+<vcnote id='EDUnique'>
+<head>Unique Element Type Declaration</head>
+<p>
+No element type may be declared more than once.
+</p>
+</vcnote>
+
+<p>Examples of element type declarations:
+<eg>&lt;!ELEMENT br EMPTY>
+&lt;!ELEMENT p (#PCDATA|emph)* >
+&lt;!ELEMENT %name.para; %content.para; >
+&lt;!ELEMENT container ANY></eg></p>
+
+<div3 id='sec-element-content'>
+<head>Element Content</head>
+
+<p><termdef id='dt-elemcontent' term='Element content'>An element <termref
+def="dt-stag">type</termref> has
+<term>element content</term> when elements of that
+type must contain only <termref def='dt-parentchild'>child</termref>
+elements (no character data), optionally separated by
+white space (characters matching the nonterminal
+<nt def='NT-S'>S</nt>).
+</termdef>
+In this case, the
+constraint includes a content model, a simple grammar governing
+the allowed types of the child
+elements and the order in which they are allowed to appear.
+The grammar is built on
+content particles (<nt def='NT-cp'>cp</nt>s), which consist of names,
+choice lists of content particles, or
+sequence lists of content particles:
+<scrap lang='ebnf'>
+<head>Element-content Models</head>
+<prodgroup pcw2="5.5" pcw4="16" pcw5="11">
+<prod id='NT-children'><lhs>children</lhs>
+<rhs>(<nt def='NT-choice'>choice</nt>
+| <nt def='NT-seq'>seq</nt>)
+('?' | '*' | '+')?</rhs></prod>
+<prod id='NT-cp'><lhs>cp</lhs>
+<rhs>(<nt def='NT-Name'>Name</nt>
+| <nt def='NT-choice'>choice</nt>
+| <nt def='NT-seq'>seq</nt>)
+('?' | '*' | '+')?</rhs></prod>
+<prod id='NT-choice'><lhs>choice</lhs>
+<rhs>'(' <nt def='NT-S'>S</nt>? cp
+( <nt def='NT-S'>S</nt>? '|' <nt def='NT-S'>S</nt>? <nt def='NT-cp'>cp</nt> )*
+<nt def='NT-S'>S</nt>? ')'</rhs>
+<vc def='vc-PEinGroup'/></prod>
+<prod id='NT-seq'><lhs>seq</lhs>
+<rhs>'(' <nt def='NT-S'>S</nt>? cp
+( <nt def='NT-S'>S</nt>? ',' <nt def='NT-S'>S</nt>? <nt def='NT-cp'>cp</nt> )*
+<nt def='NT-S'>S</nt>? ')'</rhs>
+<vc def='vc-PEinGroup'/></prod>
+
+</prodgroup>
+</scrap>
+where each <nt def='NT-Name'>Name</nt> is the type of an element which may
+appear as a <termref def="dt-parentchild">child</termref>.
+Any content
+particle in a choice list may appear in the <termref
+def="dt-elemcontent">element content</termref> at the location where
+the choice list appears in the grammar;
+content particles occurring in a sequence list must each
+appear in the <termref def="dt-elemcontent">element content</termref> in the
+order given in the list.
+The optional character following a name or list governs
+whether the element or the content particles in the list may occur one
+or more (<code>+</code>), zero or more (<code>*</code>), or zero or
+one times (<code>?</code>).
+The absence of such an operator means that the element or content particle
+must appear exactly once.
+This syntax
+and meaning are identical to those used in the productions in this
+specification.</p>
+<p>
+The content of an element matches a content model if and only if it is
+possible to trace out a path through the content model, obeying the
+sequence, choice, and repetition operators and matching each element in
+the content against an element type in the content model. <termref
+def='dt-compat'>For compatibility</termref>, it is an error
+if an element in the document can
+match more than one occurrence of an element type in the content model.
+For more information, see <specref ref="determinism"/>.
+<!-- appendix <specref ref="determinism"/>. -->
+<!-- appendix on deterministic content models. -->
+</p>
+<vcnote id='vc-PEinGroup'>
+<head>Proper Group/PE Nesting</head>
+<p>Parameter-entity
+<termref def='dt-repltext'>replacement text</termref> must be properly nested
+with parenthetized groups.
+That is to say, if either of the opening or closing parentheses
+in a <nt def='NT-choice'>choice</nt>, <nt def='NT-seq'>seq</nt>, or
+<nt def='NT-Mixed'>Mixed</nt> construct
+is contained in the replacement text for a
+<termref def='dt-PERef'>parameter entity</termref>,
+both must be contained in the same replacement text.</p>
+<p><termref def='dt-interop'>For interoperability</termref>,
+if a parameter-entity reference appears in a
+<nt def='NT-choice'>choice</nt>, <nt def='NT-seq'>seq</nt>, or
+<nt def='NT-Mixed'>Mixed</nt> construct, its replacement text
+should not be empty, and
+neither the first nor last non-blank
+character of the replacement text should be a connector
+(<code>|</code> or <code>,</code>).
+</p>
+</vcnote>
+<p>Examples of element-content models:
+<eg>&lt;!ELEMENT spec (front, body, back?)>
+&lt;!ELEMENT div1 (head, (p | list | note)*, div2*)>
+&lt;!ELEMENT dictionary-body (%div.mix; | %dict.mix;)*></eg></p>
+</div3>
+
+<div3 id='sec-mixed-content'>
+<head>Mixed Content</head>
+
+<p><termdef id='dt-mixed' term='Mixed Content'>An element
+<termref def='dt-stag'>type</termref> has
+<term>mixed content</term> when elements of that type may contain
+character data, optionally interspersed with
+<termref def="dt-parentchild">child</termref> elements.</termdef>
+In this case, the types of the child elements
+may be constrained, but not their order or their number of occurrences:
+<scrap lang='ebnf'>
+<head>Mixed-content Declaration</head>
+<prodgroup pcw2="5.5" pcw4="16" pcw5="11">
+<prod id='NT-Mixed'><lhs>Mixed</lhs>
+<rhs>'(' <nt def='NT-S'>S</nt>?
+'#PCDATA'
+(<nt def='NT-S'>S</nt>?
+'|'
+<nt def='NT-S'>S</nt>?
+<nt def='NT-Name'>Name</nt>)*
+<nt def='NT-S'>S</nt>?
+')*' </rhs>
+<rhs>| '(' <nt def='NT-S'>S</nt>? '#PCDATA' <nt def='NT-S'>S</nt>? ')'
+</rhs><vc def='vc-PEinGroup'/>
+<vc def='vc-MixedChildrenUnique'/>
+</prod>
+
+</prodgroup>
+</scrap>
+where the <nt def='NT-Name'>Name</nt>s give the types of elements
+that may appear as children.
+</p>
+<vcnote id='vc-MixedChildrenUnique'>
+<head>No Duplicate Types</head>
+<p>The same name must not appear more than once in a single mixed-content
+declaration.
+</p></vcnote>
+<p>Examples of mixed content declarations:
+<eg>&lt;!ELEMENT p (#PCDATA|a|ul|b|i|em)*>
+&lt;!ELEMENT p (#PCDATA | %font; | %phrase; | %special; | %form;)* >
+&lt;!ELEMENT b (#PCDATA)></eg></p>
+</div3>
+</div2>
+
+<div2 id='attdecls'>
+<head>Attribute-List Declarations</head>
+
+<p><termref def="dt-attr">Attributes</termref> are used to associate
+name-value pairs with <termref def="dt-element">elements</termref>.
+Attribute specifications may appear only within <termref
+def="dt-stag">start-tags</termref>
+and <termref def="dt-eetag">empty-element tags</termref>;
+thus, the productions used to
+recognize them appear in <specref ref='sec-starttags'/>.
+Attribute-list
+declarations may be used:
+<ulist>
+<item><p>To define the set of attributes pertaining to a given
+element type.</p></item>
+<item><p>To establish type constraints for these
+attributes.</p></item>
+<item><p>To provide <termref def="dt-default">default values</termref>
+for attributes.</p></item>
+</ulist>
+</p>
+<p><termdef id="dt-attdecl" term="Attribute-List Declaration">
+<term>Attribute-list declarations</term> specify the name, data type, and default
+value (if any) of each attribute associated with a given element type:
+<scrap lang='ebnf'>
+<head>Attribute-list Declaration</head>
+<prod id='NT-AttlistDecl'><lhs>AttlistDecl</lhs>
+<rhs>'&lt;!ATTLIST' <nt def='NT-S'>S</nt>
+<nt def='NT-Name'>Name</nt>
+<nt def='NT-AttDef'>AttDef</nt>*
+<nt def='NT-S'>S</nt>? '&gt;'</rhs>
+</prod>
+<prod id='NT-AttDef'><lhs>AttDef</lhs>
+<rhs><nt def='NT-S'>S</nt> <nt def='NT-Name'>Name</nt>
+<nt def='NT-S'>S</nt> <nt def='NT-AttType'>AttType</nt>
+<nt def='NT-S'>S</nt> <nt def='NT-DefaultDecl'>DefaultDecl</nt></rhs>
+</prod>
+</scrap>
+The <nt def="NT-Name">Name</nt> in the
+<nt def='NT-AttlistDecl'>AttlistDecl</nt> rule is the type of an element. At
+user option, an XML processor may issue a warning if attributes are
+declared for an element type not itself declared, but this is not an
+error. The <nt def='NT-Name'>Name</nt> in the
+<nt def='NT-AttDef'>AttDef</nt> rule is
+the name of the attribute.</termdef></p>
+<p>
+When more than one <nt def='NT-AttlistDecl'>AttlistDecl</nt> is provided for a
+given element type, the contents of all those provided are merged. When
+more than one definition is provided for the same attribute of a
+given element type, the first declaration is binding and later
+declarations are ignored.
+<termref def='dt-interop'>For interoperability,</termref> writers of DTDs
+may choose to provide at most one attribute-list declaration
+for a given element type, at most one attribute definition
+for a given attribute name, and at least one attribute definition
+in each attribute-list declaration.
+For interoperability, an XML processor may at user option
+issue a warning when more than one attribute-list declaration is
+provided for a given element type, or more than one attribute definition
+is provided
+for a given attribute, but this is not an error.
+</p>
+
+<div3 id='sec-attribute-types'>
+<head>Attribute Types</head>
+
+<p>XML attribute types are of three kinds: a string type, a
+set of tokenized types, and enumerated types. The string type may take
+any literal string as a value; the tokenized types have varying lexical
+and semantic constraints, as noted:
+<scrap lang='ebnf'>
+<head>Attribute Types</head>
+<prodgroup pcw4="14" pcw5="11.5">
+<prod id='NT-AttType'><lhs>AttType</lhs>
+<rhs><nt def='NT-StringType'>StringType</nt>
+| <nt def='NT-TokenizedType'>TokenizedType</nt>
+| <nt def='NT-EnumeratedType'>EnumeratedType</nt>
+</rhs>
+</prod>
+<prod id='NT-StringType'><lhs>StringType</lhs>
+<rhs>'CDATA'</rhs>
+</prod>
+<prod id='NT-TokenizedType'><lhs>TokenizedType</lhs>
+<rhs>'ID'</rhs>
+<vc def='id'/>
+<vc def='one-id-per-el'/>
+<vc def='id-default'/>
+<rhs>| 'IDREF'</rhs>
+<vc def='idref'/>
+<rhs>| 'IDREFS'</rhs>
+<vc def='idref'/>
+<rhs>| 'ENTITY'</rhs>
+<vc def='entname'/>
+<rhs>| 'ENTITIES'</rhs>
+<vc def='entname'/>
+<rhs>| 'NMTOKEN'</rhs>
+<vc def='nmtok'/>
+<rhs>| 'NMTOKENS'</rhs>
+<vc def='nmtok'/></prod>
+</prodgroup>
+</scrap>
+</p>
+<vcnote id='id' >
+<head>ID</head>
+<p>
+Values of type <kw>ID</kw> must match the
+<nt def='NT-Name'>Name</nt> production.
+A name must not appear more than once in
+an XML document as a value of this type; i.e., ID values must uniquely
+identify the elements which bear them.
+</p>
+</vcnote>
+<vcnote id='one-id-per-el'>
+<head>One ID per Element Type</head>
+<p>No element type may have more than one ID attribute specified.</p>
+</vcnote>
+<vcnote id='id-default'>
+<head>ID Attribute Default</head>
+<p>An ID attribute must have a declared default of <kw>#IMPLIED</kw> or
+<kw>#REQUIRED</kw>.</p>
+</vcnote>
+<vcnote id='idref'>
+<head>IDREF</head>
+<p>
+Values of type <kw>IDREF</kw> must match
+the <nt def="NT-Name">Name</nt> production, and
+values of type <kw>IDREFS</kw> must match
+<nt def="NT-Names">Names</nt>;
+each <nt def='NT-Name'>Name</nt> must match the value of an ID attribute on
+some element in the XML document; i.e. <kw>IDREF</kw> values must
+match the value of some ID attribute.
+</p>
+</vcnote>
+<vcnote id='entname'>
+<head>Entity Name</head>
+<p>
+Values of type <kw>ENTITY</kw>
+must match the <nt def="NT-Name">Name</nt> production,
+values of type <kw>ENTITIES</kw> must match
+<nt def="NT-Names">Names</nt>;
+each <nt def="NT-Name">Name</nt> must
+match the
+name of an <termref def="dt-unparsed">unparsed entity</termref> declared in the
+<termref def="dt-doctype">DTD</termref>.
+</p>
+</vcnote>
+<vcnote id='nmtok'>
+<head>Name Token</head>
+<p>
+Values of type <kw>NMTOKEN</kw> must match the
+<nt def="NT-Nmtoken">Nmtoken</nt> production;
+values of type <kw>NMTOKENS</kw> must
+match <termref def="NT-Nmtokens">Nmtokens</termref>.
+</p>
+</vcnote>
+<!-- why?
+<p>The XML processor must normalize attribute values before
+passing them to the application, as described in
+<specref ref="AVNormalize"/>.</p>-->
+<p><termdef id='dt-enumerated' term='Enumerated Attribute
+Values'><term>Enumerated attributes</term> can take one
+of a list of values provided in the declaration</termdef>. There are two
+kinds of enumerated types:
+<scrap lang='ebnf'>
+<head>Enumerated Attribute Types</head>
+<prod id='NT-EnumeratedType'><lhs>EnumeratedType</lhs>
+<rhs><nt def='NT-NotationType'>NotationType</nt>
+| <nt def='NT-Enumeration'>Enumeration</nt>
+</rhs></prod>
+<prod id='NT-NotationType'><lhs>NotationType</lhs>
+<rhs>'NOTATION'
+<nt def='NT-S'>S</nt>
+'('
+<nt def='NT-S'>S</nt>?
+<nt def='NT-Name'>Name</nt>
+(<nt def='NT-S'>S</nt>? '|' <nt def='NT-S'>S</nt>?
+<nt def='NT-Name'>Name</nt>)*
+<nt def='NT-S'>S</nt>? ')'
+</rhs>
+<vc def='notatn' /></prod>
+<prod id='NT-Enumeration'><lhs>Enumeration</lhs>
+<rhs>'(' <nt def='NT-S'>S</nt>?
+<nt def='NT-Nmtoken'>Nmtoken</nt>
+(<nt def='NT-S'>S</nt>? '|'
+<nt def='NT-S'>S</nt>?
+<nt def='NT-Nmtoken'>Nmtoken</nt>)*
+<nt def='NT-S'>S</nt>?
+')'</rhs>
+<vc def='enum'/></prod>
+</scrap>
+A <kw>NOTATION</kw> attribute identifies a
+<termref def='dt-notation'>notation</termref>, declared in the
+DTD with associated system and/or public identifiers, to
+be used in interpreting the element to which the attribute
+is attached.
+</p>
+
+<vcnote id='notatn'>
+<head>Notation Attributes</head>
+<p>
+Values of this type must match
+one of the <titleref href='Notations'>notation</titleref> names included in
+the declaration; all notation names in the declaration must
+be declared.
+</p>
+</vcnote>
+<vcnote id='enum'>
+<head>Enumeration</head>
+<p>
+Values of this type
+must match one of the <nt def='NT-Nmtoken'>Nmtoken</nt> tokens in the
+declaration.
+</p>
+</vcnote>
+<p><termref def='dt-interop'>For interoperability,</termref> the same
+<nt def='NT-Nmtoken'>Nmtoken</nt> should not occur more than once in the
+enumerated attribute types of a single element type.
+</p>
+</div3>
+
+<div3 id='sec-attr-defaults'>
+<head>Attribute Defaults</head>
+
+<p>An <termref def="dt-attdecl">attribute declaration</termref> provides
+information on whether
+the attribute's presence is required, and if not, how an XML processor should
+react if a declared attribute is absent in a document.
+<scrap lang='ebnf'>
+<head>Attribute Defaults</head>
+<prodgroup pcw4="14" pcw5="11.5">
+<prod id='NT-DefaultDecl'><lhs>DefaultDecl</lhs>
+<rhs>'#REQUIRED'
+|&nbsp;'#IMPLIED' </rhs>
+<rhs>| (('#FIXED' S)? <nt def='NT-AttValue'>AttValue</nt>)</rhs>
+<vc def='RequiredAttr'/>
+<vc def='defattrvalid'/>
+<wfc def="CleanAttrVals"/>
+<vc def='FixedAttr'/>
+</prod>
+</prodgroup>
+</scrap>
+
+</p>
+<p>In an attribute declaration, <kw>#REQUIRED</kw> means that the
+attribute must always be provided, <kw>#IMPLIED</kw> that no default
+value is provided.
+<!-- not any more!!
+<kw>#IMPLIED</kw> means that if the attribute is omitted
+from an element of this type,
+the XML processor must inform the application
+that no value was specified; no constraint is placed on the behavior
+of the application. -->
+<termdef id="dt-default" term="Attribute Default">If the
+declaration
+is neither <kw>#REQUIRED</kw> nor <kw>#IMPLIED</kw>, then the
+<nt def='NT-AttValue'>AttValue</nt> value contains the declared
+<term>default</term> value; the <kw>#FIXED</kw> keyword states that
+the attribute must always have the default value.
+If a default value
+is declared, when an XML processor encounters an omitted attribute, it
+is to behave as though the attribute were present with
+the declared default value.</termdef></p>
+<vcnote id='RequiredAttr'>
+<head>Required Attribute</head>
+<p>If the default declaration is the keyword <kw>#REQUIRED</kw>, then
+the attribute must be specified for
+all elements of the type in the attribute-list declaration.
+</p></vcnote>
+<vcnote id='defattrvalid'>
+<head>Attribute Default Legal</head>
+<p>
+The declared
+default value must meet the lexical constraints of the declared attribute type.
+</p>
+</vcnote>
+<vcnote id='FixedAttr'>
+<head>Fixed Attribute Default</head>
+<p>If an attribute has a default value declared with the
+<kw>#FIXED</kw> keyword, instances of that attribute must
+match the default value.
+</p></vcnote>
+
+<p>Examples of attribute-list declarations:
+<eg>&lt;!ATTLIST termdef
+ id ID #REQUIRED
+ name CDATA #IMPLIED>
+&lt;!ATTLIST list
+ type (bullets|ordered|glossary) "ordered">
+&lt;!ATTLIST form
+ method CDATA #FIXED "POST"></eg></p>
+</div3>
+<div3 id='AVNormalize'>
+<head>Attribute-Value Normalization</head>
+<p>Before the value of an attribute is passed to the application
+or checked for validity, the
+XML processor must normalize it as follows:
+<ulist>
+<item><p>a character reference is processed by appending the referenced
+character to the attribute value</p></item>
+<item><p>an entity reference is processed by recursively processing the
+replacement text of the entity</p></item>
+<item><p>a whitespace character (#x20, #xD, #xA, #x9) is processed by
+appending #x20 to the normalized value, except that only a single #x20
+is appended for a "#xD#xA" sequence that is part of an external
+parsed entity or the literal entity value of an internal parsed
+entity</p></item>
+<item><p>other characters are processed by appending them to the normalized
+value</p>
+</item></ulist>
+</p>
+<p>If the declared value is not CDATA, then the XML processor must
+further process the normalized attribute value by discarding any
+leading and trailing space (#x20) characters, and by replacing
+sequences of space (#x20) characters by a single space (#x20)
+character.</p>
+<p>
+All attributes for which no declaration has been read should be treated
+by a non-validating parser as if declared
+<kw>CDATA</kw>.
+</p>
+</div3>
+</div2>
+<div2 id='sec-condition-sect'>
+<head>Conditional Sections</head>
+<p><termdef id='dt-cond-section' term='conditional section'>
+<term>Conditional sections</term> are portions of the
+<termref def='dt-doctype'>document type declaration external subset</termref>
+which are
+included in, or excluded from, the logical structure of the DTD based on
+the keyword which governs them.</termdef>
+<scrap lang='ebnf'>
+<head>Conditional Section</head>
+<prodgroup pcw2="9" pcw4="14.5">
+<prod id='NT-conditionalSect'><lhs>conditionalSect</lhs>
+<rhs><nt def='NT-includeSect'>includeSect</nt>
+| <nt def='NT-ignoreSect'>ignoreSect</nt>
+</rhs>
+</prod>
+<prod id='NT-includeSect'><lhs>includeSect</lhs>
+<rhs>'&lt;![' S? 'INCLUDE' S? '['
+
+<nt def="NT-extSubsetDecl">extSubsetDecl</nt>
+']]&gt;'
+</rhs>
+</prod>
+<prod id='NT-ignoreSect'><lhs>ignoreSect</lhs>
+<rhs>'&lt;![' S? 'IGNORE' S? '['
+<nt def="NT-ignoreSectContents">ignoreSectContents</nt>*
+']]&gt;'</rhs>
+</prod>
+
+<prod id='NT-ignoreSectContents'><lhs>ignoreSectContents</lhs>
+<rhs><nt def='NT-Ignore'>Ignore</nt>
+('&lt;![' <nt def='NT-ignoreSectContents'>ignoreSectContents</nt> ']]&gt;'
+<nt def='NT-Ignore'>Ignore</nt>)*</rhs></prod>
+<prod id='NT-Ignore'><lhs>Ignore</lhs>
+<rhs><nt def='NT-Char'>Char</nt>* -
+(<nt def='NT-Char'>Char</nt>* ('&lt;![' | ']]&gt;')
+<nt def='NT-Char'>Char</nt>*)
+</rhs></prod>
+
+</prodgroup>
+</scrap>
+</p>
+<p>Like the internal and external DTD subsets, a conditional section
+may contain one or more complete declarations,
+comments, processing instructions,
+or nested conditional sections, intermingled with white space.
+</p>
+<p>If the keyword of the
+conditional section is <kw>INCLUDE</kw>, then the contents of the conditional
+section are part of the DTD.
+If the keyword of the conditional
+section is <kw>IGNORE</kw>, then the contents of the conditional section are
+not logically part of the DTD.
+Note that for reliable parsing, the contents of even ignored
+conditional sections must be read in order to
+detect nested conditional sections and ensure that the end of the
+outermost (ignored) conditional section is properly detected.
+If a conditional section with a
+keyword of <kw>INCLUDE</kw> occurs within a larger conditional
+section with a keyword of <kw>IGNORE</kw>, both the outer and the
+inner conditional sections are ignored.</p>
+<p>If the keyword of the conditional section is a
+parameter-entity reference, the parameter entity must be replaced by its
+content before the processor decides whether to
+include or ignore the conditional section.</p>
+<p>An example:
+<eg>&lt;!ENTITY % draft 'INCLUDE' >
+&lt;!ENTITY % final 'IGNORE' >
+
+&lt;![%draft;[
+&lt;!ELEMENT book (comments*, title, body, supplements?)>
+]]&gt;
+&lt;![%final;[
+&lt;!ELEMENT book (title, body, supplements?)>
+]]&gt;
+</eg>
+</p>
+</div2>
+
+
+<!--
+<div2 id='sec-pass-to-app'>
+<head>XML Processor Treatment of Logical Structure</head>
+<p>When an XML processor encounters a start-tag, it must make
+at least the following information available to the application:
+<ulist>
+<item>
+<p>the element type's generic identifier</p>
+</item>
+<item>
+<p>the names of attributes known to apply to this element type
+(validating processors must make available names of all attributes
+declared for the element type; non-validating processors must
+make available at least the names of the attributes for which
+values are specified.
+</p>
+</item>
+</ulist>
+</p>
+</div2>
+-->
+
+</div1>
+<!-- &Entities; -->
+
+<div1 id='sec-physical-struct'>
+<head>Physical Structures</head>
+
+<p><termdef id="dt-entity" term="Entity">An XML document may consist
+of one or many storage units. These are called
+<term>entities</term>; they all have <term>content</term> and are all
+(except for the document entity, see below, and
+the <termref def='dt-doctype'>external DTD subset</termref>)
+identified by <term>name</term>.
+</termdef>
+Each XML document has one entity
+called the <termref def="dt-docent">document entity</termref>, which serves
+as the starting point for the <termref def="dt-xml-proc">XML
+processor</termref> and may contain the whole document.</p>
+<p>Entities may be either parsed or unparsed.
+<termdef id="dt-parsedent" term="Text Entity">A <term>parsed entity's</term>
+contents are referred to as its
+<termref def='dt-repltext'>replacement text</termref>;
+this <termref def="dt-text">text</termref> is considered an
+integral part of the document.</termdef></p>
+
+<p><termdef id="dt-unparsed" term="Unparsed Entity">An
+<term>unparsed entity</term>
+is a resource whose contents may or may not be
+<termref def='dt-text'>text</termref>, and if text, may not be XML.
+Each unparsed entity
+has an associated <termref
+def="dt-notation">notation</termref>, identified by name.
+Beyond a requirement
+that an XML processor make the identifiers for the entity and
+notation available to the application,
+XML places no constraints on the contents of unparsed entities.</termdef>
+</p>
+<p>
+Parsed entities are invoked by name using entity references;
+unparsed entities by name, given in the value of <kw>ENTITY</kw>
+or <kw>ENTITIES</kw>
+attributes.</p>
+<p><termdef id='gen-entity' term='general entity'
+><term>General entities</term>
+are entities for use within the document content.
+In this specification, general entities are sometimes referred
+to with the unqualified term <emph>entity</emph> when this leads
+to no ambiguity.</termdef>
+<termdef id='dt-PE' term='Parameter entity'>Parameter entities
+are parsed entities for use within the DTD.</termdef>
+These two types of entities use different forms of reference and
+are recognized in different contexts.
+Furthermore, they occupy different namespaces; a parameter entity and
+a general entity with the same name are two distinct entities.
+</p>
+
+<div2 id='sec-references'>
+<head>Character and Entity References</head>
+<p><termdef id="dt-charref" term="Character Reference">
+A <term>character reference</term> refers to a specific character in the
+ISO/IEC 10646 character set, for example one not directly accessible from
+available input devices.
+<scrap lang='ebnf'>
+<head>Character Reference</head>
+<prod id='NT-CharRef'><lhs>CharRef</lhs>
+<rhs>'&amp;#' [0-9]+ ';' </rhs>
+<rhs>| '&hcro;' [0-9a-fA-F]+ ';'</rhs>
+<wfc def="wf-Legalchar"/>
+</prod>
+</scrap>
+<wfcnote id="wf-Legalchar">
+<head>Legal Character</head>
+<p>Characters referred to using character references must
+match the production for
+<termref def="NT-Char">Char</termref>.</p>
+</wfcnote>
+If the character reference begins with "<code>&amp;#x</code>", the digits and
+letters up to the terminating <code>;</code> provide a hexadecimal
+representation of the character's code point in ISO/IEC 10646.
+If it begins just with "<code>&amp;#</code>", the digits up to the terminating
+<code>;</code> provide a decimal representation of the character's
+code point.
+</termdef>
+</p>
+<p><termdef id="dt-entref" term="Entity Reference">An <term>entity
+reference</term> refers to the content of a named entity.</termdef>
+<termdef id='dt-GERef' term='General Entity Reference'>References to
+parsed general entities
+use ampersand (<code>&amp;</code>) and semicolon (<code>;</code>) as
+delimiters.</termdef>
+<termdef id='dt-PERef' term='Parameter-entity reference'>
+<term>Parameter-entity references</term> use percent-sign (<code>%</code>) and
+semicolon
+(<code>;</code>) as delimiters.</termdef>
+</p>
+<scrap lang="ebnf">
+<head>Entity Reference</head>
+<prod id='NT-Reference'><lhs>Reference</lhs>
+<rhs><nt def='NT-EntityRef'>EntityRef</nt>
+| <nt def='NT-CharRef'>CharRef</nt></rhs></prod>
+<prod id='NT-EntityRef'><lhs>EntityRef</lhs>
+<rhs>'&amp;' <nt def='NT-Name'>Name</nt> ';'</rhs>
+<wfc def='wf-entdeclared'/>
+<vc def='vc-entdeclared'/>
+<wfc def='textent'/>
+<wfc def='norecursion'/>
+</prod>
+<prod id='NT-PEReference'><lhs>PEReference</lhs>
+<rhs>'%' <nt def='NT-Name'>Name</nt> ';'</rhs>
+<vc def='vc-entdeclared'/>
+<wfc def='norecursion'/>
+<wfc def='indtd'/>
+</prod>
+</scrap>
+
+<wfcnote id='wf-entdeclared'>
+<head>Entity Declared</head>
+<p>In a document without any DTD, a document with only an internal
+DTD subset which contains no parameter entity references, or a document with
+"<code>standalone='yes'</code>",
+the <nt def='NT-Name'>Name</nt> given in the entity reference must
+<termref def="dt-match">match</termref> that in an
+<titleref href='sec-entity-decl'>entity declaration</titleref>, except that
+well-formed documents need not declare
+any of the following entities: &magicents;.
+The declaration of a parameter entity must precede any reference to it.
+Similarly, the declaration of a general entity must precede any
+reference to it which appears in a default value in an attribute-list
+declaration.</p>
+<p>Note that if entities are declared in the external subset or in
+external parameter entities, a non-validating processor is
+<titleref href='include-if-valid'>not obligated to</titleref> read
+and process their declarations; for such documents, the rule that
+an entity must be declared is a well-formedness constraint only
+if <titleref href='sec-rmd'>standalone='yes'</titleref>.</p>
+</wfcnote>
+<vcnote id="vc-entdeclared">
+<head>Entity Declared</head>
+<p>In a document with an external subset or external parameter
+entities with "<code>standalone='no'</code>",
+the <nt def='NT-Name'>Name</nt> given in the entity reference must <termref
+def="dt-match">match</termref> that in an
+<titleref href='sec-entity-decl'>entity declaration</titleref>.
+For interoperability, valid documents should declare the entities
+&magicents;, in the form
+specified in <specref ref="sec-predefined-ent"/>.
+The declaration of a parameter entity must precede any reference to it.
+Similarly, the declaration of a general entity must precede any
+reference to it which appears in a default value in an attribute-list
+declaration.</p>
+</vcnote>
+<!-- FINAL EDIT: is this duplication too clumsy? -->
+<wfcnote id='textent'>
+<head>Parsed Entity</head>
+<p>
+An entity reference must not contain the name of an <termref
+def="dt-unparsed">unparsed entity</termref>. Unparsed entities may be referred
+to only in <termref def="dt-attrval">attribute values</termref> declared to
+be of type <kw>ENTITY</kw> or <kw>ENTITIES</kw>.
+</p>
+</wfcnote>
+<wfcnote id='norecursion'>
+<head>No Recursion</head>
+<p>
+A parsed entity must not contain a recursive reference to itself,
+either directly or indirectly.
+</p>
+</wfcnote>
+<wfcnote id='indtd'>
+<head>In DTD</head>
+<p>
+Parameter-entity references may only appear in the
+<termref def='dt-doctype'>DTD</termref>.
+</p>
+</wfcnote>
+<p>Examples of character and entity references:
+<eg>Type &lt;key>less-than&lt;/key> (&hcro;3C;) to save options.
+This document was prepared on &amp;docdate; and
+is classified &amp;security-level;.</eg></p>
+<p>Example of a parameter-entity reference:
+<eg><![CDATA[<!-- declare the parameter entity "ISOLat2"... -->
+<!ENTITY % ISOLat2
+ SYSTEM "http://www.xml.com/iso/isolat2-xml.entities" >
+<!-- ... now reference it. -->
+%ISOLat2;]]></eg></p>
+</div2>
+
+<div2 id='sec-entity-decl'>
+<head>Entity Declarations</head>
+
+<p><termdef id="dt-entdecl" term="entity declaration">
+Entities are declared thus:
+<scrap lang='ebnf'>
+<head>Entity Declaration</head>
+<prodgroup pcw2="5" pcw4="18.5">
+<prod id='NT-EntityDecl'><lhs>EntityDecl</lhs>
+<rhs><nt def="NT-GEDecl">GEDecl</nt><!--</rhs><com>General entities</com>
+<rhs>--> | <nt def="NT-PEDecl">PEDecl</nt></rhs>
+<!--<com>Parameter entities</com>-->
+</prod>
+<prod id='NT-GEDecl'><lhs>GEDecl</lhs>
+<rhs>'&lt;!ENTITY' <nt def='NT-S'>S</nt> <nt def='NT-Name'>Name</nt>
+<nt def='NT-S'>S</nt> <nt def='NT-EntityDef'>EntityDef</nt>
+<nt def='NT-S'>S</nt>? '&gt;'</rhs>
+</prod>
+<prod id='NT-PEDecl'><lhs>PEDecl</lhs>
+<rhs>'&lt;!ENTITY' <nt def='NT-S'>S</nt> '%' <nt def='NT-S'>S</nt>
+<nt def='NT-Name'>Name</nt> <nt def='NT-S'>S</nt>
+<nt def='NT-PEDef'>PEDef</nt> <nt def='NT-S'>S</nt>? '&gt;'</rhs>
+<!--<com>Parameter entities</com>-->
+</prod>
+<prod id='NT-EntityDef'><lhs>EntityDef</lhs>
+<rhs><nt def='NT-EntityValue'>EntityValue</nt>
+<!--</rhs>
+<rhs>-->| (<nt def='NT-ExternalID'>ExternalID</nt>
+<nt def='NT-NDataDecl'>NDataDecl</nt>?)</rhs>
+<!-- <nt def='NT-ExternalDef'>ExternalDef</nt></rhs> -->
+</prod>
+<!-- FINAL EDIT: what happened to WFs here? -->
+<prod id='NT-PEDef'><lhs>PEDef</lhs>
+<rhs><nt def='NT-EntityValue'>EntityValue</nt>
+| <nt def='NT-ExternalID'>ExternalID</nt></rhs></prod>
+</prodgroup>
+</scrap>
+The <nt def='NT-Name'>Name</nt> identifies the entity in an
+<termref def="dt-entref">entity reference</termref> or, in the case of an
+unparsed entity, in the value of an <kw>ENTITY</kw> or <kw>ENTITIES</kw>
+attribute.
+If the same entity is declared more than once, the first declaration
+encountered is binding; at user option, an XML processor may issue a
+warning if entities are declared multiple times.</termdef>
+</p>
+
+<div3 id='sec-internal-ent'>
+<head>Internal Entities</head>
+
+<p><termdef id='dt-internent' term="Internal Entity Replacement Text">If
+the entity definition is an
+<nt def='NT-EntityValue'>EntityValue</nt>,
+the defined entity is called an <term>internal entity</term>.
+There is no separate physical
+storage object, and the content of the entity is given in the
+declaration. </termdef>
+Note that some processing of entity and character references in the
+<termref def='dt-litentval'>literal entity value</termref> may be required to
+produce the correct <termref def='dt-repltext'>replacement
+text</termref>: see <specref ref='intern-replacement'/>.
+</p>
+<p>An internal entity is a <termref def="dt-parsedent">parsed
+entity</termref>.</p>
+<p>Example of an internal entity declaration:
+<eg>&lt;!ENTITY Pub-Status "This is a pre-release of the
+ specification."></eg></p>
+</div3>
+
+<div3 id='sec-external-ent'>
+<head>External Entities</head>
+
+<p><termdef id="dt-extent" term="External Entity">If the entity is not
+internal, it is an <term>external
+entity</term>, declared as follows:
+<scrap lang='ebnf'>
+<head>External Entity Declaration</head>
+<!--
+<prod id='NT-ExternalDef'><lhs>ExternalDef</lhs>
+<rhs></prod> -->
+<prod id='NT-ExternalID'><lhs>ExternalID</lhs>
+<rhs>'SYSTEM' <nt def='NT-S'>S</nt>
+<nt def='NT-SystemLiteral'>SystemLiteral</nt></rhs>
+<rhs>| 'PUBLIC' <nt def='NT-S'>S</nt>
+<nt def='NT-PubidLiteral'>PubidLiteral</nt>
+<nt def='NT-S'>S</nt>
+<nt def='NT-SystemLiteral'>SystemLiteral</nt>
+</rhs>
+</prod>
+<prod id='NT-NDataDecl'><lhs>NDataDecl</lhs>
+<rhs><nt def='NT-S'>S</nt> 'NDATA' <nt def='NT-S'>S</nt>
+<nt def='NT-Name'>Name</nt></rhs>
+<vc def='not-declared'/></prod>
+</scrap>
+If the <nt def='NT-NDataDecl'>NDataDecl</nt> is present, this is a
+general <termref def="dt-unparsed">unparsed
+entity</termref>; otherwise it is a parsed entity.</termdef></p>
+<vcnote id='not-declared'>
+<head>Notation Declared</head>
+<p>
+The <nt def='NT-Name'>Name</nt> must match the declared name of a
+<termref def="dt-notation">notation</termref>.
+</p>
+</vcnote>
+<p><termdef id="dt-sysid" term="System Identifier">The
+<nt def='NT-SystemLiteral'>SystemLiteral</nt>
+is called the entity's <term>system identifier</term>. It is a URI,
+which may be used to retrieve the entity.</termdef>
+Note that the hash mark (<code>#</code>) and fragment identifier
+frequently used with URIs are not, formally, part of the URI itself;
+an XML processor may signal an error if a fragment identifier is
+given as part of a system identifier.
+Unless otherwise provided by information outside the scope of this
+specification (e.g. a special XML element type defined by a particular
+DTD, or a processing instruction defined by a particular application
+specification), relative URIs are relative to the location of the
+resource within which the entity declaration occurs.
+A URI might thus be relative to the
+<termref def='dt-docent'>document entity</termref>, to the entity
+containing the <termref def='dt-doctype'>external DTD subset</termref>,
+or to some other <termref def='dt-extent'>external parameter entity</termref>.
+</p>
+<p>An XML processor should handle a non-ASCII character in a URI by
+representing the character in UTF-8 as one or more bytes, and then
+escaping these bytes with the URI escaping mechanism (i.e., by
+converting each byte to %HH, where HH is the hexadecimal notation of the
+byte value).</p>
+<p><termdef id="dt-pubid" term="Public identifier">
+In addition to a system identifier, an external identifier may
+include a <term>public identifier</term>.</termdef>
+An XML processor attempting to retrieve the entity's content may use the public
+identifier to try to generate an alternative URI. If the processor
+is unable to do so, it must use the URI specified in the system
+literal. Before a match is attempted, all strings
+of white space in the public identifier must be normalized to single space characters (#x20),
+and leading and trailing white space must be removed.</p>
+<p>Examples of external entity declarations:
+<eg>&lt;!ENTITY open-hatch
+ SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">
+&lt;!ENTITY open-hatch
+ PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN"
+ "http://www.textuality.com/boilerplate/OpenHatch.xml">
+&lt;!ENTITY hatch-pic
+ SYSTEM "../grafix/OpenHatch.gif"
+ NDATA gif ></eg></p>
+</div3>
+
+</div2>
+
+<div2 id='TextEntities'>
+<head>Parsed Entities</head>
+<div3 id='sec-TextDecl'>
+<head>The Text Declaration</head>
+<p>External parsed entities may each begin with a <term>text
+declaration</term>.
+<scrap lang='ebnf'>
+<head>Text Declaration</head>
+<prodgroup pcw4="12.5" pcw5="13">
+<prod id='NT-TextDecl'><lhs>TextDecl</lhs>
+<rhs>&xmlpio;
+<nt def='NT-VersionInfo'>VersionInfo</nt>?
+<nt def='NT-EncodingDecl'>EncodingDecl</nt>
+<nt def='NT-S'>S</nt>? &pic;</rhs>
+</prod>
+</prodgroup>
+</scrap>
+</p>
+<p>The text declaration must be provided literally, not
+by reference to a parsed entity.
+No text declaration may appear at any position other than the beginning of
+an external parsed entity.</p>
+</div3>
+<div3 id='wf-entities'>
+<head>Well-Formed Parsed Entities</head>
+<p>The document entity is well-formed if it matches the production labeled
+<nt def='NT-document'>document</nt>.
+An external general
+parsed entity is well-formed if it matches the production labeled
+<nt def='NT-extParsedEnt'>extParsedEnt</nt>.
+An external parameter
+entity is well-formed if it matches the production labeled
+<nt def='NT-extPE'>extPE</nt>.
+<scrap lang='ebnf'>
+<head>Well-Formed External Parsed Entity</head>
+<prod id='NT-extParsedEnt'><lhs>extParsedEnt</lhs>
+<rhs><nt def='NT-TextDecl'>TextDecl</nt>?
+<nt def='NT-content'>content</nt></rhs>
+</prod>
+<prod id='NT-extPE'><lhs>extPE</lhs>
+<rhs><nt def='NT-TextDecl'>TextDecl</nt>?
+<nt def='NT-extSubsetDecl'>extSubsetDecl</nt></rhs>
+</prod>
+</scrap>
+An internal general parsed entity is well-formed if its replacement text
+matches the production labeled
+<nt def='NT-content'>content</nt>.
+All internal parameter entities are well-formed by definition.
+</p>
+<p>A consequence of well-formedness in entities is that the logical
+and physical structures in an XML document are properly nested; no
+<termref def='dt-stag'>start-tag</termref>,
+<termref def='dt-etag'>end-tag</termref>,
+<termref def="dt-empty">empty-element tag</termref>,
+<termref def='dt-element'>element</termref>,
+<termref def='dt-comment'>comment</termref>,
+<termref def='dt-pi'>processing instruction</termref>,
+<termref def='dt-charref'>character
+reference</termref>, or
+<termref def='dt-entref'>entity reference</termref>
+can begin in one entity and end in another.</p>
+</div3>
+<div3 id='charencoding'>
+<head>Character Encoding in Entities</head>
+
+<p>Each external parsed entity in an XML document may use a different
+encoding for its characters. All XML processors must be able to read
+entities in either UTF-8 or UTF-16.
+
+</p>
+<p>Entities encoded in UTF-16 must
+begin with the Byte Order Mark described by ISO/IEC 10646 Annex E and
+Unicode Appendix B (the ZERO WIDTH NO-BREAK SPACE character, #xFEFF).
+This is an encoding signature, not part of either the markup or the
+character data of the XML document.
+XML processors must be able to use this character to
+differentiate between UTF-8 and UTF-16 encoded documents.</p>
+<p>Although an XML processor is required to read only entities in
+the UTF-8 and UTF-16 encodings, it is recognized that other encodings are
+used around the world, and it may be desired for XML processors
+to read entities that use them.
+Parsed entities which are stored in an encoding other than
+UTF-8 or UTF-16 must begin with a <titleref href='TextDecl'>text
+declaration</titleref> containing an encoding declaration:
+<scrap lang='ebnf'>
+<head>Encoding Declaration</head>
+<prod id='NT-EncodingDecl'><lhs>EncodingDecl</lhs>
+<rhs><nt def="NT-S">S</nt>
+'encoding' <nt def='NT-Eq'>Eq</nt>
+('"' <nt def='NT-EncName'>EncName</nt> '"' |
+"'" <nt def='NT-EncName'>EncName</nt> "'" )
+</rhs>
+</prod>
+<prod id='NT-EncName'><lhs>EncName</lhs>
+<rhs>[A-Za-z] ([A-Za-z0-9._] | '-')*</rhs>
+<com>Encoding name contains only Latin characters</com>
+</prod>
+</scrap>
+In the <termref def='dt-docent'>document entity</termref>, the encoding
+declaration is part of the <termref def="dt-xmldecl">XML declaration</termref>.
+The <nt def="NT-EncName">EncName</nt> is the name of the encoding used.
+</p>
+<!-- FINAL EDIT: check name of IANA and charset names -->
+<p>In an encoding declaration, the values
+"<code>UTF-8</code>",
+"<code>UTF-16</code>",
+"<code>ISO-10646-UCS-2</code>", and
+"<code>ISO-10646-UCS-4</code>" should be
+used for the various encodings and transformations of Unicode /
+ISO/IEC 10646, the values
+"<code>ISO-8859-1</code>",
+"<code>ISO-8859-2</code>", ...
+"<code>ISO-8859-9</code>" should be used for the parts of ISO 8859, and
+the values
+"<code>ISO-2022-JP</code>",
+"<code>Shift_JIS</code>", and
+"<code>EUC-JP</code>"
+should be used for the various encoded forms of JIS X-0208-1997. XML
+processors may recognize other encodings; it is recommended that
+character encodings registered (as <emph>charset</emph>s)
+with the Internet Assigned Numbers
+Authority <bibref ref='IANA'/>, other than those just listed, should be
+referred to
+using their registered names.
+Note that these registered names are defined to be
+case-insensitive, so processors wishing to match against them
+should do so in a case-insensitive
+way.</p>
+<p>In the absence of information provided by an external
+transport protocol (e.g. HTTP or MIME),
+it is an <termref def="dt-error">error</termref> for an entity including
+an encoding declaration to be presented to the XML processor
+in an encoding other than that named in the declaration,
+for an encoding declaration to occur other than at the beginning
+of an external entity, or for
+an entity which begins with neither a Byte Order Mark nor an encoding
+declaration to use an encoding other than UTF-8.
+Note that since ASCII
+is a subset of UTF-8, ordinary ASCII entities do not strictly need
+an encoding declaration.</p>
+
+<p>It is a <termref def='dt-fatal'>fatal error</termref> when an XML processor
+encounters an entity with an encoding that it is unable to process.</p>
+<p>Examples of encoding declarations:
+<eg>&lt;?xml encoding='UTF-8'?>
+&lt;?xml encoding='EUC-JP'?></eg></p>
+</div3>
+</div2>
+<div2 id='entproc'>
+<head>XML Processor Treatment of Entities and References</head>
+<p>The table below summarizes the contexts in which character references,
+entity references, and invocations of unparsed entities might appear and the
+required behavior of an <termref def='dt-xml-proc'>XML processor</termref> in
+each case.
+The labels in the leftmost column describe the recognition context:
+<glist>
+<gitem><label>Reference in Content</label>
+<def><p>as a reference
+anywhere after the <termref def='dt-stag'>start-tag</termref> and
+before the <termref def='dt-etag'>end-tag</termref> of an element; corresponds
+to the nonterminal <nt def='NT-content'>content</nt>.</p></def>
+</gitem>
+<gitem>
+<label>Reference in Attribute Value</label>
+<def><p>as a reference within either the value of an attribute in a
+<termref def='dt-stag'>start-tag</termref>, or a default
+value in an <termref def='dt-attdecl'>attribute declaration</termref>;
+corresponds to the nonterminal
+<nt def='NT-AttValue'>AttValue</nt>.</p></def></gitem>
+<gitem>
+<label>Occurs as Attribute Value</label>
+<def><p>as a <nt def='NT-Name'>Name</nt>, not a reference, appearing either as
+the value of an
+attribute which has been declared as type <kw>ENTITY</kw>, or as one of
+the space-separated tokens in the value of an attribute which has been
+declared as type <kw>ENTITIES</kw>.</p>
+</def></gitem>
+<gitem><label>Reference in Entity Value</label>
+<def><p>as a reference
+within a parameter or internal entity's
+<termref def='dt-litentval'>literal entity value</termref> in
+the entity's declaration; corresponds to the nonterminal
+<nt def='NT-EntityValue'>EntityValue</nt>.</p></def></gitem>
+<gitem><label>Reference in DTD</label>
+<def><p>as a reference within either the internal or external subsets of the
+<termref def='dt-doctype'>DTD</termref>, but outside
+of an <nt def='NT-EntityValue'>EntityValue</nt> or
+<nt def="NT-AttValue">AttValue</nt>.</p></def>
+</gitem>
+</glist></p>
+<htable border='1' cellpadding='7' align='center'>
+<htbody>
+<tr><td bgcolor='&cellback;' rowspan='2' colspan='1'></td>
+<td bgcolor='&cellback;' align='center' valign='bottom' colspan='4'>Entity Type</td>
+<td bgcolor='&cellback;' rowspan='2' align='center'>Character</td>
+</tr>
+<tr align='center' valign='bottom'>
+<td bgcolor='&cellback;'>Parameter</td>
+<td bgcolor='&cellback;'>Internal
+General</td>
+<td bgcolor='&cellback;'>External Parsed
+General</td>
+<td bgcolor='&cellback;'>Unparsed</td>
+</tr>
+<tr align='center' valign='middle'>
+
+<td bgcolor='&cellback;' align='right'>Reference
+in Content</td>
+<td bgcolor='&cellback;'><titleref href='not-recognized'>Not recognized</titleref></td>
+<td bgcolor='&cellback;'><titleref href='included'>Included</titleref></td>
+<td bgcolor='&cellback;'><titleref href='include-if-valid'>Included if validating</titleref></td>
+<td bgcolor='&cellback;'><titleref href='forbidden'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='included'>Included</titleref></td>
+</tr>
+<tr align='center' valign='middle'>
+<td bgcolor='&cellback;' align='right'>Reference
+in Attribute Value</td>
+<td bgcolor='&cellback;'><titleref href='not-recognized'>Not recognized</titleref></td>
+<td bgcolor='&cellback;'><titleref href='inliteral'>Included in literal</titleref></td>
+<td bgcolor='&cellback;'><titleref href='forbidden'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='forbidden'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='included'>Included</titleref></td>
+</tr>
+<tr align='center' valign='middle'>
+<td bgcolor='&cellback;' align='right'>Occurs as
+Attribute Value</td>
+<td bgcolor='&cellback;'><titleref href='not-recognized'>Not recognized</titleref></td>
+<td bgcolor='&cellback;'><titleref href='not-recognized'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='not-recognized'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='notify'>Notify</titleref></td>
+<td bgcolor='&cellback;'><titleref href='not recognized'>Not recognized</titleref></td>
+</tr>
+<tr align='center' valign='middle'>
+<td bgcolor='&cellback;' align='right'>Reference
+in EntityValue</td>
+<td bgcolor='&cellback;'><titleref href='inliteral'>Included in literal</titleref></td>
+<td bgcolor='&cellback;'><titleref href='bypass'>Bypassed</titleref></td>
+<td bgcolor='&cellback;'><titleref href='bypass'>Bypassed</titleref></td>
+<td bgcolor='&cellback;'><titleref href='forbidden'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='included'>Included</titleref></td>
+</tr>
+<tr align='center' valign='middle'>
+<td bgcolor='&cellback;' align='right'>Reference
+in DTD</td>
+<td bgcolor='&cellback;'><titleref href='as-PE'>Included as PE</titleref></td>
+<td bgcolor='&cellback;'><titleref href='forbidden'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='forbidden'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='forbidden'>Forbidden</titleref></td>
+<td bgcolor='&cellback;'><titleref href='forbidden'>Forbidden</titleref></td>
+</tr>
+</htbody>
+</htable>
+<div3 id='not-recognized'>
+<head>Not Recognized</head>
+<p>Outside the DTD, the <code>%</code> character has no
+special significance; thus, what would be parameter entity references in the
+DTD are not recognized as markup in <nt def='NT-content'>content</nt>.
+Similarly, the names of unparsed entities are not recognized except
+when they appear in the value of an appropriately declared attribute.
+</p>
+</div3>
+<div3 id='included'>
+<head>Included</head>
+<p><termdef id="dt-include" term="Include">An entity is
+<term>included</term> when its
+<termref def='dt-repltext'>replacement text</termref> is retrieved
+and processed, in place of the reference itself,
+as though it were part of the document at the location the
+reference was recognized.
+The replacement text may contain both
+<termref def='dt-chardata'>character data</termref>
+and (except for parameter entities) <termref def="dt-markup">markup</termref>,
+which must be recognized in
+the usual way, except that the replacement text of entities used to escape
+markup delimiters (the entities &magicents;) is always treated as
+data. (The string "<code>AT&amp;amp;T;</code>" expands to
+"<code>AT&amp;T;</code>" and the remaining ampersand is not recognized
+as an entity-reference delimiter.)
+A character reference is <term>included</term> when the indicated
+character is processed in place of the reference itself.
+</termdef></p>
+</div3>
+<div3 id='include-if-valid'>
+<head>Included If Validating</head>
+<p>When an XML processor recognizes a reference to a parsed entity, in order
+to <termref def="dt-valid">validate</termref>
+the document, the processor must
+<termref def="dt-include">include</termref> its
+replacement text.
+If the entity is external, and the processor is not
+attempting to validate the XML document, the
+processor <termref def="dt-may">may</termref>, but need not,
+include the entity's replacement text.
+If a non-validating parser does not include the replacement text,
+it must inform the application that it recognized, but did not
+read, the entity.</p>
+<p>This rule is based on the recognition that the automatic inclusion
+provided by the SGML and XML entity mechanism, primarily designed
+to support modularity in authoring, is not necessarily
+appropriate for other applications, in particular document browsing.
+Browsers, for example, when encountering an external parsed entity reference,
+might choose to provide a visual indication of the entity's
+presence and retrieve it for display only on demand.
+</p>
+</div3>
+<div3 id='forbidden'>
+<head>Forbidden</head>
+<p>The following are forbidden, and constitute
+<termref def='dt-fatal'>fatal</termref> errors:
+<ulist>
+<item><p>the appearance of a reference to an
+<termref def='dt-unparsed'>unparsed entity</termref>.
+</p></item>
+<item><p>the appearance of any character or general-entity reference in the
+DTD except within an <nt def='NT-EntityValue'>EntityValue</nt> or
+<nt def="NT-AttValue">AttValue</nt>.</p></item>
+<item><p>a reference to an external entity in an attribute value.</p>
+</item>
+</ulist>
+</p>
+</div3>
+<div3 id='inliteral'>
+<head>Included in Literal</head>
+<p>When an <termref def='dt-entref'>entity reference</termref> appears in an
+attribute value, or a parameter entity reference appears in a literal entity
+value, its <termref def='dt-repltext'>replacement text</termref> is
+processed in place of the reference itself as though it
+were part of the document at the location the reference was recognized,
+except that a single or double quote character in the replacement text
+is always treated as a normal data character and will not terminate the
+literal.
+For example, this is well-formed:
+<eg><![CDATA[<!ENTITY % YN '"Yes"' >
+<!ENTITY WhatHeSaid "He said &YN;" >]]></eg>
+while this is not:
+<eg>&lt;!ENTITY EndAttr "27'" >
+&lt;element attribute='a-&amp;EndAttr;></eg>
+</p></div3>
+<div3 id='notify'>
+<head>Notify</head>
+<p>When the name of an <termref def='dt-unparsed'>unparsed
+entity</termref> appears as a token in the
+value of an attribute of declared type <kw>ENTITY</kw> or <kw>ENTITIES</kw>,
+a validating processor must inform the
+application of the <termref def='dt-sysid'>system</termref>
+and <termref def='dt-pubid'>public</termref> (if any)
+identifiers for both the entity and its associated
+<termref def="dt-notation">notation</termref>.</p>
+</div3>
+<div3 id='bypass'>
+<head>Bypassed</head>
+<p>When a general entity reference appears in the
+<nt def='NT-EntityValue'>EntityValue</nt> in an entity declaration,
+it is bypassed and left as is.</p>
+</div3>
+<div3 id='as-PE'>
+<head>Included as PE</head>
+<p>Just as with external parsed entities, parameter entities
+need only be <titleref href='include-if-valid'>included if
+validating</titleref>.
+When a parameter-entity reference is recognized in the DTD
+and included, its
+<termref def='dt-repltext'>replacement
+text</termref> is enlarged by the attachment of one leading and one following
+space (#x20) character; the intent is to constrain the replacement
+text of parameter
+entities to contain an integral number of grammatical tokens in the DTD.
+</p>
+</div3>
+
+</div2>
+<div2 id='intern-replacement'>
+<head>Construction of Internal Entity Replacement Text</head>
+<p>In discussing the treatment
+of internal entities, it is
+useful to distinguish two forms of the entity's value.
+<termdef id="dt-litentval" term='Literal Entity Value'>The <term>literal
+entity value</term> is the quoted string actually
+present in the entity declaration, corresponding to the
+non-terminal <nt def='NT-EntityValue'>EntityValue</nt>.</termdef>
+<termdef id='dt-repltext' term='Replacement Text'>The <term>replacement
+text</term> is the content of the entity, after
+replacement of character references and parameter-entity
+references.
+</termdef></p>
+
+<p>The literal entity value
+as given in an internal entity declaration
+(<nt def='NT-EntityValue'>EntityValue</nt>) may contain character,
+parameter-entity, and general-entity references.
+Such references must be contained entirely within the
+literal entity value.
+The actual replacement text that is
+<termref def='dt-include'>included</termref> as described above
+must contain the <emph>replacement text</emph> of any
+parameter entities referred to, and must contain the character
+referred to, in place of any character references in the
+literal entity value; however,
+general-entity references must be left as-is, unexpanded.
+For example, given the following declarations:
+
+<eg><![CDATA[<!ENTITY % pub "&#xc9;ditions Gallimard" >
+<!ENTITY rights "All rights reserved" >
+<!ENTITY book "La Peste: Albert Camus,
+&#xA9; 1947 %pub;. &rights;" >]]></eg>
+then the replacement text for the entity "<code>book</code>" is:
+<eg>La Peste: Albert Camus,
+&#169; 1947 &#201;ditions Gallimard. &amp;rights;</eg>
+The general-entity reference "<code>&amp;rights;</code>" would be expanded
+should the reference "<code>&amp;book;</code>" appear in the document's
+content or an attribute value.</p>
+<p>These simple rules may have complex interactions; for a detailed
+discussion of a difficult example, see
+<specref ref='sec-entexpand'/>.
+</p>
+
+</div2>
+<div2 id='sec-predefined-ent'>
+<head>Predefined Entities</head>
+<p><termdef id="dt-escape" term="escape">Entity and character
+references can both be used to <term>escape</term> the left angle bracket,
+ampersand, and other delimiters. A set of general entities
+(&magicents;) is specified for this purpose.
+Numeric character references may also be used; they are
+expanded immediately when recognized and must be treated as
+character data, so the numeric character references
+"<code>&amp;#60;</code>" and "<code>&amp;#38;</code>" may be used to
+escape <code>&lt;</code> and <code>&amp;</code> when they occur
+in character data.</termdef></p>
+<p>All XML processors must recognize these entities whether they
+are declared or not.
+<termref def='dt-interop'>For interoperability</termref>,
+valid XML documents should declare these
+entities, like any others, before using them.
+If the entities in question are declared, they must be declared
+as internal entities whose replacement text is the single
+character being escaped or a character reference to
+that character, as shown below.
+<eg><![CDATA[<!ENTITY lt "&#38;#60;">
+<!ENTITY gt "&#62;">
+<!ENTITY amp "&#38;#38;">
+<!ENTITY apos "&#39;">
+<!ENTITY quot "&#34;">
+]]></eg>
+Note that the <code>&lt;</code> and <code>&amp;</code> characters
+in the declarations of "<code>lt</code>" and "<code>amp</code>"
+are doubly escaped to meet the requirement that entity replacement
+be well-formed.
+</p>
+</div2>
+
+<div2 id='Notations'>
+<head>Notation Declarations</head>
+
+<p><termdef id="dt-notation" term="Notation"><term>Notations</term> identify by
+name the format of <termref def="dt-extent">unparsed
+entities</termref>, the
+format of elements which bear a notation attribute,
+or the application to which
+a <termref def="dt-pi">processing instruction</termref> is
+addressed.</termdef></p>
+<p><termdef id="dt-notdecl" term="Notation Declaration">
+<term>Notation declarations</term>
+provide a name for the notation, for use in
+entity and attribute-list declarations and in attribute specifications,
+and an external identifier for the notation which may allow an XML
+processor or its client application to locate a helper application
+capable of processing data in the given notation.
+<scrap lang='ebnf'>
+<head>Notation Declarations</head>
+<prod id='NT-NotationDecl'><lhs>NotationDecl</lhs>
+<rhs>'&lt;!NOTATION' <nt def='NT-S'>S</nt> <nt def='NT-Name'>Name</nt>
+<nt def='NT-S'>S</nt>
+(<nt def='NT-ExternalID'>ExternalID</nt> |
+<nt def='NT-PublicID'>PublicID</nt>)
+<nt def='NT-S'>S</nt>? '>'</rhs></prod>
+<prod id='NT-PublicID'><lhs>PublicID</lhs>
+<rhs>'PUBLIC' <nt def='NT-S'>S</nt>
+<nt def='NT-PubidLiteral'>PubidLiteral</nt>
+</rhs></prod>
+</scrap>
+</termdef></p>
+<p>XML processors must provide applications with the name and external
+identifier(s) of any notation declared and referred to in an attribute
+value, attribute definition, or entity declaration. They may
+additionally resolve the external identifier into the
+<termref def="dt-sysid">system identifier</termref>,
+file name, or other information needed to allow the
+application to call a processor for data in the notation described. (It
+is not an error, however, for XML documents to declare and refer to
+notations for which notation-specific applications are not available on
+the system where the XML processor or application is running.)</p>
+</div2>
+
+
+<div2 id='sec-doc-entity'>
+<head>Document Entity</head>
+
+<p><termdef id="dt-docent" term="Document Entity">The <term>document
+entity</term> serves as the root of the entity
+tree and a starting-point for an <termref def="dt-xml-proc">XML
+processor</termref>.</termdef>
+This specification does
+not specify how the document entity is to be located by an XML
+processor; unlike other entities, the document entity has no name and might
+well appear on a processor input stream
+without any identification at all.</p>
+</div2>
+
+
+</div1>
+<!-- &Conformance; -->
+
+<div1 id='sec-conformance'>
+<head>Conformance</head>
+
+<div2 id='proc-types'>
+<head>Validating and Non-Validating Processors</head>
+<p>Conforming <termref def="dt-xml-proc">XML processors</termref> fall into two
+classes: validating and non-validating.</p>
+<p>Validating and non-validating processors alike must report
+violations of this specification's well-formedness constraints
+in the content of the
+<termref def='dt-docent'>document entity</termref> and any
+other <termref def='dt-parsedent'>parsed entities</termref> that
+they read.</p>
+<p><termdef id="dt-validating" term="Validating Processor">
+<term>Validating processors</term> must report
+violations of the constraints expressed by the declarations in the
+<termref def="dt-doctype">DTD</termref>, and
+failures to fulfill the validity constraints given
+in this specification.
+</termdef>
+To accomplish this, validating XML processors must read and process the entire
+DTD and all external parsed entities referenced in the document.
+</p>
+<p>Non-validating processors are required to check only the
+<termref def='dt-docent'>document entity</termref>, including
+the entire internal DTD subset, for well-formedness.
+<termdef id='dt-use-mdecl' term='Process Declarations'>
+While they are not required to check the document for validity,
+they are required to
+<term>process</term> all the declarations they read in the
+internal DTD subset and in any parameter entity that they
+read, up to the first reference
+to a parameter entity that they do <emph>not</emph> read; that is to
+say, they must
+use the information in those declarations to
+<titleref href='AVNormalize'>normalize</titleref> attribute values,
+<titleref href='included'>include</titleref> the replacement text of
+internal entities, and supply
+<titleref href='sec-attr-defaults'>default attribute values</titleref>.
+</termdef>
+They must not <termref def='dt-use-mdecl'>process</termref>
+<termref def='dt-entdecl'>entity declarations</termref> or
+<termref def='dt-attdecl'>attribute-list declarations</termref>
+encountered after a reference to a parameter entity that is not
+read, since the entity may have contained overriding declarations.
+</p>
+</div2>
+<div2 id='safe-behavior'>
+<head>Using XML Processors</head>
+<p>The behavior of a validating XML processor is highly predictable; it
+must read every piece of a document and report all well-formedness and
+validity violations.
+Less is required of a non-validating processor; it need not read any
+part of the document other than the document entity.
+This has two effects that may be important to users of XML processors:
+<ulist>
+<item><p>Certain well-formedness errors, specifically those that require
+reading external entities, may not be detected by a non-validating processor.
+Examples include the constraints entitled
+<titleref href='wf-entdeclared'>Entity Declared</titleref>,
+<titleref href='wf-textent'>Parsed Entity</titleref>, and
+<titleref href='wf-norecursion'>No Recursion</titleref>, as well
+as some of the cases described as
+<titleref href='forbidden'>forbidden</titleref> in
+<specref ref='entproc'/>.</p></item>
+<item><p>The information passed from the processor to the application may
+vary, depending on whether the processor reads
+parameter and external entities.
+For example, a non-validating processor may not
+<titleref href='AVNormalize'>normalize</titleref> attribute values,
+<titleref href='included'>include</titleref> the replacement text of
+internal entities, or supply
+<titleref href='sec-attr-defaults'>default attribute values</titleref>,
+where doing so depends on having read declarations in
+external or parameter entities.</p></item>
+</ulist>
+</p>
+<p>For maximum reliability in interoperating between different XML
+processors, applications which use non-validating processors should not
+rely on any behaviors not required of such processors.
+Applications which require facilities such as the use of default
+attributes or internal entities which are declared in external
+entities should use validating XML processors.</p>
+</div2>
+</div1>
+
+<div1 id='sec-notation'>
+<head>Notation</head>
+
+<p>The formal grammar of XML is given in this specification using a simple
+Extended Backus-Naur Form (EBNF) notation. Each rule in the grammar defines
+one symbol, in the form
+<eg>symbol ::= expression</eg></p>
+<p>Symbols are written with an initial capital letter if they are
+defined by a regular expression, or with an initial lower case letter
+otherwise.
+Literal strings are quoted.
+
+</p>
+
+<p>Within the expression on the right-hand side of a rule, the following
+expressions are used to match strings of one or more characters:
+<glist>
+<gitem>
+<label><code>#xN</code></label>
+<def><p>where <code>N</code> is a hexadecimal integer, the
+expression matches the character in ISO/IEC 10646 whose canonical
+(UCS-4)
+code value, when interpreted as an unsigned binary number, has
+the value indicated. The number of leading zeros in the
+<code>#xN</code> form is insignificant; the number of leading
+zeros in the corresponding code value
+is governed by the character
+encoding in use and is not significant for XML.</p></def>
+</gitem>
+<gitem>
+<label><code>[a-zA-Z]</code>, <code>[#xN-#xN]</code></label>
+<def><p>matches any <termref def='dt-character'>character</termref>
+with a value in the range(s) indicated (inclusive).</p></def>
+</gitem>
+<gitem>
+<label><code>[^a-z]</code>, <code>[^#xN-#xN]</code></label>
+<def><p>matches any <termref def='dt-character'>character</termref>
+with a value <emph>outside</emph> the
+range indicated.</p></def>
+</gitem>
+<gitem>
+<label><code>[^abc]</code>, <code>[^#xN#xN#xN]</code></label>
+<def><p>matches any <termref def='dt-character'>character</termref>
+with a value not among the characters given.</p></def>
+</gitem>
+<gitem>
+<label><code>"string"</code></label>
+<def><p>matches a literal string <termref def="dt-match">matching</termref>
+that given inside the double quotes.</p></def>
+</gitem>
+<gitem>
+<label><code>'string'</code></label>
+<def><p>matches a literal string <termref def="dt-match">matching</termref>
+that given inside the single quotes.</p></def>
+</gitem>
+</glist>
+These symbols may be combined to match more complex patterns as follows,
+where <code>A</code> and <code>B</code> represent simple expressions:
+<glist>
+<gitem>
+<label>(<code>expression</code>)</label>
+<def><p><code>expression</code> is treated as a unit
+and may be combined as described in this list.</p></def>
+</gitem>
+<gitem>
+<label><code>A?</code></label>
+<def><p>matches <code>A</code> or nothing; optional <code>A</code>.</p></def>
+</gitem>
+<gitem>
+<label><code>A B</code></label>
+<def><p>matches <code>A</code> followed by <code>B</code>.</p></def>
+</gitem>
+<gitem>
+<label><code>A | B</code></label>
+<def><p>matches <code>A</code> or <code>B</code> but not both.</p></def>
+</gitem>
+<gitem>
+<label><code>A - B</code></label>
+<def><p>matches any string that matches <code>A</code> but does not match
+<code>B</code>.
+</p></def>
+</gitem>
+<gitem>
+<label><code>A+</code></label>
+<def><p>matches one or more occurrences of <code>A</code>.</p></def>
+</gitem>
+<gitem>
+<label><code>A*</code></label>
+<def><p>matches zero or more occurrences of <code>A</code>.</p></def>
+</gitem>
+
+</glist>
+Other notations used in the productions are:
+<glist>
+<gitem>
+<label><code>/* ... */</code></label>
+<def><p>comment.</p></def>
+</gitem>
+<gitem>
+<label><code>[ wfc: ... ]</code></label>
+<def><p>well-formedness constraint; this identifies by name a
+constraint on
+<termref def="dt-wellformed">well-formed</termref> documents
+associated with a production.</p></def>
+</gitem>
+<gitem>
+<label><code>[ vc: ... ]</code></label>
+<def><p>validity constraint; this identifies by name a constraint on
+<termref def="dt-valid">valid</termref> documents associated with
+a production.</p></def>
+</gitem>
+</glist>
+</p></div1>
+
+</body>
+<back>
+<!-- &SGML; -->
+
+
+<!-- &Biblio; -->
+<div1 id='sec-bibliography'>
+
+<head>References</head>
+<div2 id='sec-existing-stds'>
+<head>Normative References</head>
+
+<blist>
+<bibl id='IANA' key='IANA'>
+(Internet Assigned Numbers Authority) <emph>Official Names for
+Character Sets</emph>,
+ed. Keld Simonsen et al.
+See <loc href='ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets'>ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets</loc>.
+</bibl>
+
+<bibl id='RFC1766' key='IETF RFC 1766'>
+IETF (Internet Engineering Task Force).
+<emph>RFC 1766: Tags for the Identification of Languages</emph>,
+ed. H. Alvestrand.
+1995.
+</bibl>
+
+<bibl id='ISO639' key='ISO 639'>
+(International Organization for Standardization).
+<emph>ISO 639:1988 (E).
+Code for the representation of names of languages.</emph>
+[Geneva]: International Organization for
+Standardization, 1988.</bibl>
+
+<bibl id='ISO3166' key='ISO 3166'>
+(International Organization for Standardization).
+<emph>ISO 3166-1:1997 (E).
+Codes for the representation of names of countries and their subdivisions
+&mdash; Part 1: Country codes</emph>
+[Geneva]: International Organization for
+Standardization, 1997.</bibl>
+
+<bibl id='ISO10646' key='ISO/IEC 10646'>ISO
+(International Organization for Standardization).
+<emph>ISO/IEC 10646-1993 (E). Information technology &mdash; Universal
+Multiple-Octet Coded Character Set (UCS) &mdash; Part 1:
+Architecture and Basic Multilingual Plane.</emph>
+[Geneva]: International Organization for
+Standardization, 1993 (plus amendments AM 1 through AM 7).
+</bibl>
+
+<bibl id='Unicode' key='Unicode'>The Unicode Consortium.
+<emph>The Unicode Standard, Version 2.0.</emph>
+Reading, Mass.: Addison-Wesley Developers Press, 1996.</bibl>
+
+</blist>
+
+</div2>
+
+<div2><head>Other References</head>
+
+<blist>
+
+<bibl id='Aho' key='Aho/Ullman'>Aho, Alfred V.,
+Ravi Sethi, and Jeffrey D. Ullman.
+<emph>Compilers: Principles, Techniques, and Tools</emph>.
+Reading: Addison-Wesley, 1986, rpt. corr. 1988.</bibl>
+
+<bibl id="Berners-Lee" xml-link="simple" key="Berners-Lee et al.">
+Berners-Lee, T., R. Fielding, and L. Masinter.
+<emph>Uniform Resource Identifiers (URI): Generic Syntax and
+Semantics</emph>.
+1997.
+(Work in progress; see updates to RFC1738.)</bibl>
+
+<bibl id='ABK' key='Brüggemann-Klein'>Brüggemann-Klein, Anne.
+<emph>Regular Expressions into Finite Automata</emph>.
+Extended abstract in I. Simon, Hrsg., LATIN 1992,
+S. 97-98. Springer-Verlag, Berlin 1992.
+Full Version in Theoretical Computer Science 120: 197-213, 1993.
+
+</bibl>
+
+<bibl id='ABKDW' key='Brüggemann-Klein and Wood'>Brüggemann-Klein, Anne,
+and Derick Wood.
+<emph>Deterministic Regular Languages</emph>.
+Universität Freiburg, Institut für Informatik,
+Bericht 38, Oktober 1991.
+</bibl>
+
+<bibl id='Clark' key='Clark'>James Clark.
+Comparison of SGML and XML. See
+<loc href='http://www.w3.org/TR/NOTE-sgml-xml-971215'>http://www.w3.org/TR/NOTE-sgml-xml-971215</loc>.
+</bibl>
+<bibl id="RFC1738" xml-link="simple" key="IETF RFC1738">
+IETF (Internet Engineering Task Force).
+<emph>RFC 1738: Uniform Resource Locators (URL)</emph>,
+ed. T. Berners-Lee, L. Masinter, M. McCahill.
+1994.
+</bibl>
+
+<bibl id="RFC1808" xml-link="simple" key="IETF RFC1808">
+IETF (Internet Engineering Task Force).
+<emph>RFC 1808: Relative Uniform Resource Locators</emph>,
+ed. R. Fielding.
+1995.
+</bibl>
+
+<bibl id="RFC2141" xml-link="simple" key="IETF RFC2141">
+IETF (Internet Engineering Task Force).
+<emph>RFC 2141: URN Syntax</emph>,
+ed. R. Moats.
+1997.
+</bibl>
+
+<bibl id='ISO8879' key='ISO 8879'>ISO
+(International Organization for Standardization).
+<emph>ISO 8879:1986(E). Information processing &mdash; Text and Office
+Systems &mdash; Standard Generalized Markup Language (SGML).</emph> First
+edition &mdash; 1986-10-15. [Geneva]: International Organization for
+Standardization, 1986.
+</bibl>
+
+
+<bibl id='ISO10744' key='ISO/IEC 10744'>ISO
+(International Organization for Standardization).
+<emph>ISO/IEC 10744-1992 (E). Information technology &mdash;
+Hypermedia/Time-based Structuring Language (HyTime).
+</emph>
+[Geneva]: International Organization for
+Standardization, 1992.
+<emph>Extended Facilities Annexe.</emph>
+[Geneva]: International Organization for
+Standardization, 1996.
+</bibl>
+
+
+
+</blist>
+</div2>
+</div1>
+<div1 id='CharClasses'>
+<head>Character Classes</head>
+<p>Following the characteristics defined in the Unicode standard,
+characters are classed as base characters (among others, these
+contain the alphabetic characters of the Latin alphabet, without
+diacritics), ideographic characters, and combining characters (among
+others, this class contains most diacritics); these classes combine
+to form the class of letters. Digits and extenders are
+also distinguished.
+<scrap lang="ebnf" id="CHARACTERS">
+<head>Characters</head>
+<prodgroup pcw3="3" pcw4="15">
+<prod id="NT-Letter"><lhs>Letter</lhs>
+<rhs><nt def="NT-BaseChar">BaseChar</nt>
+| <nt def="NT-Ideographic">Ideographic</nt></rhs> </prod>
+<prod id='NT-BaseChar'><lhs>BaseChar</lhs>
+<rhs>[#x0041-#x005A]
+|&nbsp;[#x0061-#x007A]
+|&nbsp;[#x00C0-#x00D6]
+|&nbsp;[#x00D8-#x00F6]
+|&nbsp;[#x00F8-#x00FF]
+|&nbsp;[#x0100-#x0131]
+|&nbsp;[#x0134-#x013E]
+|&nbsp;[#x0141-#x0148]
+|&nbsp;[#x014A-#x017E]
+|&nbsp;[#x0180-#x01C3]
+|&nbsp;[#x01CD-#x01F0]
+|&nbsp;[#x01F4-#x01F5]
+|&nbsp;[#x01FA-#x0217]
+|&nbsp;[#x0250-#x02A8]
+|&nbsp;[#x02BB-#x02C1]
+|&nbsp;#x0386
+|&nbsp;[#x0388-#x038A]
+|&nbsp;#x038C
+|&nbsp;[#x038E-#x03A1]
+|&nbsp;[#x03A3-#x03CE]
+|&nbsp;[#x03D0-#x03D6]
+|&nbsp;#x03DA
+|&nbsp;#x03DC
+|&nbsp;#x03DE
+|&nbsp;#x03E0
+|&nbsp;[#x03E2-#x03F3]
+|&nbsp;[#x0401-#x040C]
+|&nbsp;[#x040E-#x044F]
+|&nbsp;[#x0451-#x045C]
+|&nbsp;[#x045E-#x0481]
+|&nbsp;[#x0490-#x04C4]
+|&nbsp;[#x04C7-#x04C8]
+|&nbsp;[#x04CB-#x04CC]
+|&nbsp;[#x04D0-#x04EB]
+|&nbsp;[#x04EE-#x04F5]
+|&nbsp;[#x04F8-#x04F9]
+|&nbsp;[#x0531-#x0556]
+|&nbsp;#x0559
+|&nbsp;[#x0561-#x0586]
+|&nbsp;[#x05D0-#x05EA]
+|&nbsp;[#x05F0-#x05F2]
+|&nbsp;[#x0621-#x063A]
+|&nbsp;[#x0641-#x064A]
+|&nbsp;[#x0671-#x06B7]
+|&nbsp;[#x06BA-#x06BE]
+|&nbsp;[#x06C0-#x06CE]
+|&nbsp;[#x06D0-#x06D3]
+|&nbsp;#x06D5
+|&nbsp;[#x06E5-#x06E6]
+|&nbsp;[#x0905-#x0939]
+|&nbsp;#x093D
+|&nbsp;[#x0958-#x0961]
+|&nbsp;[#x0985-#x098C]
+|&nbsp;[#x098F-#x0990]
+|&nbsp;[#x0993-#x09A8]
+|&nbsp;[#x09AA-#x09B0]
+|&nbsp;#x09B2
+|&nbsp;[#x09B6-#x09B9]
+|&nbsp;[#x09DC-#x09DD]
+|&nbsp;[#x09DF-#x09E1]
+|&nbsp;[#x09F0-#x09F1]
+|&nbsp;[#x0A05-#x0A0A]
+|&nbsp;[#x0A0F-#x0A10]
+|&nbsp;[#x0A13-#x0A28]
+|&nbsp;[#x0A2A-#x0A30]
+|&nbsp;[#x0A32-#x0A33]
+|&nbsp;[#x0A35-#x0A36]
+|&nbsp;[#x0A38-#x0A39]
+|&nbsp;[#x0A59-#x0A5C]
+|&nbsp;#x0A5E
+|&nbsp;[#x0A72-#x0A74]
+|&nbsp;[#x0A85-#x0A8B]
+|&nbsp;#x0A8D
+|&nbsp;[#x0A8F-#x0A91]
+|&nbsp;[#x0A93-#x0AA8]
+|&nbsp;[#x0AAA-#x0AB0]
+|&nbsp;[#x0AB2-#x0AB3]
+|&nbsp;[#x0AB5-#x0AB9]
+|&nbsp;#x0ABD
+|&nbsp;#x0AE0
+|&nbsp;[#x0B05-#x0B0C]
+|&nbsp;[#x0B0F-#x0B10]
+|&nbsp;[#x0B13-#x0B28]
+|&nbsp;[#x0B2A-#x0B30]
+|&nbsp;[#x0B32-#x0B33]
+|&nbsp;[#x0B36-#x0B39]
+|&nbsp;#x0B3D
+|&nbsp;[#x0B5C-#x0B5D]
+|&nbsp;[#x0B5F-#x0B61]
+|&nbsp;[#x0B85-#x0B8A]
+|&nbsp;[#x0B8E-#x0B90]
+|&nbsp;[#x0B92-#x0B95]
+|&nbsp;[#x0B99-#x0B9A]
+|&nbsp;#x0B9C
+|&nbsp;[#x0B9E-#x0B9F]
+|&nbsp;[#x0BA3-#x0BA4]
+|&nbsp;[#x0BA8-#x0BAA]
+|&nbsp;[#x0BAE-#x0BB5]
+|&nbsp;[#x0BB7-#x0BB9]
+|&nbsp;[#x0C05-#x0C0C]
+|&nbsp;[#x0C0E-#x0C10]
+|&nbsp;[#x0C12-#x0C28]
+|&nbsp;[#x0C2A-#x0C33]
+|&nbsp;[#x0C35-#x0C39]
+|&nbsp;[#x0C60-#x0C61]
+|&nbsp;[#x0C85-#x0C8C]
+|&nbsp;[#x0C8E-#x0C90]
+|&nbsp;[#x0C92-#x0CA8]
+|&nbsp;[#x0CAA-#x0CB3]
+|&nbsp;[#x0CB5-#x0CB9]
+|&nbsp;#x0CDE
+|&nbsp;[#x0CE0-#x0CE1]
+|&nbsp;[#x0D05-#x0D0C]
+|&nbsp;[#x0D0E-#x0D10]
+|&nbsp;[#x0D12-#x0D28]
+|&nbsp;[#x0D2A-#x0D39]
+|&nbsp;[#x0D60-#x0D61]
+|&nbsp;[#x0E01-#x0E2E]
+|&nbsp;#x0E30
+|&nbsp;[#x0E32-#x0E33]
+|&nbsp;[#x0E40-#x0E45]
+|&nbsp;[#x0E81-#x0E82]
+|&nbsp;#x0E84
+|&nbsp;[#x0E87-#x0E88]
+|&nbsp;#x0E8A
+|&nbsp;#x0E8D
+|&nbsp;[#x0E94-#x0E97]
+|&nbsp;[#x0E99-#x0E9F]
+|&nbsp;[#x0EA1-#x0EA3]
+|&nbsp;#x0EA5
+|&nbsp;#x0EA7
+|&nbsp;[#x0EAA-#x0EAB]
+|&nbsp;[#x0EAD-#x0EAE]
+|&nbsp;#x0EB0
+|&nbsp;[#x0EB2-#x0EB3]
+|&nbsp;#x0EBD
+|&nbsp;[#x0EC0-#x0EC4]
+|&nbsp;[#x0F40-#x0F47]
+|&nbsp;[#x0F49-#x0F69]
+|&nbsp;[#x10A0-#x10C5]
+|&nbsp;[#x10D0-#x10F6]
+|&nbsp;#x1100
+|&nbsp;[#x1102-#x1103]
+|&nbsp;[#x1105-#x1107]
+|&nbsp;#x1109
+|&nbsp;[#x110B-#x110C]
+|&nbsp;[#x110E-#x1112]
+|&nbsp;#x113C
+|&nbsp;#x113E
+|&nbsp;#x1140
+|&nbsp;#x114C
+|&nbsp;#x114E
+|&nbsp;#x1150
+|&nbsp;[#x1154-#x1155]
+|&nbsp;#x1159
+|&nbsp;[#x115F-#x1161]
+|&nbsp;#x1163
+|&nbsp;#x1165
+|&nbsp;#x1167
+|&nbsp;#x1169
+|&nbsp;[#x116D-#x116E]
+|&nbsp;[#x1172-#x1173]
+|&nbsp;#x1175
+|&nbsp;#x119E
+|&nbsp;#x11A8
+|&nbsp;#x11AB
+|&nbsp;[#x11AE-#x11AF]
+|&nbsp;[#x11B7-#x11B8]
+|&nbsp;#x11BA
+|&nbsp;[#x11BC-#x11C2]
+|&nbsp;#x11EB
+|&nbsp;#x11F0
+|&nbsp;#x11F9
+|&nbsp;[#x1E00-#x1E9B]
+|&nbsp;[#x1EA0-#x1EF9]
+|&nbsp;[#x1F00-#x1F15]
+|&nbsp;[#x1F18-#x1F1D]
+|&nbsp;[#x1F20-#x1F45]
+|&nbsp;[#x1F48-#x1F4D]
+|&nbsp;[#x1F50-#x1F57]
+|&nbsp;#x1F59
+|&nbsp;#x1F5B
+|&nbsp;#x1F5D
+|&nbsp;[#x1F5F-#x1F7D]
+|&nbsp;[#x1F80-#x1FB4]
+|&nbsp;[#x1FB6-#x1FBC]
+|&nbsp;#x1FBE
+|&nbsp;[#x1FC2-#x1FC4]
+|&nbsp;[#x1FC6-#x1FCC]
+|&nbsp;[#x1FD0-#x1FD3]
+|&nbsp;[#x1FD6-#x1FDB]
+|&nbsp;[#x1FE0-#x1FEC]
+|&nbsp;[#x1FF2-#x1FF4]
+|&nbsp;[#x1FF6-#x1FFC]
+|&nbsp;#x2126
+|&nbsp;[#x212A-#x212B]
+|&nbsp;#x212E
+|&nbsp;[#x2180-#x2182]
+|&nbsp;[#x3041-#x3094]
+|&nbsp;[#x30A1-#x30FA]
+|&nbsp;[#x3105-#x312C]
+|&nbsp;[#xAC00-#xD7A3]
+</rhs></prod>
+<prod id='NT-Ideographic'><lhs>Ideographic</lhs>
+<rhs>[#x4E00-#x9FA5]
+|&nbsp;#x3007
+|&nbsp;[#x3021-#x3029]
+</rhs></prod>
+<prod id='NT-CombiningChar'><lhs>CombiningChar</lhs>
+<rhs>[#x0300-#x0345]
+|&nbsp;[#x0360-#x0361]
+|&nbsp;[#x0483-#x0486]
+|&nbsp;[#x0591-#x05A1]
+|&nbsp;[#x05A3-#x05B9]
+|&nbsp;[#x05BB-#x05BD]
+|&nbsp;#x05BF
+|&nbsp;[#x05C1-#x05C2]
+|&nbsp;#x05C4
+|&nbsp;[#x064B-#x0652]
+|&nbsp;#x0670
+|&nbsp;[#x06D6-#x06DC]
+|&nbsp;[#x06DD-#x06DF]
+|&nbsp;[#x06E0-#x06E4]
+|&nbsp;[#x06E7-#x06E8]
+|&nbsp;[#x06EA-#x06ED]
+|&nbsp;[#x0901-#x0903]
+|&nbsp;#x093C
+|&nbsp;[#x093E-#x094C]
+|&nbsp;#x094D
+|&nbsp;[#x0951-#x0954]
+|&nbsp;[#x0962-#x0963]
+|&nbsp;[#x0981-#x0983]
+|&nbsp;#x09BC
+|&nbsp;#x09BE
+|&nbsp;#x09BF
+|&nbsp;[#x09C0-#x09C4]
+|&nbsp;[#x09C7-#x09C8]
+|&nbsp;[#x09CB-#x09CD]
+|&nbsp;#x09D7
+|&nbsp;[#x09E2-#x09E3]
+|&nbsp;#x0A02
+|&nbsp;#x0A3C
+|&nbsp;#x0A3E
+|&nbsp;#x0A3F
+|&nbsp;[#x0A40-#x0A42]
+|&nbsp;[#x0A47-#x0A48]
+|&nbsp;[#x0A4B-#x0A4D]
+|&nbsp;[#x0A70-#x0A71]
+|&nbsp;[#x0A81-#x0A83]
+|&nbsp;#x0ABC
+|&nbsp;[#x0ABE-#x0AC5]
+|&nbsp;[#x0AC7-#x0AC9]
+|&nbsp;[#x0ACB-#x0ACD]
+|&nbsp;[#x0B01-#x0B03]
+|&nbsp;#x0B3C
+|&nbsp;[#x0B3E-#x0B43]
+|&nbsp;[#x0B47-#x0B48]
+|&nbsp;[#x0B4B-#x0B4D]
+|&nbsp;[#x0B56-#x0B57]
+|&nbsp;[#x0B82-#x0B83]
+|&nbsp;[#x0BBE-#x0BC2]
+|&nbsp;[#x0BC6-#x0BC8]
+|&nbsp;[#x0BCA-#x0BCD]
+|&nbsp;#x0BD7
+|&nbsp;[#x0C01-#x0C03]
+|&nbsp;[#x0C3E-#x0C44]
+|&nbsp;[#x0C46-#x0C48]
+|&nbsp;[#x0C4A-#x0C4D]
+|&nbsp;[#x0C55-#x0C56]
+|&nbsp;[#x0C82-#x0C83]
+|&nbsp;[#x0CBE-#x0CC4]
+|&nbsp;[#x0CC6-#x0CC8]
+|&nbsp;[#x0CCA-#x0CCD]
+|&nbsp;[#x0CD5-#x0CD6]
+|&nbsp;[#x0D02-#x0D03]
+|&nbsp;[#x0D3E-#x0D43]
+|&nbsp;[#x0D46-#x0D48]
+|&nbsp;[#x0D4A-#x0D4D]
+|&nbsp;#x0D57
+|&nbsp;#x0E31
+|&nbsp;[#x0E34-#x0E3A]
+|&nbsp;[#x0E47-#x0E4E]
+|&nbsp;#x0EB1
+|&nbsp;[#x0EB4-#x0EB9]
+|&nbsp;[#x0EBB-#x0EBC]
+|&nbsp;[#x0EC8-#x0ECD]
+|&nbsp;[#x0F18-#x0F19]
+|&nbsp;#x0F35
+|&nbsp;#x0F37
+|&nbsp;#x0F39
+|&nbsp;#x0F3E
+|&nbsp;#x0F3F
+|&nbsp;[#x0F71-#x0F84]
+|&nbsp;[#x0F86-#x0F8B]
+|&nbsp;[#x0F90-#x0F95]
+|&nbsp;#x0F97
+|&nbsp;[#x0F99-#x0FAD]
+|&nbsp;[#x0FB1-#x0FB7]
+|&nbsp;#x0FB9
+|&nbsp;[#x20D0-#x20DC]
+|&nbsp;#x20E1
+|&nbsp;[#x302A-#x302F]
+|&nbsp;#x3099
+|&nbsp;#x309A
+</rhs></prod>
+<prod id='NT-Digit'><lhs>Digit</lhs>
+<rhs>[#x0030-#x0039]
+|&nbsp;[#x0660-#x0669]
+|&nbsp;[#x06F0-#x06F9]
+|&nbsp;[#x0966-#x096F]
+|&nbsp;[#x09E6-#x09EF]
+|&nbsp;[#x0A66-#x0A6F]
+|&nbsp;[#x0AE6-#x0AEF]
+|&nbsp;[#x0B66-#x0B6F]
+|&nbsp;[#x0BE7-#x0BEF]
+|&nbsp;[#x0C66-#x0C6F]
+|&nbsp;[#x0CE6-#x0CEF]
+|&nbsp;[#x0D66-#x0D6F]
+|&nbsp;[#x0E50-#x0E59]
+|&nbsp;[#x0ED0-#x0ED9]
+|&nbsp;[#x0F20-#x0F29]
+</rhs></prod>
+<prod id='NT-Extender'><lhs>Extender</lhs>
+<rhs>#x00B7
+|&nbsp;#x02D0
+|&nbsp;#x02D1
+|&nbsp;#x0387
+|&nbsp;#x0640
+|&nbsp;#x0E46
+|&nbsp;#x0EC6
+|&nbsp;#x3005
+|&nbsp;[#x3031-#x3035]
+|&nbsp;[#x309D-#x309E]
+|&nbsp;[#x30FC-#x30FE]
+</rhs></prod>
+
+</prodgroup>
+</scrap>
+</p>
+<p>The character classes defined here can be derived from the
+Unicode character database as follows:
+<ulist>
+<item>
+<p>Name start characters must have one of the categories Ll, Lu,
+Lo, Lt, Nl.</p>
+</item>
+<item>
+<p>Name characters other than Name-start characters
+must have one of the categories Mc, Me, Mn, Lm, or Nd.</p>
+</item>
+<item>
+<p>Characters in the compatibility area (i.e. with character code
+greater than #xF900 and less than #xFFFE) are not allowed in XML
+names.</p>
+</item>
+<item>
+<p>Characters which have a font or compatibility decomposition (i.e. those
+with a "compatibility formatting tag" in field 5 of the database --
+marked by field 5 beginning with a "&lt;") are not allowed.</p>
+</item>
+<item>
+<p>The following characters are treated as name-start characters
+rather than name characters, because the property file classifies
+them as Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6.</p>
+</item>
+<item>
+<p>Characters #x20DD-#x20E0 are excluded (in accordance with
+Unicode, section 5.14).</p>
+</item>
+<item>
+<p>Character #x00B7 is classified as an extender, because the
+property list so identifies it.</p>
+</item>
+<item>
+<p>Character #x0387 is added as a name character, because #x00B7
+is its canonical equivalent.</p>
+</item>
+<item>
+<p>Characters ':' and '_' are allowed as name-start characters.</p>
+</item>
+<item>
+<p>Characters '-' and '.' are allowed as name characters.</p>
+</item>
+</ulist>
+</p>
+</div1>
+<inform-div1 id="sec-xml-and-sgml">
+<head>XML and SGML</head>
+
+<p>XML is designed to be a subset of SGML, in that every
+<termref def="dt-valid">valid</termref> XML document should also be a
+conformant SGML document.
+For a detailed comparison of the additional restrictions that XML places on
+documents beyond those of SGML, see <bibref ref='Clark'/>.
+</p>
+</inform-div1>
+<inform-div1 id="sec-entexpand">
+<head>Expansion of Entity and Character References</head>
+<p>This appendix contains some examples illustrating the
+sequence of entity- and character-reference recognition and
+expansion, as specified in <specref ref='entproc'/>.</p>
+<p>
+If the DTD contains the declaration
+<eg><![CDATA[<!ENTITY example "<p>An ampersand (&#38;#38;) may be escaped
+numerically (&#38;#38;#38;) or with a general entity
+(&amp;amp;).</p>" >
+]]></eg>
+then the XML processor will recognize the character references
+when it parses the entity declaration, and resolve them before
+storing the following string as the
+value of the entity "<code>example</code>":
+<eg><![CDATA[<p>An ampersand (&#38;) may be escaped
+numerically (&#38;#38;) or with a general entity
+(&amp;amp;).</p>
+]]></eg>
+A reference in the document to "<code>&amp;example;</code>"
+will cause the text to be reparsed, at which time the
+start- and end-tags of the "<code>p</code>" element will be recognized
+and the three references will be recognized and expanded,
+resulting in a "<code>p</code>" element with the following content
+(all data, no delimiters or markup):
+<eg><![CDATA[An ampersand (&) may be escaped
+numerically (&#38;) or with a general entity
+(&amp;).
+]]></eg>
+</p>
+<p>A more complex example will illustrate the rules and their
+effects fully. In the following example, the line numbers are
+solely for reference.
+<eg><![CDATA[1 <?xml version='1.0'?>
+2 <!DOCTYPE test [
+3 <!ELEMENT test (#PCDATA) >
+4 <!ENTITY % xx '&#37;zz;'>
+5 <!ENTITY % zz '&#60;!ENTITY tricky "error-prone" >' >
+6 %xx;
+7 ]>
+8 <test>This sample shows a &tricky; method.</test>
+]]></eg>
+This produces the following:
+<ulist spacing="compact">
+<item><p>in line 4, the reference to character 37 is expanded immediately,
+and the parameter entity "<code>xx</code>" is stored in the symbol
+table with the value "<code>%zz;</code>". Since the replacement text
+is not rescanned, the reference to parameter entity "<code>zz</code>"
+is not recognized. (And it would be an error if it were, since
+"<code>zz</code>" is not yet declared.)</p></item>
+<item><p>in line 5, the character reference "<code>&amp;#60;</code>" is
+expanded immediately and the parameter entity "<code>zz</code>" is
+stored with the replacement text
+"<code>&lt;!ENTITY tricky "error-prone" ></code>",
+which is a well-formed entity declaration.</p></item>
+<item><p>in line 6, the reference to "<code>xx</code>" is recognized,
+and the replacement text of "<code>xx</code>" (namely
+"<code>%zz;</code>") is parsed. The reference to "<code>zz</code>"
+is recognized in its turn, and its replacement text
+("<code>&lt;!ENTITY tricky "error-prone" ></code>") is parsed.
+The general entity "<code>tricky</code>" has now been
+declared, with the replacement text "<code>error-prone</code>".</p></item>
+<item><p>
+in line 8, the reference to the general entity "<code>tricky</code>" is
+recognized, and it is expanded, so the full content of the
+"<code>test</code>" element is the self-describing (and ungrammatical) string
+<emph>This sample shows a error-prone method.</emph>
+</p></item>
+</ulist>
+</p>
+</inform-div1>
+<inform-div1 id="determinism">
+<head>Deterministic Content Models</head>
+<p><termref def='dt-compat'>For compatibility</termref>, it is
+required
+that content models in element type declarations be deterministic.
+</p>
+<!-- FINAL EDIT: WebSGML allows ambiguity? -->
+<p>SGML
+requires deterministic content models (it calls them
+"unambiguous"); XML processors built using SGML systems may
+flag non-deterministic content models as errors.</p>
+<p>For example, the content model <code>((b, c) | (b, d))</code> is
+non-deterministic, because given an initial <code>b</code> the parser
+cannot know which <code>b</code> in the model is being matched without
+looking ahead to see which element follows the <code>b</code>.
+In this case, the two references to
+<code>b</code> can be collapsed
+into a single reference, making the model read
+<code>(b, (c | d))</code>. An initial <code>b</code> now clearly
+matches only a single name in the content model. The parser doesn't
+need to look ahead to see what follows; either <code>c</code> or
+<code>d</code> would be accepted.</p>
+<p>More formally: a finite state automaton may be constructed from the
+content model using the standard algorithms, e.g. algorithm 3.5
+in section 3.9
+of Aho, Sethi, and Ullman <bibref ref='Aho'/>.
+In many such algorithms, a follow set is constructed for each
+position in the regular expression (i.e., each leaf
+node in the
+syntax tree for the regular expression);
+if any position has a follow set in which
+more than one following position is
+labeled with the same element type name,
+then the content model is in error
+and may be reported as an error.
+</p>
+<p>Algorithms exist which allow many but not all non-deterministic
+content models to be reduced automatically to equivalent deterministic
+models; see Brüggemann-Klein 1991 <bibref ref='ABK'/>.</p>
+</inform-div1>
+<inform-div1 id="sec-guessing">
+<head>Autodetection of Character Encodings</head>
+<p>The XML encoding declaration functions as an internal label on each
+entity, indicating which character encoding is in use. Before an XML
+processor can read the internal label, however, it apparently has to
+know what character encoding is in use&mdash;which is what the internal label
+is trying to indicate. In the general case, this is a hopeless
+situation. It is not entirely hopeless in XML, however, because XML
+limits the general case in two ways: each implementation is assumed
+to support only a finite set of character encodings, and the XML
+encoding declaration is restricted in position and content in order to
+make it feasible to autodetect the character encoding in use in each
+entity in normal cases. Also, in many cases other sources of information
+are available in addition to the XML data stream itself.
+Two cases may be distinguished,
+depending on whether the XML entity is presented to the
+processor without, or with, any accompanying
+(external) information. We consider the first case first.
+</p>
+<p>
+Because each XML entity not in UTF-8 or UTF-16 format <emph>must</emph>
+begin with an XML encoding declaration, in which the first characters
+must be '<code>&lt;?xml</code>', any conforming processor can detect,
+after two to four octets of input, which of the following cases apply.
+In reading this list, it may help to know that in UCS-4, '&lt;' is
+"<code>#x0000003C</code>" and '?' is "<code>#x0000003F</code>", and the Byte
+Order Mark required of UTF-16 data streams is "<code>#xFEFF</code>".</p>
+<p>
+<ulist>
+<item>
+<p><code>00 00 00 3C</code>: UCS-4, big-endian machine (1234 order)</p>
+</item>
+<item>
+<p><code>3C 00 00 00</code>: UCS-4, little-endian machine (4321 order)</p>
+</item>
+<item>
+<p><code>00 00 3C 00</code>: UCS-4, unusual octet order (2143)</p>
+</item>
+<item>
+<p><code>00 3C 00 00</code>: UCS-4, unusual octet order (3412)</p>
+</item>
+<item>
+<p><code>FE FF</code>: UTF-16, big-endian</p>
+</item>
+<item>
+<p><code>FF FE</code>: UTF-16, little-endian</p>
+</item>
+<item>
+<p><code>00 3C 00 3F</code>: UTF-16, big-endian, no Byte Order Mark
+(and thus, strictly speaking, in error)</p>
+</item>
+<item>
+<p><code>3C 00 3F 00</code>: UTF-16, little-endian, no Byte Order Mark
+(and thus, strictly speaking, in error)</p>
+</item>
+<item>
+<p><code>3C 3F 78 6D</code>: UTF-8, ISO 646, ASCII, some part of ISO 8859,
+Shift-JIS, EUC, or any other 7-bit, 8-bit, or mixed-width encoding
+which ensures that the characters of ASCII have their normal positions,
+width,
+and values; the actual encoding declaration must be read to
+detect which of these applies, but since all of these encodings
+use the same bit patterns for the ASCII characters, the encoding
+declaration itself may be read reliably
+</p>
+</item>
+<item>
+<p><code>4C 6F A7 94</code>: EBCDIC (in some flavor; the full
+encoding declaration must be read to tell which code page is in
+use)</p>
+</item>
+<item>
+<p>other: UTF-8 without an encoding declaration, or else
+the data stream is corrupt, fragmentary, or enclosed in
+a wrapper of some kind</p>
+</item>
+</ulist>
+</p>
+<p>
+This level of autodetection is enough to read the XML encoding
+declaration and parse the character-encoding identifier, which is
+still necessary to distinguish the individual members of each family
+of encodings (e.g. to tell UTF-8 from 8859, and the parts of 8859
+from each other, or to distinguish the specific EBCDIC code page in
+use, and so on).
+</p>
+<p>
+Because the contents of the encoding declaration are restricted to
+ASCII characters, a processor can reliably read the entire encoding
+declaration as soon as it has detected which family of encodings is in
+use. Since in practice, all widely used character encodings fall into
+one of the categories above, the XML encoding declaration allows
+reasonably reliable in-band labeling of character encodings, even when
+external sources of information at the operating-system or
+transport-protocol level are unreliable.
+</p>
+<p>
+Once the processor has detected the character encoding in use, it can
+act appropriately, whether by invoking a separate input routine for
+each case, or by calling the proper conversion function on each
+character of input.
+</p>
+<p>
+Like any self-labeling system, the XML encoding declaration will not
+work if any software changes the entity's character set or encoding
+without updating the encoding declaration. Implementors of
+character-encoding routines should be careful to ensure the accuracy
+of the internal and external information used to label the entity.
+</p>
+<p>The second possible case occurs when the XML entity is accompanied
+by encoding information, as in some file systems and some network
+protocols.
+When multiple sources of information are available,
+
+their relative
+priority and the preferred method of handling conflict should be
+specified as part of the higher-level protocol used to deliver XML.
+Rules for the relative priority of the internal label and the
+MIME-type label in an external header, for example, should be part of the
+RFC document defining the text/xml and application/xml MIME types. In
+the interests of interoperability, however, the following rules
+are recommended.
+<ulist>
+<item><p>If an XML entity is in a file, the Byte-Order Mark
+and encoding-declaration PI are used (if present) to determine the
+character encoding. All other heuristics and sources of information
+are solely for error recovery.
+</p></item>
+<item><p>If an XML entity is delivered with a
+MIME type of text/xml, then the <code>charset</code> parameter
+on the MIME type determines the
+character encoding method; all other heuristics and sources of
+information are solely for error recovery.
+</p></item>
+<item><p>If an XML entity is delivered
+with a
+MIME type of application/xml, then the Byte-Order Mark and
+encoding-declaration PI are used (if present) to determine the
+character encoding. All other heuristics and sources of
+information are solely for error recovery.
+</p></item>
+</ulist>
+These rules apply only in the absence of protocol-level documentation;
+in particular, when the MIME types text/xml and application/xml are
+defined, the recommendations of the relevant RFC will supersede
+these rules.
+</p>
+
+</inform-div1>
+
+<inform-div1 id="sec-xml-wg">
+<head>W3C XML Working Group</head>
+
+<p>This specification was prepared and approved for publication by the
+W3C XML Working Group (WG). WG approval of this specification does
+not necessarily imply that all WG members voted for its approval.
+The current and former members of the XML WG are:</p>
+
+<orglist>
+<member><name>Jon Bosak, Sun</name><role>Chair</role></member>
+<member><name>James Clark</name><role>Technical Lead</role></member>
+<member><name>Tim Bray, Textuality and Netscape</name><role>XML Co-editor</role></member>
+<member><name>Jean Paoli, Microsoft</name><role>XML Co-editor</role></member>
+<member><name>C. M. Sperberg-McQueen, U. of Ill.</name><role>XML
+Co-editor</role></member>
+<member><name>Dan Connolly, W3C</name><role>W3C Liaison</role></member>
+<member><name>Paula Angerstein, Texcel</name></member>
+<member><name>Steve DeRose, INSO</name></member>
+<member><name>Dave Hollander, HP</name></member>
+<member><name>Eliot Kimber, ISOGEN</name></member>
+<member><name>Eve Maler, ArborText</name></member>
+<member><name>Tom Magliery, NCSA</name></member>
+<member><name>Murray Maloney, Muzmo and Grif</name></member>
+<member><name>Makoto Murata, Fuji Xerox Information Systems</name></member>
+<member><name>Joel Nava, Adobe</name></member>
+<member><name>Conleth O'Connell, Vignette</name></member>
+<member><name>Peter Sharpe, SoftQuad</name></member>
+<member><name>John Tigue, DataChannel</name></member>
+</orglist>
+
+</inform-div1>
+</back>
+</spec>
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-default-dtd-file:"~/sgml/spec.ced"
+sgml-omittag:t
+sgml-shorttag:t
+End:
+-->
diff --git a/samples/canonical b/samples/canonical
new file mode 100755
index 0000000..9337cbe
--- /dev/null
+++ b/samples/canonical
@@ -0,0 +1,124 @@
+#!/usr/local/bin/perl -w
+#
+# Copyright 1999 Clark Cooper <coopercc@netheaven.com>
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+# $Revision: 1.1.1.1 $
+#
+# $Date: 2003/07/27 11:07:11 $
+#
+# This program take an XML document (either on standard input or
+# from a filename supplied as an argument) and generates corresponding
+# canonical XML document on the standard output. The definition of
+# "Canonical XML" that I'm using is taken from the working draft
+# published by W3C on 19-Jan-2000:
+#
+# http://www.w3.org/TR/2000/WD-xml-c14n-20000119.html
+#
+# The latest version of this document is at:
+#
+# http://www.w3.org/TR/xml-c14n
+#
+
+use XML::Parser;
+
+my $indoctype = 0;
+my $inroot = 0;
+my $p = new XML::Parser(ErrorContext => 2,
+ Namespaces => 1,
+ ParseParamEnt => 1,
+ Handlers => {Start => \&sthndl,
+ End => \&endhndl,
+ Char => \&chrhndl,
+ Proc => \&proc,
+ Doctype => sub {$indoctype = 1},
+ DoctypeFin => sub {$indoctype = 0}
+ }
+ );
+
+my $file = shift;
+if (defined $file) {
+ $p->parsefile($file);
+}
+else {
+ $p->parse(*STDIN);
+}
+
+################
+## End main
+################
+
+sub sthndl {
+ my $xp = shift;
+ my $el = shift;
+
+ $inroot = 1 unless $inroot;
+ my $ns_index = 1;
+
+ my $elns = $xp->namespace($el);
+ if (defined $elns) {
+ my $pfx = 'n' . $ns_index++;
+ print "<$pfx:$el xmlns:$pfx=\"$elns\"";
+ }
+ else {
+ print "<$el";
+ }
+
+ if (@_) {
+ for (my $i = 0; $i < @_; $i += 2) {
+ my $nm = $_[$i];
+ my $ns = $xp->namespace($nm);
+ $_[$i] = defined($ns) ? "$ns\01$nm" : "\01$nm";
+ }
+
+ my %atts = @_;
+ my @ids = sort keys %atts;
+ foreach my $id (@ids) {
+ my ($ns, $nm) = split(/\01/, $id);
+ my $val = $xp->xml_escape($atts{$id}, '"', "\x9", "\xA", "\xD");
+ if (length($ns)) {
+ my $pfx = 'n' . $ns_index++;
+ print " $pfx:$nm=\"$val\" xmlns:$pfx=\"$ns\"";
+ }
+ else {
+ print " $nm=\"$val\"";
+ }
+ }
+ }
+
+ print '>';
+} # End sthndl
+
+sub endhndl {
+ my ($xp, $el) = @_;
+
+ my $nm = $xp->namespace($el) ? "n1:$el" : $el;
+ print "</$nm>";
+ if ($xp->depth == 0) {
+ $inroot = 0;
+ print "\n";
+ }
+} # End endhndl
+
+sub chrhndl {
+ my ($xp, $data) = @_;
+
+ print $xp->xml_escape($data, '>', "\xD");
+} # End chrhndl
+
+sub proc {
+ my ($xp, $target, $data) = @_;
+
+ unless ($indoctype) {
+ print "<?$target $data?>";
+ print "\n" unless $inroot;
+ }
+}
+
+# Tell emacs that this is really a perl script
+#Local Variables:
+#Mode: perl
+#End:
diff --git a/samples/canontst.xml b/samples/canontst.xml
new file mode 100644
index 0000000..e01ef77
--- /dev/null
+++ b/samples/canontst.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<?pre_doctype
+ hello ?>
+<!DOCTYPE ctest SYSTEM "ctest.dtd"
+ [
+ <?in_doctype there ?>
+ ]
+>
+<?pre_r1
+ testing?><?pre_r2 one two?>
+<ctest xmlns:x="urn:1" xmlns:y="urn:2" version='0.5'>
+ <x:e a="a"/>
+ <foo xmlns='urn:3' z="hello" y:b="there" k="world">
+ <bar/>
+ Here is a PI: <?inside
+ more pi testing ?>. Like it?
+ </foo>
+ <la y:b='b' a='tab->( ) qtab->(&#x9;) junk '/>
+</ctest>
+<?post_root last stuff?> \ No newline at end of file
diff --git a/samples/ctest.dtd b/samples/ctest.dtd
new file mode 100644
index 0000000..4882cf2
--- /dev/null
+++ b/samples/ctest.dtd
@@ -0,0 +1,2 @@
+<!ATTLIST ctest magic CDATA "xyzzy">
+<!ATTLIST la a NMTOKENS #IMPLIED>
diff --git a/samples/xmlcomments b/samples/xmlcomments
new file mode 100755
index 0000000..2a46585
--- /dev/null
+++ b/samples/xmlcomments
@@ -0,0 +1,44 @@
+#!/usr/local/bin/perl -w
+#
+# $Revision: 1.1.1.1 $
+#
+# $Date: 2003/07/27 11:07:11 $
+
+use XML::Parser;
+
+my $file = shift;
+
+die "Can't find file \"$file\""
+ unless -f $file;
+
+my $count = 0;
+
+my $parser = new XML::Parser(ErrorContext => 2,
+ ParseParamEnt => 0
+ );
+
+$parser->setHandlers(Comment => \&comments);
+
+$parser->parsefile($file);
+
+print "Found $count comments.\n";
+
+################
+## End of main
+################
+
+sub comments
+{
+ my ($p, $data) = @_;
+
+ my $line = $p->current_line;
+ $data =~ s/\n/\n\t/g;
+ print "$line:\t<!--$data-->\n";
+ $count++;
+
+} # End comments
+
+# Tell Emacs that this is really a perl script
+# Local Variables:
+# mode:perl
+# End:
diff --git a/samples/xmlfilter b/samples/xmlfilter
new file mode 100755
index 0000000..3f6dea5
--- /dev/null
+++ b/samples/xmlfilter
@@ -0,0 +1,329 @@
+#!/usr/local/bin/perl -w
+#
+# $Revision: 1.1.1.1 $
+#
+# $Date: 2003/07/27 11:07:11 $
+
+use XML::Parser;
+
+my $Usage =<<'End_of_Usage;';
+Usage is:
+ xmlfilter [-h] [-nl] [{-+}root] [{-+}el=elname] [{-+}el:elnamepat]
+ [{-+}att:attname] [{-+}att:attname:attvalpat] xmlfile
+
+Prints on standard output the result of filtering the given xmlfile
+for elements according to the switches. A '-' option will drop the
+element from the output; a '+' will keep it. The output should also
+be a well-formed XML document.
+
+ -h Print this message
+
+ -nl Emit a newline prior to every start tag.
+
+ [-+]root Drop (or keep) the root element. Defaults to keep.
+ If the root element were named "foo", then -root
+ would be equivalent to -el=foo. Note that even if
+ you're dropping the root element, it's start and
+ end tag are kept in order that the output remains
+ a well-formed XML document.
+
+ [-+]el=elname
+ Drop (or keep) elements of type elname.
+
+ [-+]el:elnamepat
+ Drop (or keep) element whose type name matches elnamepat.
+
+ [-+]att:attname
+ Drop (or keep) elements which have an attribute = attname.
+
+ [-+]att:attname:attvalpat
+ Drop (or keep) elements which have an attribute = attname
+ and for which the attribute value matches attvalpat.
+End_of_Usage;
+
+my $pass = 1;
+my $do_newline = 0;
+
+my $attcheck = 0;
+
+my %drop_el;
+my @drop_elpat;
+
+my %keep_el;
+my @keep_elpat;
+
+my %drop_att;
+my %keep_att;
+
+my $always_true = sub {1;};
+my $root_element = '';
+
+my $in_cdata = 0;
+
+# Process options
+
+while (defined($ARGV[0]) and $ARGV[0] =~ /^[-+]/)
+{
+ my $opt = shift;
+
+ if ($opt eq '-root')
+ {
+ $pass = 0;
+ }
+ elsif ($opt eq '+root')
+ {
+ $pass = 1;
+ }
+ elsif ($opt eq '-h')
+ {
+ print $Usage;
+ exit;
+ }
+ elsif ($opt eq '-nl')
+ {
+ $do_newline = 1;
+ }
+ elsif ($opt =~ /^([-+])el([:=])(\S*)/)
+ {
+ my ($disp, $kind, $pattern) = ($1, $2, $3);
+ my ($hashref, $aref);
+
+ if ($disp eq '-')
+ {
+ $hashref = \%drop_el;
+ $aref = \@drop_elpat;
+ }
+ else
+ {
+ $hashref = \%keep_el;
+ $aref = \@keep_elpat;
+ }
+
+ if ($kind eq '=')
+ {
+ $hashref->{$pattern} = 1;
+ }
+ else
+ {
+ push(@$aref, $pattern);
+ }
+ }
+ elsif ($opt =~ /^([-+])att:(\w+)(?::(\S*))?/)
+ {
+ my ($disp, $id, $pattern) = ($1, $2, $3);
+ my $ref = ($disp eq '-') ? \%drop_att : \%keep_att;
+
+ if (defined($pattern))
+ {
+ $pattern =~ s!/!\\/!g;
+ my $sub;
+ eval "\$sub = sub {\$_[0] =~ /$pattern/;};";
+
+ $ref->{$id} = $sub;
+ }
+ else
+ {
+ $ref->{$id} = $always_true;
+ }
+
+ $attcheck = 1;
+ }
+ else
+ {
+ die "Unknown option: $opt\n$Usage";
+ }
+}
+
+my $drop_el_pattern = join('|', @drop_elpat);
+my $keep_el_pattern = join('|', @keep_elpat);
+
+my $drop_sub;
+if ($drop_el_pattern)
+{
+ eval "\$drop_sub = sub {\$_[0] =~ /$drop_el_pattern/;}";
+}
+else
+{
+ $drop_sub = sub {};
+}
+
+my $keep_sub;
+if ($keep_el_pattern)
+{
+ eval "\$keep_sub = sub {\$_[0] =~ /$keep_el_pattern/;}";
+}
+else
+{
+ $keep_sub = sub {};
+}
+
+my $doc = shift;
+
+die "No file specified\n$Usage" unless defined($doc);
+
+my @togglestack = ();
+
+my $p = new XML::Parser(ErrorContext => 2,
+ Handlers => {Start => \&start_handler,
+ End => \&end_handler
+ }
+ );
+
+if ($pass) {
+ $p->setHandlers(Char => \&char_handler,
+ CdataStart => \&cdata_start,
+ CdataEnd => \&cdata_end);
+}
+
+$p->parsefile($doc);
+
+print "</$root_element>\n"
+ unless $pass;
+
+################
+## End of main
+################
+
+sub start_handler
+{
+ my $xp = shift;
+ my $el = shift;
+
+ unless ($root_element)
+ {
+ $root_element = $el;
+ print "<$el>\n"
+ unless $pass;
+ }
+
+ my ($elref, $attref, $sub);
+
+ if ($pass)
+ {
+ $elref = \%drop_el;
+ $attref = \%drop_att;
+ $sub = $drop_sub;
+ }
+ else
+ {
+ $elref = \%keep_el;
+ $attref = \%keep_att;
+ $sub = $keep_sub;
+ }
+
+ if (defined($elref->{$el})
+ or &$sub($el)
+ or check_atts($attref, @_))
+ {
+ $pass = ! $pass;
+ if ($pass) {
+ $xp->setHandlers(Char => \&char_handler,
+ CdataStart => \&cdata_start,
+ CdataEnd => \&cdata_end);
+ }
+ else {
+ $xp->setHandlers(Char => 0,
+ CdataStart => 0,
+ CdataEnd => 0);
+ }
+ push(@togglestack, $xp->depth);
+ }
+
+ if ($pass)
+ {
+ print "\n" if $do_newline;
+ print "<$el";
+ while (@_)
+ {
+ my $id = shift;
+ my $val = shift;
+
+ $val = $xp->xml_escape($val, "'");
+ print " $id='$val'";
+ }
+ print ">";
+ }
+} # End start_handler
+
+sub end_handler
+{
+ my $xp = shift;
+ my $el = shift;
+
+ if ($pass)
+ {
+ print "</$el>";
+ }
+
+ if (@togglestack and $togglestack[-1] == $xp->depth)
+ {
+ $pass = ! $pass;
+ if ($pass) {
+ $xp->setHandlers(Char => \&char_handler,
+ CdataStart => \&cdata_start,
+ CdataEnd => \&cdata_end);
+ }
+ else {
+ $xp->setHandlers(Char => 0,
+ CdataStart => 0,
+ CdataEnd => 0);
+ }
+
+ pop(@togglestack);
+ }
+
+} # End end_handler
+
+
+sub char_handler
+{
+ my ($xp, $text) = @_;
+
+ if (length($text)) {
+
+ $text = $xp->xml_escape($text, '>')
+ unless $in_cdata;
+
+ print $text;
+ }
+} # End char_handler
+
+sub cdata_start {
+ my $xp = shift;
+
+ print '<![CDATA[';
+ $in_cdata = 1;
+}
+
+sub cdata_end {
+ my $xp = shift;
+
+ print ']]>';
+ $in_cdata = 0;
+}
+
+sub check_atts
+{
+ return $attcheck unless $attcheck;
+
+ my $ref = shift;
+
+ while (@_)
+ {
+ my $id = shift;
+ my $val = shift;
+
+ if (defined($ref->{$id}))
+ {
+ my $ret = &{$ref->{$id}}($val);
+ return $ret if $ret;
+ }
+ }
+
+ return 0;
+} # End check_atts
+
+# Tell Emacs that this is really a perl script
+# Local Variables:
+# mode:perl
+# End:
diff --git a/samples/xmlstats b/samples/xmlstats
new file mode 100755
index 0000000..9af3d23
--- /dev/null
+++ b/samples/xmlstats
@@ -0,0 +1,186 @@
+#!/usr/local/bin/perl -w
+#
+# $Revision: 1.1.1.1 $
+#
+# $Date: 2003/07/27 11:07:11 $
+
+package Elinfo;
+
+sub new {
+ bless { COUNT => 0,
+ MINLEV => undef,
+ SEEN => 0,
+ CHARS => 0,
+ EMPTY => 1,
+ PTAB => {},
+ KTAB => {},
+ ATAB => {} }, shift;
+}
+
+
+package main;
+
+use English;
+use XML::Parser;
+
+my %elements;
+my $seen = 0;
+my $root;
+
+my $file = shift;
+
+my $subform =
+ ' @<<<<<<<<<<<<<<< @>>>>';
+die "Can't find file \"$file\""
+ unless -f $file;
+
+my $parser = new XML::Parser(ErrorContext => 2);
+$parser->setHandlers(Start => \&start_handler,
+ Char => \&char_handler);
+
+$parser->parsefile($file);
+
+set_minlev($root, 0);
+
+my $el;
+
+foreach $el (sort bystruct keys %elements)
+{
+ my $ref = $elements{$el};
+ print "\n================\n$el: ", $ref->{COUNT}, "\n";
+ print "Had ", $ref->{CHARS}, " bytes of character data\n"
+ if $ref->{CHARS};
+ print "Always empty\n"
+ if $ref->{EMPTY};
+
+ showtab('Parents', $ref->{PTAB}, 0);
+ showtab('Children', $ref->{KTAB}, 1);
+ showtab('Attributes', $ref->{ATAB}, 0);
+}
+
+
+################
+## End of main
+################
+
+sub start_handler
+{
+ my $p = shift;
+ my $el = shift;
+
+ my $elinf = $elements{$el};
+
+ if (not defined($elinf))
+ {
+ $elements{$el} = $elinf = new Elinfo;
+ $elinf->{SEEN} = $seen++;
+ }
+
+ $elinf->{COUNT}++;
+
+ my $partab = $elinf->{PTAB};
+
+ my $parent = $p->current_element;
+ if (defined($parent))
+ {
+ $partab->{$parent}++;
+ my $pinf = $elements{$parent};
+
+ # Increment our slot in parent's child table
+ $pinf->{KTAB}->{$el}++;
+ $pinf->{EMPTY} = 0;
+ }
+ else
+ {
+ $root = $el;
+ }
+
+ # Deal with attributes
+
+ my $atab = $elinf->{ATAB};
+
+ while (@_)
+ {
+ my $att = shift;
+
+ $atab->{$att}++;
+ shift; # Throw away value
+ }
+
+} # End start_handler
+
+sub char_handler
+{
+ my ($p, $data) = @_;
+ my $inf = $elements{$p->current_element};
+
+ $inf->{EMPTY} = 0;
+ if ($data =~ /\S/)
+ {
+ $inf->{CHARS} += length($data);
+ }
+} # End char_handler
+
+sub set_minlev
+{
+ my ($el, $lev) = @_;
+
+ my $elinfo = $elements{$el};
+ if (! defined($elinfo->{MINLEV}) or $elinfo->{MINLEV} > $lev)
+ {
+ my $newlev = $lev + 1;
+
+ $elinfo->{MINLEV} = $lev;
+ foreach (keys %{$elinfo->{KTAB}})
+ {
+ set_minlev($_, $newlev);
+ }
+ }
+} # End set_minlev
+
+sub bystruct
+{
+ my $refa = $elements{$a};
+ my $refb = $elements{$b};
+
+ $refa->{MINLEV} <=> $refb->{MINLEV}
+ or $refa->{SEEN} <=> $refb->{SEEN};
+} # End bystruct
+
+
+sub showtab
+{
+ my ($title, $table, $dosum) = @_;
+
+ my @list = sort keys %{$table};
+
+ if (@list)
+ {
+ print "\n $title:\n";
+
+ my $item;
+ my $sum = 0;
+ foreach $item (@list)
+ {
+ my $cnt = $table->{$item};
+ $sum += $cnt;
+ formline($subform, $item, $cnt);
+ print $ACCUMULATOR, "\n";
+ $ACCUMULATOR = '';
+ }
+
+ if ($dosum and @list > 1)
+ {
+ print " =====\n";
+ formline($subform, '', $sum);
+ print $ACCUMULATOR, "\n";
+ $ACCUMULATOR = '';
+ }
+ }
+
+} # End showtab
+
+# Tell Emacs that this is really a perl script
+# Local Variables:
+# mode:perl
+# End:
diff --git a/t/astress.t b/t/astress.t
new file mode 100644
index 0000000..210760b
--- /dev/null
+++ b/t/astress.t
@@ -0,0 +1,264 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+######################### We start with some black magic to print on failure.
+
+# Change 1..1 below to 1..last_test_to_print .
+# (It may become useful if the test is moved to ./t subdirectory.)
+
+BEGIN {print "1..27\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
+
+# Insert your test code below (better if it prints "ok 13"
+# (correspondingly "not ok 13") depending on the success of chunk 13
+# of the test code):
+
+# Test 2
+
+
+my $parser = new XML::Parser(ProtocolEncoding => 'ISO-8859-1');
+if ($parser)
+{
+ print "ok 2\n";
+}
+else
+{
+ print "not ok 2\n";
+ exit;
+}
+
+my @ndxstack;
+my $indexok = 1;
+
+# Need this external entity
+
+open(ZOE, '>zoe.ent');
+print ZOE "'cute'";
+close(ZOE);
+
+# XML string for tests
+
+my $xmlstring =<<"End_of_XML;";
+<!DOCTYPE foo
+ [
+ <!NOTATION bar PUBLIC "qrs">
+ <!ENTITY zinger PUBLIC "xyz" "abc" NDATA bar>
+ <!ENTITY fran SYSTEM "fran-def">
+ <!ENTITY zoe SYSTEM "zoe.ent">
+ ]>
+<foo>
+ First line in foo
+ <boom>Fran is &fran; and Zoe is &zoe;</boom>
+ <bar id="jack" stomp="jill">
+ <?line-noise *&*&^&<< ?>
+ 1st line in bar
+ <blah> 2nd line in bar </blah>
+ 3rd line in bar <!-- Isn't this a doozy -->
+ </bar>
+ <zap ref="zing" />
+ This, '\240', would be a bad character in UTF-8.
+</foo>
+End_of_XML;
+
+# Handlers
+my @tests;
+my $pos ='';
+
+sub ch
+{
+ my ($p, $str) = @_;
+ $tests[4]++;
+ $tests[5]++ if ($str =~ /2nd line/ and $p->in_element('blah'));
+ if ($p->in_element('boom'))
+ {
+ $tests[17]++ if $str =~ /pretty/;
+ $tests[18]++ if $str =~ /cute/;
+ }
+}
+
+sub st
+{
+ my ($p, $el, %atts) = @_;
+
+ $ndxstack[$p->depth] = $p->element_index;
+ $tests[6]++ if ($el eq 'bar' and $atts{stomp} eq 'jill');
+ if ($el eq 'zap' and $atts{'ref'} eq 'zing')
+ {
+ $tests[7]++;
+ $p->default_current;
+ }
+ elsif ($el eq 'bar') {
+ $tests[22]++ if $p->recognized_string eq '<bar id="jack" stomp="jill">';
+ }
+}
+
+sub eh
+{
+ my ($p, $el) = @_;
+ $indexok = 0 unless $p->element_index == $ndxstack[$p->depth];
+ if ($el eq 'zap')
+ {
+ $tests[8]++;
+ my @old = $p->setHandlers('Char', \&newch);
+ $tests[19]++ if $p->current_line == 17;
+ $tests[20]++ if $p->current_column == 20;
+ $tests[23]++ if ($old[0] eq 'Char' and $old[1] == \&ch);
+ }
+ if ($el eq 'boom')
+ {
+ $p->setHandlers('Default', \&dh);
+ }
+}
+
+sub dh
+{
+ my ($p, $str) = @_;
+ if ($str =~ /doozy/)
+ {
+ $tests[9]++;
+ $pos = $p->position_in_context(1);
+ }
+ $tests[10]++ if $str =~ /^<zap/;
+}
+
+sub pi
+{
+ my ($p, $tar, $data) = @_;
+
+ $tests[11]++ if ($tar eq 'line-noise' and $data =~ /&\^&<</);
+}
+
+sub note
+{
+ my ($p, $name, $base, $sysid, $pubid) = @_;
+
+ $tests[12]++ if ($name eq 'bar' and $pubid eq 'qrs');
+}
+
+sub unp
+{
+ my ($p, $name, $base, $sysid, $pubid, $notation) = @_;
+
+ $tests[13]++ if ($name eq 'zinger' and $pubid eq 'xyz'
+ and $sysid eq 'abc' and $notation eq 'bar');
+}
+
+sub newch
+{
+ my ($p, $str) = @_;
+
+ if ($] < 5.007001) {
+ $tests[14]++ if $str =~ /'\302\240'/;
+ }
+ else {
+ $tests[14]++ if $str =~ /'\xa0'/;
+ }
+}
+
+sub extent
+{
+ my ($p, $base, $sys, $pub) = @_;
+
+ if ($sys eq 'fran-def')
+ {
+ $tests[15]++;
+ return 'pretty';
+ }
+ elsif ($sys eq 'zoe.ent')
+ {
+ $tests[16]++;
+
+ open(FOO, $sys) or die "Couldn't open $sys";
+ return *FOO;
+ }
+}
+
+eval {
+ $parser->setHandlers('Char' => \&ch,
+ 'Start' => \&st,
+ 'End' => \&eh,
+ 'Proc' => \&pi,
+ 'Notation' => \&note,
+ 'Unparsed' => \&unp,
+ 'ExternEnt' => \&extent,
+ 'ExternEntFin' => sub {close(FOO);}
+ );
+};
+
+if ($@)
+{
+ print "not ok 3\n";
+ exit;
+}
+
+print "ok 3\n";
+
+# Test 4..20
+eval {
+ $parser->parsestring($xmlstring);
+};
+
+if ($@)
+{
+ print "Parse error:\n$@";
+}
+else
+{
+ $tests[21]++;
+}
+
+unlink('zoe.ent') if (-f 'zoe.ent');
+
+for (4 .. 23)
+{
+ print "not " unless $tests[$_];
+ print "ok $_\n";
+}
+
+$cmpstr =<< 'End_of_Cmp;';
+ <blah> 2nd line in bar </blah>
+ 3rd line in bar <!-- Isn't this a doozy -->
+===================^
+ </bar>
+End_of_Cmp;
+
+if ($cmpstr ne $pos)
+{
+ print "not ";
+}
+print "ok 24\n";
+
+print "not " unless $indexok;
+print "ok 25\n";
+
+
+# Test that memory leak through autovivifying symbol table entries is fixed.
+
+my $count = 0;
+$parser = new XML::Parser(
+ Handlers => {
+ Start => sub { $count++ }
+ }
+);
+
+$xmlstring = '<a><b>Sea</b></a>';
+
+eval {
+ $parser->parsestring($xmlstring);
+};
+
+if($count != 2) {
+ print "not ";
+}
+print "ok 26\n";
+
+if(defined(*{$xmlstring})) {
+ print "not ";
+}
+print "ok 27\n";
+
diff --git a/t/cdata.t b/t/cdata.t
new file mode 100644
index 0000000..5e1190b
--- /dev/null
+++ b/t/cdata.t
@@ -0,0 +1,40 @@
+BEGIN {print "1..2\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+my $count = 0;
+
+my $cdata_part = "<<< & > '' << &&&>&&&&;<";
+
+my $doc = "<foo> hello <![CDATA[$cdata_part]]> there</foo>";
+
+my $acc = '';
+
+sub ch {
+ my ($xp, $data) = @_;
+
+ $acc .= $data;
+}
+
+sub stcd {
+ my $xp = shift;
+ $xp->setHandlers(Char => \&ch);
+}
+
+sub ecd {
+ my $xp = shift;
+ $xp->setHandlers(Char => 0);
+}
+
+$parser = new XML::Parser(ErrorContext => 2,
+ Handlers => {CdataStart => \&stcd,
+ CdataEnd => \&ecd});
+
+$parser->parse($doc);
+
+print "not "
+ unless ($acc eq $cdata_part);
+print "ok 2\n";
+
diff --git a/t/decl.t b/t/decl.t
new file mode 100644
index 0000000..b89d6de
--- /dev/null
+++ b/t/decl.t
@@ -0,0 +1,166 @@
+BEGIN {print "1..30\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+my $bigval =<<'End_of_bigval;';
+This is a large string value to test whether the declaration parser still
+works when the entity or attribute default value may be broken into multiple
+calls to the default handler.
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+End_of_bigval;
+
+$bigval =~ s/\n/ /g;
+
+my $docstr =<<"End_of_Doc;";
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE foo SYSTEM 't/foo.dtd'
+ [
+ <!ENTITY alpha 'a'>
+ <!ELEMENT junk ((bar|foo|xyz+), zebra*)>
+ <!ELEMENT xyz (#PCDATA)>
+ <!ELEMENT zebra (#PCDATA|em|strong)*>
+ <!ATTLIST junk
+ id ID #REQUIRED
+ version CDATA #FIXED '1.0'
+ color (red|green|blue) 'green'
+ foo NOTATION (x|y|z) #IMPLIED>
+ <!ENTITY skunk "stinky animal">
+ <!ENTITY big "$bigval">
+ <!-- a comment -->
+ <!NOTATION gif SYSTEM 'http://www.somebody.com/specs/GIF31.TXT'>
+ <!ENTITY logo PUBLIC '//Widgets Corp/Logo' 'logo.gif' NDATA gif>
+ <?DWIM a useless processing instruction ?>
+ <!ELEMENT bar ANY>
+ <!ATTLIST bar big CDATA '$bigval'>
+ ]>
+<foo/>
+End_of_Doc;
+
+my $entcnt = 0;
+my %ents;
+my @tests;
+
+sub enth1 {
+ my ($p, $name, $val, $sys, $pub, $notation) = @_;
+
+ $tests[2]++ if ($name eq 'alpha' and $val eq 'a');
+ $tests[3]++ if ($name eq 'skunk' and $val eq 'stinky animal');
+ $tests[4]++ if ($name eq 'logo' and !defined($val) and
+ $sys eq 'logo.gif' and $pub eq '//Widgets Corp/Logo'
+ and $notation eq 'gif');
+}
+
+my $parser = new XML::Parser(ErrorContext => 2,
+ NoLWP => 1,
+ ParseParamEnt => 1,
+ Handlers => {Entity => \&enth1});
+
+$parser->parse($docstr);
+
+sub eleh {
+ my ($p, $name, $model) = @_;
+
+ if ($name eq 'junk') {
+ $tests[5]++ if $model eq '((bar|foo|xyz+),zebra*)';
+ $tests[6]++ if $model->isseq;
+ my @parts = $model->children;
+ $tests[7]++ if $parts[0]->ischoice;
+ my @cparts = $parts[0]->children;
+ $tests[8]++ if $cparts[0] eq 'bar';
+ $tests[9]++ if $cparts[1] eq 'foo';
+ $tests[10]++ if $cparts[2] eq 'xyz+';
+ $tests[11]++ if $cparts[2]->name eq 'xyz';
+ $tests[12]++ if $parts[1]->name eq 'zebra';
+ $tests[13]++ if $parts[1]->quant eq '*';
+ }
+
+ if ($name eq 'xyz') {
+ $tests[14]++ if ($model->ismixed and ! defined($model->children));
+ }
+
+ if ($name eq 'zebra') {
+ $tests[15]++ if ($model->ismixed and ($model->children)[1] eq 'strong');
+ }
+
+ if ($name eq 'bar') {
+ $tests[16]++ if $model->isany;
+ }
+}
+
+sub enth2 {
+ my ($p, $name, $val, $sys, $pub, $notation) = @_;
+
+ $tests[17]++ if ($name eq 'alpha' and $val eq 'a');
+ $tests[18]++ if ($name eq 'skunk' and $val eq 'stinky animal');
+ $tests[19]++ if ($name eq 'big' and $val eq $bigval);
+ $tests[20]++ if ($name eq 'logo' and !defined($val) and
+ $sys eq 'logo.gif' and $pub eq '//Widgets Corp/Logo'
+ and $notation eq 'gif');
+}
+
+sub doc {
+ my ($p, $name, $sys, $pub, $intdecl) = @_;
+
+ $tests[21]++ if $name eq 'foo';
+ $tests[22]++ if $sys eq 't/foo.dtd';
+ $tests[23]++ if $intdecl
+}
+
+sub att {
+ my ($p, $elname, $attname, $type, $default, $fixed) = @_;
+
+ $tests[24]++ if ($elname eq 'junk' and $attname eq 'id'
+ and $type eq 'ID' and $default eq '#REQUIRED'
+ and not $fixed);
+ $tests[25]++ if ($elname eq 'junk' and $attname eq 'version'
+ and $type eq 'CDATA' and $default eq "'1.0'" and $fixed);
+ $tests[26]++ if ($elname eq 'junk' and $attname eq 'color'
+ and $type eq '(red|green|blue)'
+ and $default eq "'green'");
+ $tests[27]++ if ($elname eq 'bar' and $attname eq 'big' and $default eq
+ "'$bigval'");
+ $tests[28]++ if ($elname eq 'junk' and $attname eq 'foo'
+ and $type eq 'NOTATION(x|y|z)' and $default eq '#IMPLIED');
+
+}
+
+sub xd {
+ my ($p, $version, $enc, $stand) = @_;
+
+ if (defined($version)) {
+ if ($version eq '1.0' and $enc eq 'ISO-8859-1' and not defined($stand)) {
+ $tests[29]++;
+ }
+ }
+ else {
+ $tests[30]++ if $enc eq 'x-sjis-unicode';
+ }
+}
+
+$parser->setHandlers(Entity => \&enth2,
+ Element => \&eleh,
+ Attlist => \&att,
+ Doctype => \&doc,
+ XMLDecl => \&xd);
+
+$| = 1;
+$parser->parse($docstr);
+
+for (2 .. 30) {
+ print "not " unless $tests[$_];
+ print "ok $_\n";
+}
diff --git a/t/defaulted.t b/t/defaulted.t
new file mode 100644
index 0000000..a3dfb91
--- /dev/null
+++ b/t/defaulted.t
@@ -0,0 +1,50 @@
+BEGIN {print "1..4\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+$doc =<<'End_of_Doc;';
+<!DOCTYPE foo [
+<!ATTLIST bar zz CDATA 'there'>
+]>
+<foo>
+ <bar xx="hello"/>
+ <bar zz="other"/>
+</foo>
+End_of_Doc;
+
+sub st {
+ my $xp = shift;
+ my $el = shift;
+
+ if ($el eq 'bar') {
+ my %atts = @_;
+ my %isdflt;
+ my $specified = $xp->specified_attr;
+
+ for (my $i = $specified; $i < @_; $i += 2) {
+ $isdflt{$_[$i]} = 1;
+ }
+
+ if (defined $atts{xx}) {
+ print 'not '
+ if $isdflt{'xx'};
+ print "ok 2\n";
+
+ print 'not '
+ unless $isdflt{'zz'};
+ print "ok 3\n";
+ }
+ else {
+ print 'not '
+ if $isdflt{'zz'};
+ print "ok 4\n";
+ }
+
+ }
+}
+
+$p = new XML::Parser(Handlers => {Start => \&st});
+
+$p->parse($doc);
diff --git a/t/encoding.t b/t/encoding.t
new file mode 100644
index 0000000..f0df1dd
--- /dev/null
+++ b/t/encoding.t
@@ -0,0 +1,110 @@
+BEGIN {print "1..6\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+################################################################
+# Check encoding
+
+my $xmldec = "<?xml version='1.0' encoding='x-sjis-unicode' ?>\n";
+
+my $docstring=<<"End_of_doc;";
+<\x8e\x83>\x90\x46\x81\x41\x98\x61\x81\x41\x99\x44
+</\x8e\x83>
+End_of_doc;
+
+my $doc = $xmldec . $docstring;
+
+my @bytes;
+my $lastel;
+
+sub text {
+ my ($xp, $data) = @_;
+
+ push(@bytes, unpack('U0C*', $data)); # was fixed 5.10
+}
+
+sub start {
+ my ($xp, $el) = @_;
+
+ $lastel = $el;
+}
+
+my $p = new XML::Parser(Handlers => {Start => \&start, Char => \&text});
+
+$p->parse($doc);
+
+my $exptag = ($] < 5.006)
+ ? "\xe7\xa5\x89" # U+7949 blessings 0x8e83
+ : chr(0x7949);
+
+my @expected = (0xe8, 0x89, 0xb2, # U+8272 beauty 0x9046
+ 0xe3, 0x80, 0x81, # U+3001 comma 0x8141
+ 0xe5, 0x92, 0x8c, # U+548C peace 0x9861
+ 0xe3, 0x80, 0x81, # U+3001 comma 0x8141
+ 0xe5, 0x83, 0x96, # U+50D6 joy 0x9944
+ 0x0a);
+
+if ($lastel eq $exptag) {
+ print "ok 2\n";
+}
+else {
+ print "not ok 2\n";
+}
+
+if (@bytes != @expected) {
+ print "not ok 3\n";
+}
+else {
+ my $i;
+ for ($i = 0; $i < @expected; $i++) {
+ if ($bytes[$i] != $expected[$i]) {
+ print "not ok 3\n";
+ exit;
+ }
+ }
+ print "ok 3\n";
+}
+
+$lastel = '';
+
+$p->parse($docstring, ProtocolEncoding => 'X-SJIS-UNICODE');
+
+if ($lastel eq $exptag) {
+ print "ok 4\n";
+}
+else {
+ print "not ok 4\n";
+}
+
+# Test the CP-1252 Win-Latin-1 mapping
+
+$docstring = qq(<?xml version='1.0' encoding='WINDOWS-1252' ?>
+<doc euro="\x80" lsq="\x91" rdq="\x94" />
+);
+
+my %attr;
+
+sub get_attr {
+ my ($xp, $el, @list) = @_;
+ %attr = @list;
+}
+
+$p = new XML::Parser(Handlers => {Start => \&get_attr});
+
+eval{ $p->parse($docstring) };
+
+if($@) {
+ print "not "; # couldn't load the map
+}
+print "ok 5\n";
+
+if( $attr{euro} ne ( $] < 5.006 ? "\xE2\x82\xAC" : chr(0x20AC) )
+ or $attr{lsq} ne ( $] < 5.006 ? "\xE2\x80\x98" : chr(0x2018) )
+ or $attr{rdq} ne ( $] < 5.006 ? "\xE2\x80\x9D" : chr(0x201D) )
+) {
+ print "not ";
+}
+print "ok 6\n";
+
diff --git a/t/ext.ent b/t/ext.ent
new file mode 100644
index 0000000..da72814
--- /dev/null
+++ b/t/ext.ent
@@ -0,0 +1 @@
+<!ATTLIST ext type CDATA "flag">
diff --git a/t/ext2.ent b/t/ext2.ent
new file mode 100644
index 0000000..cd96a84
--- /dev/null
+++ b/t/ext2.ent
@@ -0,0 +1 @@
+<more/>
diff --git a/t/external_ent.t b/t/external_ent.t
new file mode 100644
index 0000000..6d62aff
--- /dev/null
+++ b/t/external_ent.t
@@ -0,0 +1,70 @@
+BEGIN {print "1..5\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+################################################################
+# Check default external entity handler
+
+
+my $txt = '';
+
+sub txt {
+ my ($xp, $data) = @_;
+
+ $txt .= $data;
+}
+
+my $docstring =<<'End_of_XML;';
+<!DOCTYPE foo [
+ <!ENTITY a SYSTEM "a.ent">
+ <!ENTITY b SYSTEM "b.ent">
+ <!ENTITY c SYSTEM "c.ent">
+]>
+<foo>
+a = "&a;"
+b = "&b;"
+
+
+And here they are again in reverse order:
+b = "&b;"
+a = "&a;"
+
+</foo>
+End_of_XML;
+
+open(ENT, '>a.ent') or die "Couldn't open a.ent for writing";
+print ENT "This ('&c;') is a quote of c";
+close(ENT);
+
+open(ENT, '>b.ent') or die "Couldn't open b.ent for writing";
+print ENT "Hello, I'm B";
+close(ENT);
+
+open(ENT, '>c.ent') or die "Couldn't open c.ent for writing";
+print ENT "Hurrah for C";
+close(ENT);
+
+my $p = new XML::Parser(Handlers => {Char => \&txt});
+
+$p->parse($docstring);
+
+my %check = (a => "This ('Hurrah for C') is a quote of c",
+ b => "Hello, I'm B");
+
+my $tstcnt = 2;
+
+while ($txt =~ /([ab]) = "(.*)"/g) {
+ my ($k, $v) = ($1, $2);
+
+ unless ($check{$k} eq $v) {
+ print "not ";
+ }
+ print "ok $tstcnt\n";
+ $tstcnt++;
+}
+
+unlink('a.ent');
+unlink('b.ent');
+unlink('c.ent');
diff --git a/t/file.t b/t/file.t
new file mode 100644
index 0000000..d7c4f53
--- /dev/null
+++ b/t/file.t
@@ -0,0 +1,15 @@
+BEGIN {print "1..2\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+my $count = 0;
+
+$parser = new XML::Parser(ErrorContext => 2);
+$parser->setHandlers(Comment => sub {$count++;});
+
+$parser->parsefile('samples/REC-xml-19980210.xml');
+
+print "not " unless $count == 37;
+print "ok 2\n";
diff --git a/t/finish.t b/t/finish.t
new file mode 100644
index 0000000..45cd86c
--- /dev/null
+++ b/t/finish.t
@@ -0,0 +1,32 @@
+BEGIN {print "1..3\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+my $stcount = 0;
+my $encount = 0;
+
+sub st {
+ my ($exp, $el) = @_;
+ $stcount++;
+ $exp->finish if $el eq 'loc';
+}
+
+sub end {
+ $encount++;
+}
+
+$parser = new XML::Parser(Handlers => {Start => \&st,
+ End => \&end
+ },
+ ErrorContext => 2);
+
+
+$parser->parsefile('samples/REC-xml-19980210.xml');
+
+print "not " unless $stcount == 12;
+print "ok 2\n";
+
+print "not " unless $encount == 8;
+print "ok 3\n";
diff --git a/t/foo.dtd b/t/foo.dtd
new file mode 100644
index 0000000..fb026bf
--- /dev/null
+++ b/t/foo.dtd
@@ -0,0 +1,20 @@
+<?xml encoding="x-sjis-unicode"?>
+<!ENTITY joy "™D">
+
+<!ATTLIST foo zz CDATA 'here'>
+
+<!ENTITY % bar 'IGNORE'>
+<!ENTITY % foo 'IGNORE'>
+
+<!ENTITY more SYSTEM 'ext2.ent'>
+
+<!ENTITY % ext SYSTEM 'ext.ent'>
+%ext;
+
+<![%bar;[
+<!ATTLIST bar xyz (a|b|c) 'b'>
+]]>
+
+<![%foo;[
+<!ATTLIST foo top CDATA "hello">
+]]>
diff --git a/t/namespaces.t b/t/namespaces.t
new file mode 100644
index 0000000..bbc48d7
--- /dev/null
+++ b/t/namespaces.t
@@ -0,0 +1,133 @@
+BEGIN {print "1..16\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+################################################################
+# Check namespaces
+
+$docstring =<<'End_of_doc;';
+<foo xmlns="urn:blazing-saddles"
+ xmlns:bar="urn:young-frankenstein"
+ bar:alpha="17">
+ <zebra xyz="nothing"/>
+ <tango xmlns=""
+ xmlns:zoo="urn:high-anxiety"
+ beta="blue"
+ zoo:beta="green"
+ bar:beta="red">
+ <?nscheck?>
+ <zoo:here/>
+ <there/>
+ </tango>
+ <everywhere/>
+</foo>
+End_of_doc;
+
+my $gname;
+
+sub init {
+ my $xp = shift;
+ $gname = $xp->generate_ns_name('alpha', 'urn:young-frankenstein');
+}
+
+sub start {
+ my $xp = shift;
+ my $el = shift;
+
+ if ($el eq 'foo') {
+ print "not " unless $xp->namespace($el) eq 'urn:blazing-saddles';
+ print "ok 2\n";
+
+ print "not " unless $xp->new_ns_prefixes == 2;
+ print "ok 3\n";
+
+ while (@_) {
+ my $att = shift;
+ my $val = shift;
+ if ($att eq 'alpha') {
+ print "not " unless $xp->eq_name($gname, $att);
+ print "ok 4\n";
+ last;
+ }
+ }
+ }
+ elsif ($el eq 'zebra') {
+ print "not " unless $xp->new_ns_prefixes == 0;
+ print "ok 5\n";
+
+ print "not " unless $xp->namespace($el) eq 'urn:blazing-saddles';
+ print "ok 6\n";
+ }
+ elsif ($el eq 'tango') {
+ print "not " if $xp->namespace($_[0]);
+ print "ok 8\n";
+
+ print "not " unless $_[0] eq $_[2];
+ print "ok 9\n";
+
+ print "not " if $xp->eq_name($_[0], $_[2]);
+ print "ok 10\n";
+
+ my $cnt = 0;
+ foreach ($xp->new_ns_prefixes) {
+ $cnt++ if $_ eq '#default';
+ $cnt++ if $_ eq 'zoo';
+ }
+
+ print "not " unless $cnt == 2;
+ print "ok 11\n";
+ }
+}
+
+sub end {
+ my $xp = shift;
+ my $el = shift;
+
+ if ($el eq 'zebra') {
+ print "not "
+ unless $xp->expand_ns_prefix('#default') eq 'urn:blazing-saddles';
+ print "ok 7\n";
+ }
+ elsif ($el eq 'everywhere') {
+ print "not " unless $xp->namespace($el) eq 'urn:blazing-saddles';
+ print "ok 16\n";
+ }
+}
+
+sub proc {
+ my $xp = shift;
+ my $target = shift;
+
+ if ($target eq 'nscheck') {
+ print "not " if $xp->new_ns_prefixes > 0;
+ print "ok 12\n";
+
+ my $cnt = 0;
+ foreach ($xp->current_ns_prefixes) {
+ $cnt++ if $_ eq 'zoo';
+ $cnt++ if $_ eq 'bar';
+ }
+
+ print "not " unless $cnt == 2;
+ print "ok 13\n";
+
+ print "not "
+ unless $xp->expand_ns_prefix('bar') eq 'urn:young-frankenstein';
+ print "ok 14\n";
+
+ print "not "
+ unless $xp->expand_ns_prefix('zoo') eq 'urn:high-anxiety';
+ print "ok 15\n";
+ }
+}
+
+my $parser = new XML::Parser(ErrorContext => 2,
+ Namespaces => 1,
+ Handlers => {Start => \&start,
+ End => \&end,
+ Proc => \&proc,
+ Init => \&init});
+
+$parser->parse($docstring);
diff --git a/t/parament.t b/t/parament.t
new file mode 100644
index 0000000..0a04277
--- /dev/null
+++ b/t/parament.t
@@ -0,0 +1,117 @@
+BEGIN {print "1..12\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+my $internal_subset =<<'End_of_internal;';
+[
+ <!ENTITY % foo "IGNORE">
+ <!ENTITY % bar "INCLUDE">
+ <!ENTITY more SYSTEM "t/ext2.ent">
+]
+End_of_internal;
+
+my $doc =<<"End_of_doc;";
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE foo SYSTEM "t/foo.dtd"
+$internal_subset>
+<foo>Happy, happy
+<bar>&joy;, &joy;</bar>
+<ext/>
+&more;
+</foo>
+End_of_doc;
+
+my $gotinclude = 0;
+my $gotignore = 0;
+my $doctype_called = 0;
+my $internal_exists = 0;
+my $gotmore = 0;
+
+my $bartxt = '';
+
+sub start {
+ my ($xp, $el, %atts) = @_;
+
+ if ($el eq 'foo') {
+ print "not " if defined($atts{top});
+ print "ok 2\n";
+ print "not " unless defined($atts{zz});
+ print "ok 3\n";
+ }
+ elsif ($el eq 'bar') {
+ print "not " unless (defined $atts{xyz} and $atts{xyz} eq 'b');
+ print "ok 4\n";
+ }
+ elsif ($el eq 'ext') {
+ print "not " unless (defined $atts{type} and $atts{type} eq 'flag');
+ print "ok 5\n";
+ }
+ elsif ($el eq 'more') {
+ $gotmore = 1;
+ }
+}
+
+sub char {
+ my ($xp, $text) = @_;
+
+ $bartxt .= $text if $xp->current_element eq 'bar';
+}
+
+sub attl {
+ my ($xp, $el, $att, $type, $dflt, $fixed) = @_;
+
+ $gotinclude = 1 if ($el eq 'bar' and $att eq 'xyz' and $dflt eq "'b'");
+ $gotignore = 1 if ($el eq 'foo' and $att eq 'top' and $dflt eq '"hello"');
+}
+
+sub dtd {
+ my ($xp, $name, $sysid, $pubid, $internal) = @_;
+
+ $doctype_called = 1;
+ $internal_exists = $internal;
+}
+
+$p = new XML::Parser(ParseParamEnt => 1,
+ ErrorContext => 2,
+ Handlers => {Start => \&start,
+ Char => \&char,
+ Attlist => \&attl,
+ Doctype => \&dtd
+ }
+ );
+
+$p->parse($doc);
+
+print "not " unless $gotmore;
+print "ok 6\n";
+
+print "not " unless $bartxt eq ($] < 5.006)
+ ? "\xe5\x83\x96, \xe5\x83\x96"
+ : chr(0x50d6). ", " . chr(0x50d6);
+print "ok 7\n";
+
+print "not " unless $gotinclude;
+print "ok 8\n";
+
+print "not " if $gotignore;
+print "ok 9\n";
+
+print "not " unless $doctype_called;
+print "ok 10\n";
+
+print "not " unless $internal_exists;
+print "ok 11\n";
+
+$doc =~ s/[\s\n]+\[[^]]*\][\s\n]+//m;
+
+$p->setHandlers(Start => sub {
+ my ($xp,$el,%atts) = @_;
+ if ($el eq 'foo') {
+ print "not " unless defined($atts{zz});
+ print "ok 12\n";
+ }
+ });
+
+$p->parse($doc);
diff --git a/t/partial.t b/t/partial.t
new file mode 100644
index 0000000..c94c9b8
--- /dev/null
+++ b/t/partial.t
@@ -0,0 +1,40 @@
+BEGIN {print "1..3\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+my $cnt = 0;
+my $str;
+
+sub tmpchar {
+ my ($xp, $data) = @_;
+
+ if ($xp->current_element eq 'day') {
+ $str = $xp->original_string;
+ $xp->setHandlers(Char => 0);
+ }
+}
+
+my $p = new XML::Parser(Handlers => {Comment => sub {$cnt++;},
+ Char => \&tmpchar
+ });
+
+my $xpnb = $p->parse_start;
+
+open(REC, 'samples/REC-xml-19980210.xml');
+
+while (<REC>) {
+ $xpnb->parse_more($_);
+}
+
+close(REC);
+
+$xpnb->parse_done;
+
+print "not " unless $cnt == 37;
+print "ok 2\n";
+
+print "not " unless $str eq '&draft.day;';
+print "ok 3\n";
+
diff --git a/t/skip.t b/t/skip.t
new file mode 100644
index 0000000..6cde2a7
--- /dev/null
+++ b/t/skip.t
@@ -0,0 +1,53 @@
+BEGIN {print "1..4\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+my $cmnt_count = 0;
+my $pi_count = 0;
+my $between_count = 0;
+my $authseen = 0;
+
+sub init {
+ my $xp = shift;
+ $xp->skip_until(1); # Skip through prolog
+}
+
+sub proc {
+ $pi_count++;
+}
+
+sub cmnt {
+ $cmnt_count++;
+}
+
+sub start {
+ my ($xp, $el) = @_;
+ my $ndx = $xp->element_index;
+ if (! $authseen and $el eq 'authlist') {
+ $authseen = 1;
+ $xp->skip_until(2000);
+ }
+ elsif ($authseen and $ndx < 2000) {
+ $between_count++;
+ }
+}
+
+my $p = new XML::Parser(Handlers => {Init => \&init,
+ Start => \&start,
+ Comment => \&cmnt,
+ Proc => \&proc
+ });
+
+$p->parsefile('samples/REC-xml-19980210.xml');
+
+print "not " if $between_count;
+print "ok 2\n";
+
+print "not " if $pi_count;
+print "ok 3\n";
+
+print "not " unless $cmnt_count == 5;
+print "ok 4\n";
+
diff --git a/t/stream.t b/t/stream.t
new file mode 100644
index 0000000..92b7994
--- /dev/null
+++ b/t/stream.t
@@ -0,0 +1,50 @@
+BEGIN {print "1..3\n";}
+END {print "not ok 1\n" unless $loaded;}
+use XML::Parser;
+$loaded = 1;
+print "ok 1\n";
+
+my $delim = '------------123453As23lkjlklz877';
+my $file = 'samples/REC-xml-19980210.xml';
+my $tmpfile = 'stream.tmp';
+
+my $cnt = 0;
+
+
+open(OUT, ">$tmpfile") or die "Couldn't open $tmpfile for output";
+open(IN, $file) or die "Couldn't open $file for input";
+
+while (<IN>) {
+ print OUT;
+}
+
+close(IN);
+print OUT "$delim\n";
+
+open(IN, $file);
+while (<IN>) {
+ print OUT;
+}
+
+close(IN);
+close(OUT);
+
+my $parser = new XML::Parser(Stream_Delimiter => $delim,
+ Handlers => {Comment => sub {$cnt++;}});
+
+open(FOO, $tmpfile);
+
+$parser->parse(*FOO);
+
+print "not " if ($cnt != 37);
+print "ok 2\n";
+
+$cnt = 0;
+
+$parser->parse(*FOO);
+
+print "not " if ($cnt != 37);
+print "ok 3\n";
+
+close(FOO);
+unlink($tmpfile);
diff --git a/t/styles.t b/t/styles.t
new file mode 100644
index 0000000..b4567ce
--- /dev/null
+++ b/t/styles.t
@@ -0,0 +1,62 @@
+use Test;
+BEGIN { plan tests => 13 }
+use XML::Parser;
+use IO::File;
+
+my $xmlstr = '<foo>bar</foo>';
+
+{
+ # Debug style
+ my $parser = XML::Parser->new(Style => 'Debug');
+ ok($parser);
+
+ my $tmpfile = IO::File->new_tmpfile();
+ open(OLDERR, ">&STDERR");
+ open(STDERR, ">&" . $tmpfile->fileno) || die "Cannot re-open STDERR : $!";
+
+ $parser->parse($xmlstr);
+
+ close(STDERR);
+ open(STDERR, ">&OLDERR");
+ close(OLDERR);
+
+ seek($tmpfile, 0, 0);
+ my $warn = 0;
+ $warn++ while (<$tmpfile>);
+ ok($warn, 3, "Check we got three warnings out");
+}
+
+{
+ # Object style
+ my $parser = XML::Parser->new(Style => 'Objects');
+ ok($parser);
+
+ my $tree = $parser->parse($xmlstr);
+ ok($tree);
+}
+
+{
+ # Stream style
+ my $parser = XML::Parser->new(Style => 'Stream');
+ ok($parser);
+}
+
+{
+ # Subs style
+ my $parser = XML::Parser->new(Style => 'Subs');
+ ok($parser);
+}
+
+{
+ # Tree style
+ my $parser = XML::Parser->new(Style => 'Tree');
+ ok($parser);
+
+ my $tree = $parser->parse($xmlstr);
+ ok(ref($tree), 'ARRAY');
+ ok($tree->[0], 'foo');
+ ok(ref($tree->[1]), 'ARRAY');
+ ok(ref($tree->[1]->[0]), 'HASH');
+ ok($tree->[1][1], '0');
+ ok($tree->[1][2], 'bar');
+}