Parent Directory
|
Revision Log
Bug fix
| 1 | wakaba | 1.1 | |
| 2 | =head1 NAME | ||
| 3 | |||
| 4 | wakaba | 1.12 | Message::Markup::XML::Parser --- manakai: Simple XML parser |
| 5 | wakaba | 1.1 | |
| 6 | =head1 DESCRIPTION | ||
| 7 | |||
| 8 | wakaba | 1.12 | This is a simple XML parser intended to be used with Message::Markup::XML. |
| 9 | After parsing of the XML document, this module returns a Message::Markup::XML | ||
| 10 | wakaba | 1.1 | object so that you can handle XML document with that module (and other modules |
| 11 | implementing same interface). | ||
| 12 | |||
| 13 | wakaba | 1.12 | This module is part of manakai. |
| 14 | wakaba | 1.1 | |
| 15 | =cut | ||
| 16 | |||
| 17 | wakaba | 1.12 | package Message::Markup::XML::Parser; |
| 18 | wakaba | 1.1 | use strict; |
| 19 | wakaba | 1.17 | our $VERSION = do{my @r=(q$Revision: 1.16 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r}; |
| 20 | wakaba | 1.6 | use Char::Class::XML qw!InXML_NameStartChar InXMLNameChar InXMLChar |
| 21 | InXML_deprecated_noncharacter InXML_unicode_xml_not_suitable!; | ||
| 22 | wakaba | 1.12 | require Message::Markup::XML; |
| 23 | require Message::Markup::XML::Error; | ||
| 24 | *_raise_error = \&Message::Markup::XML::Error::raise; | ||
| 25 | wakaba | 1.6 | our %NS; |
| 26 | wakaba | 1.12 | *NS = \%Message::Markup::XML::NS; |
| 27 | wakaba | 1.1 | |
| 28 | =head1 METHODS | ||
| 29 | |||
| 30 | WARNING: This module is under construction. Interface of this module is not yet fixed. | ||
| 31 | |||
| 32 | =cut | ||
| 33 | |||
| 34 | w | 1.10 | our %xml_re; |
| 35 | wakaba | 1.1 | # [1] document = prolog element *Misc |
| 36 | # [2] Char = %x09 / %x0A / %x0D / U+0020-U+D7FF / U+E000-U+FFFD / U+10000-U+10FFFF ;; 1.0 | ||
| 37 | # [2] Char = %x09 / %x0A / %x0D / %x20-7E / U+0085 / U+00A0-U+D7FF / U+E000-U+FFFD | ||
| 38 | # / U+10000-U+10FFFF ;; 1.1 | ||
| 39 | # [3] s = 1*(%x20 / %x09 / %x0D / %x0A) | ||
| 40 | wakaba | 1.6 | $xml_re{s} = qr/[\x09\x0A\x0D\x20]+/s; |
| 41 | w | 1.8 | $xml_re{_s__chars} = qr/\x09\x0A\x0D\x20/s; |
| 42 | wakaba | 1.1 | # [4] NameChar = Letter / Digit / "." / "-" / "_" / ":" / CombiningChar / Extender ;; 1.0 |
| 43 | # [4] NameStartChar = ":" / ALPHA / "_" / U+00C0-U+02FF / U+0370-U+037D | ||
| 44 | # / U+037F-U+1FFF / U+200C-U+200D / U+2070-U+218F | ||
| 45 | # / U+2C00-U+2FEF / U+3001-U+D7FF / U+F900-U+EFFFF ;; 1.1 | ||
| 46 | # [4a] NameChar = NameStartChar / "-" / "." / DIGIT / U+00B7 / U+0300-U+036F | ||
| 47 | # / U+203F-U+2040 ;; 1.1 | ||
| 48 | # $xml_re{NameChar} = qr/[A-Za-z0-9._:-]|[^\x00-\x7F]/; | ||
| 49 | wakaba | 1.4 | #$xml_re{NameChar} = qr/\p{InXMLNameChar}/; |
| 50 | wakaba | 1.1 | # [5] Name = (Letter / "_" / ":") *NameChar ;; 1.0 |
| 51 | # [5] Name = NameStartChar *NameChar ;; 1.1 | ||
| 52 | # $xml_re{Name} = qr/(?:[A-Z_:]|[^\x00-\x7F])(?:$xml_re{NameChar})*/; | ||
| 53 | $xml_re{Name} = qr/\p{InXML_NameStartChar}\p{InXMLNameChar}*/; | ||
| 54 | # [6] Names = Name *(S Name) ;; 1.0 FE & 1.0 FE-errata (2000-09-27) & 1.0 SE | ||
| 55 | # [6] Names = Name *(%x20 Name) ;; 1.0 FE-errata (2000-04-09) & 1.0 SE-errata | ||
| 56 | wakaba | 1.4 | #$xml_re{Names} = qr/$xml_re{Name}(?:$xml_re{s}$xml_re{Name})*/s; |
| 57 | wakaba | 1.1 | # [7] Nmtoken = 1*NameChar |
| 58 | #$xml_re{Nmtoken} = qr/(?:$xml_re{NameChar})+/; | ||
| 59 | wakaba | 1.4 | #$xml_re{Nmtoken} = qr/\p{InXMLNameChar}+/; |
| 60 | wakaba | 1.1 | # [8] Nmtokens = Nmtoken *(S Nmtoken) ;; 1.0 FE & 1.0 FE-errata (2000-09-27) & 1.0 SE |
| 61 | # [8] Nmtokens = Nmtoken *(%x20 Nmtoken) ;; 1.0 FE-errata (2000-04-09) & 1.0 SE-errata | ||
| 62 | wakaba | 1.4 | #$xml_re{Nmtokens} = qr/$xml_re{Nmtoken}(?:$xml_re{s}$xml_re{Nmtoken})*/s; |
| 63 | wakaba | 1.1 | # [9] EntityValue = <"> *((Char - ("%" / "&" / <">)) / PEReference / Reference) <"> |
| 64 | # / "'" *((Char - ("%" / "&" / "'")) / PEReference / Reference) "'" | ||
| 65 | # [10] AttValue = <"> *((Char - ("<" / "&" / <">)) / Reference) <"> | ||
| 66 | # / "'" *((Char - ("<" / "&" / "'")) / Reference) "'" | ||
| 67 | $xml_re{__AttValue_simple} = qr/"[^"]*"|'[^']*'/s; | ||
| 68 | # [11] SystemLiteral = <"> *(Char - <">) <"> / "'" *(Char - "'") "'" | ||
| 69 | wakaba | 1.4 | #$xml_re{SystemLiteral} = qr/"[^"]*"|'[^']*'/; |
| 70 | wakaba | 1.1 | # [12] PublicLiteral = <"> *PubidChar <"> / "'" *(PubidChar - "'") "'" |
| 71 | # [13] PubidChar = %x20 / %x0D / %x0A / ALPHA / DIGIT / "-" / "'" / "(" / ")" | ||
| 72 | # / "+" / "," / "." / "/" / ":" / "=" / "?" / ";" / "!" / "*" | ||
| 73 | # / "#" / "@" / "$" / "_" / "%" | ||
| 74 | wakaba | 1.6 | #$xml_re{PubidChar} = qr[[\x0D\x0A\x20!\x24#%'()+*,./0-9:;=?\x40A-Z_a-z-]]; |
| 75 | #$xml_re{__non_PubidChar} = qr[[^\x0D\x0A\x20!\x24#%'()+*,./0-9:;=?\x40A-Z_a-z-]]; | ||
| 76 | wakaba | 1.4 | #$xml_re{__PubidChar2} = qr[[\x0D\x0A\x20!\x24#%()+*,./0-9:;=?\x40A-Z_a-z-]]; |
| 77 | #$xml_re{PublicLiteral} = qr/"(?:$xml_re{PubidChar})*"|'(?:$xml_re{__PubidChar2})*'/; | ||
| 78 | wakaba | 1.1 | # [14] CharData = *(Char - ("<" / "&")) - (*(Char - ("<" / "&")) "]]>" *(Char - ("<" / "&"))) |
| 79 | wakaba | 1.4 | #$xml_re{CharData} = qr/(?:(?!\]\]>)[^<&])*/s; |
| 80 | wakaba | 1.1 | $xml_re{__CharDataP} = qr/(?:(?!\]\]>)[^<&])+/s; |
| 81 | # [15] Comment = "<!--" *((Char - "-") / ("-" (Char - "-")))) "-->" | ||
| 82 | wakaba | 1.16 | #$xml_re{Comment_M} = qr/<!--((?:(?!--).)*)-->/s; |
| 83 | wakaba | 1.1 | # [16] PI = "<?" PITarget [S (*Char - (*Char "?>" *Char))] "?>" |
| 84 | $xml_re{PI_M} = qr/<\?($xml_re{Name})(?:$xml_re{s}((?:(?!\?>).)*))?\?>/s; | ||
| 85 | wakaba | 1.4 | $xml_re{_xml_PI_M} = qr/<\?xml(?:$xml_re{s}((?:(?!\?>).)*))?\?>/s; |
| 86 | wakaba | 1.1 | # [17] PITarget = Name - "xml" |
| 87 | # [18] CDSect = CDStart CData CDEnd | ||
| 88 | # [19] CDStart = '<![CDATA[' | ||
| 89 | # [20] CDATA = (*Char - (*Char "]]>" *Char)) | ||
| 90 | # [21] CDEnd = "]]>" | ||
| 91 | $xml_re{CDSect_M} = qr/<!\[CDATA\[((?:(?!\]\]>).)*)\]\]>/s; | ||
| 92 | # [22] prolog = [XMLDecl] *Misc [doctypedecl *Misc] | ||
| 93 | # [23] XMLDecl = '<?xml' VersionInfo [EncodingDecl] [SDDecl] [S] "?>" | ||
| 94 | # [24] VersionInfo = S 'version' Eq ("'" VersionNum "'" / <"> VersionNum <">) | ||
| 95 | # [25] Eq = [S] "=" [S] | ||
| 96 | # [26] VersionNum = 1*(ALPHA / DIGIT / "_" / "." / ":" / "-") ;; 1.0 FE & 1.0 SE | ||
| 97 | # [26] VersionNum = "1.0" ;; 1.0 SE-errata | ||
| 98 | # [26] VersionNum = "1.1" ;; 1.1 | ||
| 99 | # [27] Misc = Comment / PI / S | ||
| 100 | # [28] doctypedecl = '<!DOCTYPE' S Name [S ExternalID] [S] | ||
| 101 | # ["[" *(markupdecl / PEReference / S) "]" [S]] ">" ;; 1.0 FE | ||
| 102 | # [28] doctypedecl = '<!DOCTYPE' S Name [S ExternalID] [S] ["[" *(markupdecl / DeclSep) "]" [S]] ">" | ||
| 103 | # ;; 1.0 FE-errata & 1.0 SE | ||
| 104 | # [28] doctypedecl = '<!DOCTYPE' S Name [S ExternalID] [S] ["[" intSubset "]" [S]] ">" | ||
| 105 | # ;; 1.0 SE-errata | ||
| 106 | wakaba | 1.6 | #$xml_re{__doctypedecl_start_simple_M} = qr/(<!DOCTYPE$xml_re{s})($xml_re{Name})($xml_re{s}SYSTEM$xml_re{s}$xml_re{__AttValue_simple}|$xml_re{s}PUBLIC$xml_re{s}$xml_re{__AttValue_simple}$xml_re{s}$xml_re{__AttValue_simple})?/s; |
| 107 | wakaba | 1.1 | # [28a] DeclSep = PEReference / S ;; 1.0 FE-errata & 1.0 SE |
| 108 | # [28b] intSubset = *(markupdecl / DeclSep) ;; 1.0 SE-errata | ||
| 109 | # [29] markupdecl = elementdecl / AttlistDecl / EntityDecl / NotationDecl / PI / Comment | ||
| 110 | # [30] extSubset = [TextDecl] extSubsetDecl | ||
| 111 | # [31] extSubsetDecl = *(markupdecl / conditionalSect / PEReference / S) ;; 1.0 FE | ||
| 112 | # [31] extSubsetDecl = *(markupdecl / conditionalSect / DeclSep) ;; 1.0 FE-errata & 1.0 SE | ||
| 113 | # [32] SDDecl = S 'standalone' Eq ("'" ('yes' / 'no') "'" / <"> ('yes' / 'no') <">) | ||
| 114 | # [33] LanguageID = Langcode *("-" Subcode) ;; 1.0 FE (removed by 1.0 SE) | ||
| 115 | # [34] Langcode = ISO639Cocde / IanaCode / UserCode ;; 1.0 FE (ditto) | ||
| 116 | # [35] ISO639Code = 2ALPHA ;; 1.0 FE (ditto) | ||
| 117 | # [36] IanaCode = "i-" 1*ALPHA ;; 1.0 FE (ditto) | ||
| 118 | # [37] UserCode = "x-" 1*ALPHA ;; 1.0 FE (ditto) | ||
| 119 | # [38] Subcode = 1*ALPHA ;; 1.0 FE (ditto) | ||
| 120 | # [39] element = EmptyElemTag / STag content ETag | ||
| 121 | # [40] STag = "<" Name *(S Attribute) [S] ">" | ||
| 122 | # [41] Attribute = Name Eq AttValue | ||
| 123 | $xml_re{Attribute} = qr/$xml_re{Name}(?:$xml_re{s})?=(?:$xml_re{s})?$xml_re{__AttValue_simple}/s; | ||
| 124 | $xml_re{Attribute_M} = qr/($xml_re{Name})(?:$xml_re{s})?=(?:$xml_re{s})?($xml_re{__AttValue_simple})/s; | ||
| 125 | wakaba | 1.4 | #$xml_re{STag} = qr/<$xml_re{Name}(?:$xml_re{s}$xml_re{Attribute})*(?:$xml_re{s})?>/s; |
| 126 | wakaba | 1.1 | # [42] ETag = "</" Name [S] ">" |
| 127 | $xml_re{ETag_M} = qr!</($xml_re{Name})(?:$xml_re{s})?>!s; | ||
| 128 | # [43] content = *(element / CharData / Reference / CDSect / PI / Comment) ;; 1.0 FE | ||
| 129 | # [43] content = [CharData] *((element / Reference / CDSect / PI / Comment) [CharData]) | ||
| 130 | # ;; 1.0 FE-errata & 1.0 SE | ||
| 131 | # [44] EmptyElemTag = "<" Name *(S Attribute) [S] "/>" | ||
| 132 | wakaba | 1.4 | #$xml_re{__STag_or_EmptyElemTag} = qr!<$xml_re{Name}(?:$xml_re{s}$xml_re{Attribute})*(?:$xml_re{s})?/?>!s; |
| 133 | wakaba | 1.1 | $xml_re{__STag_or_EmptyElemTag_simple} = qr!<$xml_re{ame}(?:$xml_re{s}|$xml_re{Name}|$xml_re{__AttValue_simple}|=)*/?>!s; |
| 134 | # [45] elementdecl = '<!ELEMENT' S Name S contentspec [S] ">" | ||
| 135 | # [46] contentspec = 'EMPTY' / 'ANY' / Mixed / children | ||
| 136 | wakaba | 1.4 | #$xml_re{__contentspec_simple} = qr/(?:$xml_re{Name}|\#PCDATA|[()|,?*+]|$xml_re{s})/s; |
| 137 | wakaba | 1.1 | # [47] children = (choice / seq) ["?" / "*" / "+"] |
| 138 | # [48] cp = (Name / choice / seq) ["?" / "*" / "+"] | ||
| 139 | # [49] choice = "(" [S] cp *([S] "|" [S] cp) [S] ")" ;; 1.0 FE | ||
| 140 | # [49] choice = "(" [S] cp 1*([S] "|" [S] cp) [S] ")" ;; 1.0 FE-errata & 1.0 SE | ||
| 141 | # [50] seq = "(" [S] cp *([S] "," [S] cp) [S] ")" | ||
| 142 | # [51] Mixed = "(" [S] '#PCDATA' *([S] "|" [S] Name) [S] ")*" | ||
| 143 | # / "(" [S] '#PCDATA' [S] ")" | ||
| 144 | #$xml_re{seq} = qr/\($xml_re{cp}(?:(?:$xml_re{s})?,(?:$xml_re{s})?$xml_re{cp})*(?:$xml_re{s})?\)/; | ||
| 145 | #$xml_re{cp} = qr/(?:$xml_re{Name}|$xml_re{choice}|$xml_re{seq})[?*+]/; | ||
| 146 | #$xml_re{choice} = qr/\($xml_re{cp}(?:(?:$xml_re{s})?\|(?:$xml_re{s})?$xml_re{cp})+(?:$xml_re{s})?\)/; | ||
| 147 | #$xml_re{children} = qr/(?:$xml_re{choice}|$xml_re{seq})[?*+]/; | ||
| 148 | #$xml_re{Mixed} = qr/(?:\((?:$xml_re{s})?\#PCDATA(?:$xml_re{s})?(?:(?:$xml_re{s})?|(?:$xml_re{s})?$xml_re{Name})*(?:$xml_re{s})?\)|\((?:$xml_re{s})?\#PCDATA(?:$xml_re{s})?\))/; | ||
| 149 | #$xml_re{contentspec} = qr/(?:EMPTY|ANY|$xml_re{Mixed}|$xml_re{children})/; | ||
| 150 | # [52] AttlistDecl = '<!ATTLIST' S Name *AttDef [S] ">" | ||
| 151 | # [53] AttDef = S Name S AttType S DefaultDecl | ||
| 152 | # [54] AttType = StringType / TokenizedType / EnumeratedType | ||
| 153 | # [55] StringType = 'CDATA' | ||
| 154 | # [56] TokenizedType = 'ID' / 'IDREF' / 'IDREFS' / 'ENTITY' / 'ENTITIES' / 'NMTOKEN' / 'NMTOKENS' | ||
| 155 | # [57] EnumeratedType = NotationType / Enumeration | ||
| 156 | # [58] NotationType = 'NOTATION' S "(" [S] Name *([S] "|" [S] Name) [S] ")" | ||
| 157 | # [59] Enumeration = "(" [S] Nmtoken *([S] "|" [S] Nmtoken) [S} ")" | ||
| 158 | # [60] DefaultDecl = '#REQUIRED' / '#IMPLIED' / ['#FIXED' S] AttValue | ||
| 159 | # [61] conditionalSect = includeSect / ignoreSect | ||
| 160 | # [62] includeSect = "<![" [S} 'INCLUDE' [S] "[" extSubsetDecl "]]>" | ||
| 161 | # [63] ignoreSect = "<![" [S] 'IGNORE' [S] "[" *ignoreSectContents "]]>" | ||
| 162 | # [64] ignoreSectContents = Ignore *("<![" ignoreSectContents "]]>" Ignore) | ||
| 163 | # [65] Ignore = *Char - (*Char ("<![" / "]]>") *Char) | ||
| 164 | # [66] CharRef = '&#' 1*DIGIT ";" / '&#x' 1*HEXDIGIT ";" | ||
| 165 | $xml_re{CharRef} = qr/&#[0-9]+;|&#x[0-9A-Fa-f]+;/; | ||
| 166 | # [67] Reference = EntityRef / CharRef | ||
| 167 | # [68] EntityRef = "&" Name ";" | ||
| 168 | $xml_re{EntityRef} = qr/&$xml_re{Name};/; | ||
| 169 | $xml_re{EntityRef_M} = qr/&($xml_re{Name});/; | ||
| 170 | $xml_re{Reference} = qr/$xml_re{EntityRef}|$xml_re{CharRef}/; | ||
| 171 | wakaba | 1.4 | #$xml_re{AttValue} = qr/"(?:$xml_re{Reference}|[^&<"])*"|'(?:$xml_re{Reference}|[^&<'])*'/s; |
| 172 | wakaba | 1.1 | # [69] PEReference = "%" Name ";" |
| 173 | $xml_re{PEReference} = qr/%(?:$xml_re{Name});/; | ||
| 174 | $xml_re{PEReference_M} = qr/%($xml_re{Name});/; | ||
| 175 | $xml_re{__elementdecl_simple} = qr/<!ELEMENT(?:$xml_re{s}|$xml_re{PEReference}|$xml_re{Name}|\#PCDATA|[()|,?*+])+>/s; | ||
| 176 | wakaba | 1.5 | $xml_re{__AttlistDecl_simple} = qr/<!ATTLIST(?:$xml_re{PEReference}|$xml_re{Name}|[#()|]|$xml_re{s}|$xml_re{__AttValue_simple})*>/s; |
| 177 | wakaba | 1.1 | # [70] EntityDecl = GEDecl / PEDecl |
| 178 | wakaba | 1.6 | #$xml_re{__EntityDecl_simple} = qr/<!ENTITY(?:$xml_re{__AttValue_simple}|[^"'>])*>/s; |
| 179 | wakaba | 1.1 | # [71] GEDecl = '<!ENTITY' S Name S EntityDef [S] ">" |
| 180 | # [72] PEDecl = '<!ENTITY' S "%" S Name S PEDef [S] ">" | ||
| 181 | # [73] EntityDef = EntityValue / ExternalID [NDataDecl] | ||
| 182 | # [74] PEDef = EntityValue / ExternalID | ||
| 183 | # [75] ExternalID = 'SYSTEM' S SystemLiteral / 'PUBLIC' S PublicLiteral S SystemLiteral | ||
| 184 | # [76] NDataDecl = S 'NDATA' S Name | ||
| 185 | # [77] TextDecl = '?xml' [VersionInfo] EncodingDecl [S] "?>" | ||
| 186 | # [78] extParsedEnt = [TextDecl] content | ||
| 187 | # [79] extPE ;; 1.0 FE (removed by errata) | ||
| 188 | # [80] EncodingDecl = S 'encoding' Eq (<"> EncName <"> / "'" EncName "'") | ||
| 189 | # [81] EncName = ALPHA *(ALPHA / DIGIT / "." / "_" / "-") | ||
| 190 | # [82] NotationDecl = '<!NOTATION' S Name S (ExternalID / PublicID) [S] ">" | ||
| 191 | wakaba | 1.6 | #$xml_re{__NotationDecl_simple} = qr/<!NOTATION(?:$xml_re{__AttValue_simple}|[^"'>])*>/s; |
| 192 | wakaba | 1.1 | # [83] PublicID = 'PUBLIC' S PubidLiteral |
| 193 | # [84] Letter = BaseChar / Ideographic | ||
| 194 | # [85] Basechar = ... | ||
| 195 | # [86] Ideographic = ... | ||
| 196 | # [87] CombiningChar = ... | ||
| 197 | # [88] Digit = ... | ||
| 198 | # [89] Extender = U+00B7 / U+02D0 / U+02D1 / U+0387 / U+0640 / U+0E46 / U+0EC6 | ||
| 199 | # / U+3005 / U+3031-U+3035 / U+309D / U+309E / U+30FC-U+30FE | ||
| 200 | ## [84]-[89] removed by 1.1 | ||
| 201 | |||
| 202 | # [XMLNames] | ||
| 203 | # [1] NSAttName = PrefixedAttName / DefaultAttName | ||
| 204 | # [2] PrefixedAttName = 'xmlns:' NCName | ||
| 205 | # [3] DefaultAttName = 'xmlns' | ||
| 206 | # [4] NCName = (Letter / "_") *NCNameChar ;; 1.0 | ||
| 207 | # [4] NCName = NCNameStartChar *NCNameChar ;; 1.1 | ||
| 208 | # [5] NCNameChar = Letter / Digit / "." / "-" / "_" / CombiningChar / Extender ;; 1.0 | ||
| 209 | # [5] NCNameChar = NameChar - ":" ;; 1.1 | ||
| 210 | # [5a] NCNameStartChar = NameStartChar - ":" ;; 1.1 | ||
| 211 | # [6] QName = [Prefix ":"] LocalPart ;; 1.0 | ||
| 212 | # [6] QName = PrefixedName / UnprefixedName ;; 1.1 | ||
| 213 |