Changeset 69
- Timestamp:
- 05/15/05 16:30:32 (4 years ago)
- Files:
-
- trunk/xml/BaseLexer.d (deleted)
- trunk/xml/BaseParser.d (deleted)
- trunk/xml/DTDLexer.d (deleted)
- trunk/xml/DTDParser.d (deleted)
- trunk/xml/ILexerStream.d (deleted)
- trunk/xml/IXMLConsumer.d (modified) (1 diff)
- trunk/xml/IXMLConsumerAdapter.d (modified) (1 diff)
- trunk/xml/IXMLProvider.d (modified) (1 diff)
- trunk/xml/MNonValidatingConsumer.d (deleted)
- trunk/xml/OfflineProvider.d (modified) (3 diffs)
- trunk/xml/Position.d (modified) (1 diff)
- trunk/xml/SimpleConsumer.d (added)
- trunk/xml/SimpleStream.d (deleted)
- trunk/xml/Unicode.d (added)
- trunk/xml/XMLAttributes.d (modified) (1 diff)
- trunk/xml/XMLException.d (modified) (2 diffs)
- trunk/xml/XMLLexer.d (deleted)
- trunk/xml/XMLParser.d (modified) (2 diffs)
- trunk/xml/XMLToken.d (deleted)
- trunk/xml/all.d (modified) (1 diff)
- trunk/xml/dom/DOMString.d (modified) (1 diff)
- trunk/xml/dom/std/CCDataSection.d (added)
- trunk/xml/dom/std/CComment.d (added)
- trunk/xml/dom/std/CDOMConfiguration.d (added)
- trunk/xml/dom/std/CDOMError.d (added)
- trunk/xml/dom/std/CDOMLocator.d (added)
- trunk/xml/dom/std/CDOMStringList.d (added)
- trunk/xml/dom/std/CDocumentFragment.d (added)
- trunk/xml/dom/std/CElement.d (added)
- trunk/xml/dom/std/CEntity.d (added)
- trunk/xml/dom/std/CEntityReference.d (added)
- trunk/xml/dom/std/CNotation.d (added)
- trunk/xml/dom/std/CTypeInfo.d (added)
- trunk/xml/utf16all.d (added)
- trunk/xml/utf32all.d (added)
- trunk/xml/utf32all.obj (added)
- trunk/xml/utf8all.d (added)
- trunk/xml/xpath (added)
- trunk/xml/xpath/XPath.d (added)
- trunk/xml/xpath/XPathBindings.d (added)
- trunk/xml/xpath/XPathContext.d (added)
- trunk/xml/xpath/XPathExpression.d (added)
- trunk/xml/xpath/XPathFunction.d (added)
- trunk/xml/xpath/XPathParser.d (added)
- trunk/xml/xpath/XPathVar.d (added)
- trunk/xml/xpath/all.d (added)
- trunk/xml/xpath/fn.d (added)
- trunk/xml/xpath/op.d (added)
- trunk/xml/xpath/xs.d (added)
- trunk/xml/xpath/xtd.d (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/xml/IXMLConsumer.d
r46 r69 28 28 private import xml.XMLAttributes; 29 29 30 interface IXMLConsumer{ 31 void xmlProlog(XMLAttributes attribs); 32 void xmlStartDoctype(char[] name); 33 void xmlEndDoctype(char[] name); 34 35 void xmlProcessingInstruction(char[] name,char[] data); 36 37 void xmlComment(char[] text); 38 39 void xmlStartElement(char[] name,XMLAttributes attribs,bit isEmpty); 40 void xmlEndElement(char[] name,XMLAttributes attribs,bit isEmpty); 41 void xmlText(char[] text); 30 enum TextType: short{ 31 NormalText, 32 EntityText, 33 CDATAText, 42 34 } 43 35 36 interface IXMLConsumer(CharT){ 37 mixin MXMLAttribute!(CharT); 38 39 enum DTDOperation: CharT{ 40 StartSequence = '(', 41 EndSequence = ')', 42 Or = '|', 43 And = '&', 44 OneOrMore = '*', 45 ZeroOrMore = '+', 46 ZeroOrOne = '?', 47 } 48 49 //TODO: break these out? 50 CharT[] getEntityValue(CharT[] entity,bit parsed); 51 bit xmlIsParsedProcessingInstruction(CharT[] name); 52 53 void xmlStartDTD(CharT[] name,XMLAttributes externalID); 54 void xmlEndDTD(CharT[] name,XMLAttributes externalID); 55 56 void xmlStartDTDElement(CharT[] name); 57 void xmlSetDTDElementChild(CharT[] name,CharT[] childName); 58 void xmlSetDTDElementOperation(CharT[] name,DTDOperation type); 59 void xmlEndDTDElement(CharT[] name); 60 61 void xmlStartDTDAttlist(CharT[] name); 62 void xmlSetDTDAttlistDef(CharT[] name,CharT[] type,CharT[] defaultDecl,CharT[] defaultValue); 63 void xmlEndDTDAttlist(CharT[] name); 64 65 void xmlSetDTDEntity(CharT[] name,CharT[] value,CharT[] ndata,bit parsed); 66 67 void xmlSetDTDNotation(CharT[] name, CharT[] publicId, CharT[] systemLiteral); 68 69 void xmlParsedProcessingInstruction(CharT[] name,XMLAttributes attribs); 70 void xmlProcessingInstruction(CharT[] name,CharT[] data); 71 72 void xmlComment(CharT[] text); 73 74 void xmlStartElement(CharT[] name,XMLAttributes attribs,bit isEmpty); 75 void xmlEndElement(CharT[] name,XMLAttributes attribs,bit isEmpty); 76 void xmlText(CharT[] text,TextType type); 77 } 78 79 alias IXMLConsumer!(char) Utf8IXMLConsumer; 80 alias IXMLConsumer!(wchar) Utf16IXMLConsumer; 81 alias IXMLConsumer!(dchar) Utf32IXMLConsumer; trunk/xml/IXMLConsumerAdapter.d
r46 r69 29 29 private import xml.XMLAttributes; 30 30 31 class IXMLConsumerAdapter : IXMLConsumer{ 32 void xmlProlog(XMLAttributes attribs){} 33 void xmlStartDoctype(char[] name){} 34 void xmlEndDoctype(char[] name){} 31 class IXMLConsumerAdapter(CharT) : IXMLConsumer!(CharT){ 32 CharT[] getEntityValue(CharT[] entity,bit parsed){ return "&" ~ entity ~ ";"; } 33 bit xmlIsParsedProcessingInstruction(CharT[] name){ return false; } 35 34 36 void xmlProcessingInstruction(char[] name,char[] data){} 35 void xmlStartDTD(CharT[] name,XMLAttributes externalID){} 36 void xmlEndDTD(CharT[] name,XMLAttributes externalID){} 37 37 38 void xmlComment(char[] text){} 38 void xmlStartDTDElement(CharT[] name){} 39 void xmlSetDTDElementChild(CharT[] name,CharT[] childName){} 40 void xmlSetDTDElementOperation(CharT[] name,DTDOperation type){} 41 void xmlEndDTDElement(CharT[] name){} 42 43 void xmlStartDTDAttlist(CharT[] name){} 44 void xmlSetDTDAttlistDef(CharT[] name,CharT[] type,CharT[] defaultDecl,CharT[] defaultValue){} 45 void xmlEndDTDAttlist(CharT[] name){} 39 46 40 void xmlStartElement(char[] name,XMLAttributes attribs,bit isEmpty){} 41 void xmlEndElement(char[] name,XMLAttributes attribs,bit isEmpty){} 42 void xmlText(char[] text){} 47 void xmlSetDTDEntity(CharT[] name,CharT[] value,CharT[] ndata,bit parsed){} 48 49 void xmlSetDTDNotation(CharT[] name, CharT[] publicId, CharT[] systemLiteral){} 50 51 void xmlParsedProcessingInstruction(CharT[] name,XMLAttributes attribs){} 52 void xmlProcessingInstruction(CharT[] name,CharT[] data){} 53 54 void xmlComment(CharT[] text){} 55 56 void xmlStartElement(CharT[] name,XMLAttributes attribs,bit isEmpty){} 57 void xmlEndElement(CharT[] name,XMLAttributes attribs,bit isEmpty){} 58 void xmlText(CharT[] text,TextType type){} 43 59 } 44 60 61 alias IXMLConsumerAdapter!(char) Utf8IXMLConsumerAdapter; 62 alias IXMLConsumerAdapter!(wchar) Utf16IXMLConsumerAdapter; 63 alias IXMLConsumerAdapter!(dchar) Utf32IXMLConsumerAdapter; 45 64 46 trunk/xml/IXMLProvider.d
r46 r69 26 26 module xml.IXMLProvider; 27 27 28 private import xml.ILexerStream; 28 interface IXMLProvider(CharT){ 29 CharT[] resolveExternalID(CharT[] pubid,CharT[] system); 30 } 29 31 30 interface IXMLProvider{ 31 ILexerStream resolveExternalID(char[] pubid,char[] system);32 } 32 alias IXMLProvider!(char) Utf8IXMLProvider; 33 alias IXMLProvider!(wchar) Utf16IXMLProvider; 34 alias IXMLProvider!(dchar) Utf32IXMLProvider; trunk/xml/OfflineProvider.d
r46 r69 26 26 module xml.OfflineProvider; 27 27 28 private import xml.ILexerStream;29 private import xml.SimpleStream;30 28 private import xml.IXMLProvider; 31 29 private import xml.XMLException; 30 private import xml.Unicode; 32 31 33 32 private import std.file; 34 33 private import std.utf; 35 34 36 class OfflineProvider : IXMLProvider{ 35 class OfflineProvider(CharT) : IXMLProvider!(CharT){ 36 mixin MCharConversionFunctions!(CharT); 37 37 38 char[] currentPath; 38 39 … … 49 50 } 50 51 51 ILexerStream resolveExternalID(char[] pubid,char[] system){52 CharT[] resolveExternalID(CharT[] pubid,CharT[] system){ 52 53 //throw out the public identifier (not useful here) 54 char[] utf8System = toUTF8(system); 53 55 54 if(system.length == 0) return new SimpleStream(""); 55 56 57 56 if(system.length == 0) return ""; 57 58 58 if(system.length < 5 || system[0..5] == "http:"){ 59 59 return null; // can't do this offline … … 65 65 66 66 if(system[0] != '/' || system[0] != '\\'){ 67 filename = currentPath ~ system;67 filename = currentPath ~ utf8System; 68 68 } 69 69 else{ 70 filename = system;70 filename = utf8System; 71 71 } 72 72 73 73 try{ 74 return new SimpleStream(toUTF8(cast(char[])std.file.read(filename)));74 return charTConvert(cast(char[])std.file.read(filename)); 75 75 } 76 76 catch(Exception e){ 77 throw new XMLException("failure to resolve file: " ~ system);77 throw new XMLException("failure to resolve file: " ~ utf8System); 78 78 } 79 79 return null; 80 80 } 81 81 } 82 83 alias OfflineProvider!(char) Utf8OfflineProviderBase; 84 alias OfflineProvider!(wchar) Utf16OfflineProviderBase; 85 alias OfflineProvider!(dchar) Utf32OfflineProviderBase; trunk/xml/Position.d
r43 r69 29 29 30 30 struct Position{ 31 uint row,col;31 uint line,column,offset; 32 32 char[] toString(){ 33 return format("(%d,%d)", row,col);33 return format("(%d,%d)",line,column); 34 34 } 35 35 } trunk/xml/XMLAttributes.d
r42 r69 26 26 module xml.XMLAttributes; 27 27 28 alias char[][char[]] XMLAttributes; 28 private import xml.Unicode; 29 30 template MXMLAttribute(CharT){ 31 alias CharT[][CharT[]] XMLAttributes; 32 } 33 34 template MXMLAttributeFunctions(CharT){ 35 CharT[] toCharTString(XMLAttributes attribs){ 36 CharT[] output = ""; 37 foreach(CharT[] name,CharT[] value; attribs){ 38 output ~= name ~ "=" ~ "\"" ~ value ~ "\"" ~ " "; 39 } 40 return output; 41 } 42 43 CharT[] toCharTString(CharT ch){ 44 CharT[] value; 45 value.length = 1; 46 value[0] = ch; 47 return value; 48 } 49 } trunk/xml/XMLException.d
r48 r69 26 26 module xml.XMLException; 27 27 28 private import xml.Position;29 private import xml.BaseParser;30 private import xml.BaseLexer;31 private import xml.ILexerStream;32 33 28 private import std.string; 34 35 //TODO: add chaining, named streams and references to originating lexer36 29 37 30 class XMLException : Exception{ … … 52 45 } 53 46 } 54 55 class XMLLexerException : XMLException{56 public BaseLexer lex;57 public Position pos;58 public char[] streamName;59 60 public this(BaseLexer lex,ILexerStream stream,char[] reason){61 super(reason);62 this.lex = lex;63 pos = stream.getPosition();64 streamName = stream.getStreamName();65 }66 67 public this(Exception cause,BaseLexer lex,ILexerStream stream,char[] reason){68 super(cause,reason);69 this.lex = lex;70 pos = stream.getPosition();71 streamName = stream.getStreamName();72 }73 74 public char[] toString(){75 return format("%s (%d,%d): %s\nToken Dump:\n%s",streamName,pos.row,pos.col,super.toString(),lex.toString());76 }77 }78 79 class XMLParserException : XMLException{80 public BaseParser parser;81 public Position pos;82 public char[] streamName;83 84 public this(BaseParser parser,Position pos,char[] reason){85 super(reason);86 this.parser = parser;87 this.pos = pos;88 streamName = parser.getStreamName();89 }90 91 public this(Exception cause,BaseParser parser,Position pos,char[] reason){92 super(cause,reason);93 this.parser = parser;94 this.pos = pos;95 streamName = parser.getStreamName();96 }97 98 public char[] toString(){99 return format("%s (%d,%d): %s\nToken Dump:\n%s",streamName,pos.row,pos.col,super.toString(),parser.toString());100 }101 }trunk/xml/XMLParser.d
r48 r69 26 26 module xml.XMLParser; 27 27 28 private import xml.IXMLConsumer; 28 29 private import xml.IXMLProvider; 29 private import xml.IXMLConsumer;30 private import xml.ILexerStream;31 private import xml.XMLLexer;32 private import xml.XMLToken;33 private import xml.BaseLexer;34 private import xml.BaseParser;35 private import xml.XMLException;36 private import xml.DTDParser;37 private import xml.SimpleStream;38 30 private import xml.OfflineProvider; 39 31 private import xml.XMLAttributes; 40 41 private import std.string; 42 43 /* 44 - string-content is not validated. 45 -attribute ordering for certain situations is not validated. 46 TODO: note that all content is assumed UTF8 or converted to UTF8 prior to parsing 47 48 */ 49 50 class XMLParser : BaseParser{ 51 protected BaseLexer getLexer(){ 52 return new XMLLexer(); 53 } 54 55 protected void startParse(){ 56 getNext(TokStartElem); 57 58 if(peek().type == TokQuestion){ 59 parseProlog(); 60 } 61 parseMisc(); 62 63 if(peek().type == TokName){ 64 parseElement(); 65 } 66 parseMisc(); 67 } 68 69 protected void parseProlog(){ 70 /* 71 [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? 72 [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' 73 [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') 74 [25] Eq ::= S? '=' S? 75 [26] VersionNum ::= '1.0' 76 */ 77 78 //?xml 79 getNext(TokQuestion); 80 if(std.string.tolower(getNext().value) != "xml"){ 81 throw new XMLParserException(this,peek().pos,"document prolog must begin with an 'xml' processing instruction"); 82 } 83 84 getNext(TokSpace); 85 86 // attribs 87 consumer.xmlProlog(parseAttributes()); 88 89 // ?> 90 getNext(TokQuestion); 91 getNext(TokEndElem); 92 93 parseMisc(); 94 95 if(peek().type == TokBang){ 96 getNext(); // eat token 97 parseDoctype(); 98 } 99 } 100 101 protected void parseMisc(){ 102 /* 103 [27] Misc ::= Comment | PI | S 104 */ 32 private import xml.Position; 33 34 private import std.utf; 35 private import std.stdio; 36 37 class XMLParser(CharT){ 38 mixin MXMLAttribute!(CharT); 39 mixin MXMLAttributeFunctions!(CharT); 40 41 IXMLConsumer!(CharT) consumer; 42 IXMLProvider!(CharT) provider; 43 CharT[] source; 44 uint cursor; 45 Position pos; 46 Position lastPosition; 47 48 /+++ public parser +++/ 49 50 public void parse(IXMLConsumer!(CharT) consumer,CharT[] source){ 51 parse(consumer,new OfflineProvider!(CharT),source); 52 } 53 54 public void parse(IXMLConsumer!(CharT) consumer,IXMLProvider!(CharT) provider,CharT[] source){ 55 this.consumer = consumer; 56 this.source = source; 57 this.provider = provider; 58 cursor = 0; 59 pos.offset = 0; 60 pos.line = 1; 61 pos.column = 1; 62 lastPosition = pos; 63 64 debug printf("xml: %.*s",source); 65 66 parseContent(true); 67 } 68 69 public Position getPosition(){ 70 return pos; 71 } 72 73 public Position getLastPosition(){ 74 return lastPosition; 75 } 76 77 78 /+++ exception handler +++/ 79 80 protected void exception(CharT[] value){ 81 throw new Exception(lastPosition.toString() ~ " - " ~ toUTF8(value)); 82 } 83 84 /+++ lexer rules +++/ 85 86 protected bit hasMore(){ 87 return cursor < source.length; 88 } 89 90 protected CharT getNext(CharT match=0){ 91 if(!hasMore()) return '\0'; // exception("unexpected EOF"); 92 CharT next = source[cursor]; 93 if(match != 0 && next != match){ 94 exception("unexpected token (expected '" ~ toCharTString(match) ~ "' not '" ~ toCharTString(next) ~ "')"); 95 } 96 cursor++; 97 if(cursor == '\n'){ 98 pos.line++; 99 pos.column = 1; 100 } 101 else{ 102 pos.column++; 103 } 104 pos.offset=cursor; 105 //writefln("getNext: '%c'",next); 106 return next; 107 } 108 109 protected CharT peek(){ 110 if(!hasMore()) return '\0'; 111 return source[cursor]; 112 } 113 114 protected CharT[] getUntil(CharT[] match){ 115 uint start = cursor; 105 116 while(hasMore()){ 106 switch(peek().type){ 107 case TokSpace: 108 getNext(); // eat whitespace 109 break; 110 111 case TokComment: 112 consumer.xmlComment(getNext().value); 113 break; 114 115 case TokStartElem: 116 getNext(); // eat '<' token 117 if(peek().type == TokQuestion){ 118 getNext(); // eat '?' token 119 parseProcessingInstruction(); 120 break; 117 if(source[cursor..cursor+match.length] == match){ 118 return source[start..cursor]; 119 } 120 getNext(); 121 } 122 return null; // dummy 123 } 124 125 protected CharT[] parseWhitespace(bit required){ 126 uint start = cursor; 127 if(required && peek() > 32) exception("expected whitespace"); 128 while(hasMore() && peek() <= 32){ 129 getNext(); 130 } 131 return source[start..cursor]; 132 } 133 134 protected CharT[] contentGetNext(){ 135 uint start = cursor; 136 while(hasMore()){ 137 CharT ch = peek(); 138 if(ch == '&' || ch == '<' || ch == ']'){ 139 if(start == cursor) getNext(); 140 return source[start..cursor]; 141 } 142 getNext(); 143 } 144 return null; // dummy 145 } 146 147 protected bit isDTDExpressionChar(CharT ch){ 148 return 149 ch == '&' || ch == '|' || ch == '*' || ch == '+' || 150 ch == '(' || ch == ')' || ch == ',' || ch == '&' || 151 ch == '%' 152 ; 153 } 154 155 protected bit isElementChar(CharT ch){ 156 return 157 ch == '?' || ch == '!' || ch == '=' || ch == '\'' || 158 ch == '\"' || ch == '>' || ch == '<' || 159 ch == '[' || ch == ']' || ch == '/' || //ch == '-' || 160 isDTDExpressionChar(ch); 161 ; 162 } 163 164 protected CharT[] elementGetNext(){ 165 uint start = cursor; 166 while(hasMore()){ 167 CharT ch = peek(); 168 if(ch <= 32 || isElementChar(ch)){ 169 if(start == cursor) getNext(); 170 return source[start..cursor]; 171 } 172 getNext(); 173 } 174 return null; // dummy 175 } 176 177 /+++ Parser +++/ 178 179 protected void parseEntity(){ 180 consumer.xmlText(getUntil(";"),TextType.EntityText); 181 getNext(); 182 } 183 184 protected CharT[] parseString(){ 185 CharT[] value; 186 lastPosition = pos; 187 CharT delim = getNext(); 188 189 if(delim == '\'' || delim == '\"'){ 190 while(hasMore()){ 191 CharT tok = getNext(); 192 if(tok == delim) break; 193 else if(tok == '&'){ 194 value ~= consumer.getEntityValue(getUntil(";"),true); 195 getNext(); 121 196 } 122 197 else{ 123 return; // something other than a PI, let parent worry about it198 value ~= tok; 124 199 } 125 break; 126 127 default: 128 return; // let parent worry about it 129 } 130 } 131 } 132 133 protected void parseDoctype(){ 134 /* 135 [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' [VC: Root Element Type][WFC: External Subset] 136 [28a] DeclSep ::= PEReference | S [WFC: PE Between Declarations] 137 [28b] intSubset ::= (markupdecl | DeclSep)* 138 [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment [VC: Proper Declaration/PE Nesting][WFC: PEs in Internal Subset] 139 [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral 140 */ 141 char[] name,pubidLiteral,systemLiteral; 142 143 getNext(TokName,"DOCTYPE"); 144 getNextOptional(TokSpace); 145 146 name = getNext(TokName).value; 147 getNextOptional(TokSpace); 148 149 if(peek().type == TokName){ 150 ILexerStream newStream = parseExternalID(); 151 152 if(newStream){ 153 // check for non-empty stream 154 if(newStream.hasMore()){ 155 //parse against DTD 156 DTDParser parser = new DTDParser(); 157 parser.parse(consumer,provider,newStream); 158 159 //copy any useful bits 160 copyParserData(parser); 161 } 162 } 163 else{ 164 throw new XMLParserException(this,peek().pos,"could not resolve external DTD"); 165 } 166 167 getNextOptional(TokSpace); 168 } 169 170 consumer.xmlStartDoctype(name); 171 172 // parse all the elements under the doctype 173 if(peek().type == TokDTD){ 174 SimpleStream newStream = new SimpleStream(getNext().value); 175 DTDParser parser; 176 try{ 177 parser = new DTDParser(); 178 parser.parse(consumer,provider,newStream); 179 } 180 catch(XMLException e){ 181 throw new XMLParserException(e,this,peek().pos,"Error in parsing DTD"); 182 } 183 184 //copy any useful bits 185 copyParserData(parser); 186 getNextOptional(TokSpace); 187 } 188 189 getNext(TokEndElem); 190 191 consumer.xmlEndDoctype(name); 192 } 193 194 protected ILexerStream parseExternalID(){ 195 char[] pubidLiteral; 196 char[] systemLiteral; 197 198 if(peek().value == "SYSTEM"){ 199 pubidLiteral = ""; // empty value 200 getNext(); // eat token 201 getNext(TokSpace); 202 systemLiteral = parseString(); 203 } 204 else if(peek().value == "PUBLIC"){ 205 getNext(); // eat token 206 getNext(TokSpace); 207 pubidLiteral = parseString(); 208 getNext(TokSpace); 209 systemLiteral = parseString(); 200 } 210 201 } 211 202 else{ 212 throw new XMLParserException(this,peek().pos,"document external identity must begin with 'PUBLIC' or 'SYSTEM'"); 213 } 214 215 return provider.resolveExternalID(pubidLiteral,systemLiteral); 216 } 217 218 protected void parseElement(){ 219 char[] name; 220 XMLAttributes attribs; 221 222 name = getNext(TokName).value; 223 224 attribs = parseAttributes(); 225 getNextOptional(TokSpace); 226 227 if(peek().type == TokSlash){ 228 getNext(); // eat token 229 getNext(TokEndElem); 230 consumer.xmlStartElement(name,attribs,true); 231 consumer.xmlEndElement(name,attribs,true); 232 } 233 else{ 234 getNext(TokEndElem); 235 consumer.xmlStartElement(name,attribs,false); 236 237 parseElementContent(); 238 239 getNext(TokSlash); 240 getNext(TokName,name); 241 getNextOptional(TokSpace); 242 getNext(TokEndElem); 243 244 consumer.xmlEndElement(name,attribs,false); 245 } 246 } 247 248 protected void parseElementContent(){ 203 exception("Expected ' or \""); 204 } 205 return value; 206 } 207 208 protected void parseContent(bit isTopLevel=false,bit isDTD=false){ 249 209 while(hasMore()){ 250 switch(peek().type){ 251 case TokStartElem: 252 getNext(); // eat token 253 254 if(peek().type == TokSlash){ 210 lastPosition = pos; 211 CharT[] tok = contentGetNext(); 212 switch(tok){ 213 case "<": 214 if(peek() == '/'){ 215 if(isTopLevel) exception("tag closed out of sequence"); 255 216 return; // end parsing the content, as the tag is ending 256 217 } … … 260 221 break; 261 222 262 case TokEntity: 263 consumer.xmlText(parseEntity()); 264 break; 265 266 case TokSpace: 267 case TokChars: 268 consumer.xmlText(getNext().value); 223 case "&": 224 parseEntity(); 225 break; 226 227 case "]": 228 if(isDTD) return; 229 // fallthrough 230 231 default: 232 consumer.xmlText(tok,TextType.NormalText); 233 break; 234 } 235 } 236 } 237 238 /+++ DTD Parsers +++/ 239 protected void parseElement(){ 240 switch(peek()){ 241 case '!': 242 getNext(); 243 if(peek() == '-'){ // comment 244 getNext(); 245 getNext('-'); 246 consumer.xmlComment(getUntil("--")); 247 getNext(); 248 getNext(); 249 getNext('>'); 269 250 break; 251 } 252 253 CharT[] tok = elementGetNext(); 254 switch(tok){ 255 case "DOCTYPE": 256 parseWhitespace(true); 257 parseDTDDoctype(); 258 break; 259 260 case "ELEMENT": 261 parseWhitespace(true); 262 parseDTDElement(); 263 break; 264 265 case "ATTLIST": 266 parseWhitespace(true); 267 parseDTDAttlist(); 268 break; 269 270 case "ENTITY": 271 parseWhitespace(true); 272 parseDTDEntity(); 273 break; 274 275 case "NOTATION": 276 parseWhitespace(true); 277 parseDTDNotation(); 278 break; 279 280 default: 281 exception("Unknown DTD element: <!" ~ tok ~ ">"); 282 283 //recovery 284 getUntil(">"); 285 getNext(); 286 } 287 break; 288 289 case '?': 290 getNext(); 291 parseProcessingInstruction(); 292 break; 293 294 case '[': 295 getNext(); 296 parseCDATA(); 297 break; 298 299 default: 300 parseStandardElement(); 301 } 302 } 303 304 305 /+++ DTD parsers +++/ 306 307 protected void parseDTDDoctype(){ 308 CharT[] name = elementGetNext(); 309 parseWhitespace(true); 310 311 XMLAttributes externalID; 312 if(peek() != '[' && peek() != '>'){ 313 externalID = parseExternalId(); 314 315 CharT[] externalDTD = provider.resolveExternalID(externalID["PUBLIC"],externalID["SYSTEM"]); 316 317 // parse the external DTD through a new parser (using the same callbacks) 318 //XMLParserBase!(wchar) parser = new XMLParserBase!(CharT)(); 319 //parser.parse(consumer,provider,externalDTD); 320 321 parseWhitespace(false); 322 } 323 324 consumer.xmlStartDTD(name,externalID); 325 326 if(peek() == '['){ 327 getNext(); 328 parseContent(false,true); 329 parseWhitespace(false); 330 } 331 332 getNext('>'); 333 consumer.xmlEndDTD(name,externalID); 334 } 335 336 protected void parseDTDElement(){ 337 CharT[] name = elementGetNext(); 338 parseWhitespace(true); 339 340 consumer.xmlStartDTDElement(name); 341 342 //TODO: assume more responsibility than this 343 while(hasMore() && peek() != '>'){ 344 CharT ch = peek(); 345 if(isDTDExpressionChar(ch)){ 346 consumer.xmlSetDTDElementOperation(name,cast(IXMLConsumer!(CharT).DTDOperation)getNext()); 347 } 348 else if(isElementChar(ch)){ 349 exception("unexpected token '" ~ toCharTString(ch) ~ "'"); 350 } 351 else{ 352 consumer.xmlSetDTDElementChild(name,elementGetNext()); 353 } 354 parseWhitespace(false); 355 } 356 357 consumer.xmlEndDTDElement(name); 358 359 getNext('>'); 360 } 361 362 protected void parseDTDAttlist(){ 363 CharT[] name = elementGetNext(); 364 parseWhitespace(true); 365 366 consumer.xmlStartDTDAttlist(name); 367 368 while(hasMore() && peek() != '>'){ 369 CharT[] attName = elementGetNext(); 370 parseWhitespace(true); 371 372 //TODO: this needs help for parsing notations and enumerations 373 CharT[] attType = elementGetNext(); 374 parseWhitespace(true); 375 376 CharT[] defaultValue = elementGetNext(); 377 parseWhitespace(false); 378 379 consumer.xmlSetDTDAttlistDef(name,attName,attType,defaultValue); 380 } 381 382 consumer.xmlEndDTDAttlist(name); 383 getNext('>'); 384 } 385 386 protected void parseDTDEntity(){ 387 if(peek() == '%'){ 388 getNext(); 389 parseWhitespace(true); 390 391 CharT[] name = elementGetNext(); 392 parseWhitespace(true); 393 394 CharT ch = peek(); 395 if(ch == '\'' || ch == '"'){ 396 CharT[] value = parseString(); 397 consumer.xmlSetDTDEntity(name,value,null,true); 398 } 399 else{ 400 XMLAttributes externalId = parseExternalId(); 270 401 271 case TokComment:272 consumer.xmlComment(getNext().value);273 break;402 //TODO: chase down the externalId via provider and a custom consumer that will capture the needed entity def 403 CharT[] value; 404 consumer.xmlSetDTDEntity(name,value,null,true); 274 405 275 default: 276 getNext(TokNull); // force error 277 break; 278 } 279 } 280 } 281 282 protected void parseProcesingInstruction(){ 283 char[] name,data; 284 285 name = getNext(TokName).value; 286 getNext(TokSpace); 287 288 if(tolower(name) == "xml"){ 289 throw new XMLParserException(this,peek().pos,"processing instruction 'xml' not allowed outside the prolog"); 290 } 291 data = getNext(TokChars).value; 292 293 getNext(TokQuestion); 294 getNext(TokEndElem); 295 296 consumer.xmlProcessingInstruction(name,data); 297 } 298 406 parseWhitespace(false); 407 } 408 } 409
