| 34 | | |
|---|
| 35 | | void xmlProlog(XMLAttributes attribs){} |
|---|
| 36 | | void xmlStartDoctype(char[] name){} |
|---|
| 37 | | void xmlEndDoctype(char[] name){} |
|---|
| 38 | | |
|---|
| 39 | | void xmlProcessingInstruction(char[] name,char[] data){} |
|---|
| 40 | | |
|---|
| 41 | | void xmlComment(char[] text){} |
|---|
| 42 | | |
|---|
| 43 | | void xmlStartElement(char[] name,XMLAttributes attribs,bit isEmpty){} |
|---|
| 44 | | void xmlEndElement(char[] name,XMLAttributes attribs,bit isEmpty){} |
|---|
| 45 | | void xmlText(char[] text){} |
|---|
| | 62 | |
|---|
| | 63 | private QName parseQName(char[] name){ |
|---|
| | 64 | QName newName; |
|---|
| | 65 | int split = find(name,":"); |
|---|
| | 66 | |
|---|
| | 67 | if(split>0){ |
|---|
| | 68 | newName.ns = name[0..split+1]; |
|---|
| | 69 | newName.local = name[split..name.length]; |
|---|
| | 70 | } |
|---|
| | 71 | return newName; |
|---|
| | 72 | } |
|---|
| | 73 | |
|---|
| | 74 | private void pushAttributes(XMLNSAttributes attribs){ |
|---|
| | 75 | push!(XMLNSAttributes)(tagAttributes,attribs); |
|---|
| | 76 | } |
|---|
| | 77 | |
|---|
| | 78 | private XMLNSAttributes popAttributes(){ |
|---|
| | 79 | return pop!(XMLNSAttributes)(tagAttributes); |
|---|
| | 80 | } |
|---|
| | 81 | |
|---|
| | 82 | private void pushTagname(QName tagname){ |
|---|
| | 83 | push!(QName)(tagNames,tagname); |
|---|
| | 84 | } |
|---|
| | 85 | |
|---|
| | 86 | private QName popTagname(){ |
|---|
| | 87 | return pop!(QName)(tagNames); |
|---|
| | 88 | } |
|---|
| | 89 | |
|---|
| | 90 | private void pushNamespace(char[] name, char[] value){ |
|---|
| | 91 | namespaces[name].length = namespaces[name].length + 1; |
|---|
| | 92 | namespaces[name][$-1] = value; |
|---|
| | 93 | } |
|---|
| | 94 | |
|---|
| | 95 | private void popNamespace(char[] name){ |
|---|
| | 96 | namespaces[name].length = namespaces[name].length - 1; |
|---|
| | 97 | } |
|---|
| | 98 | |
|---|
| | 99 | private char[] getNamespaceURI(char[] name){ |
|---|
| | 100 | if(name in namespaces){ |
|---|
| | 101 | return namespaces[name][$-1]; |
|---|
| | 102 | } |
|---|
| | 103 | return ""; |
|---|
| | 104 | } |
|---|
| | 105 | |
|---|
| | 106 | void xmlProlog(XMLAttributes attribs){ |
|---|
| | 107 | consumer.xmlProlog(attribs); |
|---|
| | 108 | } |
|---|
| | 109 | |
|---|
| | 110 | void xmlStartDoctype(char[] name){ |
|---|
| | 111 | consumer.xmlStartDoctype(name); |
|---|
| | 112 | } |
|---|
| | 113 | |
|---|
| | 114 | void xmlEndDoctype(char[] name){ |
|---|
| | 115 | consumer.xmlEndDoctype(name); |
|---|
| | 116 | } |
|---|
| | 117 | |
|---|
| | 118 | void xmlProcessingInstruction(char[] name,char[] data){ |
|---|
| | 119 | consumer.xmlProcessingInstruction(name,data); |
|---|
| | 120 | } |
|---|
| | 121 | |
|---|
| | 122 | void xmlComment(char[] text){ |
|---|
| | 123 | consumer.xmlComment(text); |
|---|
| | 124 | } |
|---|
| | 125 | |
|---|
| | 126 | void xmlStartElement(char[] name,XMLAttributes attribs,bit isEmpty){ |
|---|
| | 127 | XMLNSAttributes nsAttribs; |
|---|
| | 128 | |
|---|
| | 129 | foreach(char[] name, char[] value; attribs){ |
|---|
| | 130 | // handle default namespace |
|---|
| | 131 | if(name == "xmlns"){ |
|---|
| | 132 | pushNamespace("",value); |
|---|
| | 133 | consumer.xmlStartNamespace("",value); |
|---|
| | 134 | } |
|---|
| | 135 | |
|---|
| | 136 | // handle typical attribute |
|---|
| | 137 | else{ |
|---|
| | 138 | QName qname = parseQName(name); |
|---|
| | 139 | |
|---|
| | 140 | // handle namespace definition |
|---|
| | 141 | if(qname.ns == "xmlns"){ |
|---|
| | 142 | if(qname.local == "xmlns"){ |
|---|
| | 143 | throw new XMLException("Cannot redefine namespace 'xmlns'."); |
|---|
| | 144 | } |
|---|
| | 145 | else if(qname.local == ""){ |
|---|
| | 146 | throw new XMLException("Namespace definition incomplete, need name to follow 'xmlns:'"); |
|---|
| | 147 | } |
|---|
| | 148 | else{ |
|---|
| | 149 | // create namespace alias |
|---|
| | 150 | pushNamespace(qname.local,value); |
|---|
| | 151 | consumer.xmlStartNamespace(qname.local,value); |
|---|
| | 152 | } |
|---|
| | 153 | } |
|---|
| | 154 | |
|---|
| | 155 | // handle standard attribute, possibly with a namespace prefix |
|---|
| | 156 | else{ |
|---|
| | 157 | qname.ns = getNamespaceURI(qname.ns); |
|---|
| | 158 | nsAttribs[qname] = value; |
|---|
| | 159 | } |
|---|
| | 160 | } |
|---|
| | 161 | |
|---|
| | 162 | } |
|---|
| | 163 | pushAttributes(nsAttribs); |
|---|
| | 164 | |
|---|
| | 165 | // establish the namespace for the name |
|---|
| | 166 | QName tagname = parseQName(name); |
|---|
| | 167 | tagname.ns = getNamespaceURI(tagname.ns); |
|---|
| | 168 | pushTagname(tagname); |
|---|
| | 169 | |
|---|
| | 170 | // fire off consumer event |
|---|
| | 171 | consumer.xmlStartElement(tagname,nsAttribs,isEmpty); |
|---|
| | 172 | } |
|---|
| | 173 | |
|---|
| | 174 | void xmlEndElement(char[] name,XMLAttributes attribs,bit isEmpty){ |
|---|
| | 175 | // keep things symmetrical: fire element end first |
|---|
| | 176 | consumer.xmlEndElement(popTagname(),popAttributes(),isEmpty); |
|---|
| | 177 | |
|---|
| | 178 | // unwind all that was done with these attributes |
|---|
| | 179 | //TODO: get these in reverse order |
|---|
| | 180 | foreach(char[] name, char[] value; attribs){ |
|---|
| | 181 | // handle default namespace |
|---|
| | 182 | if(name == "xmlns"){ |
|---|
| | 183 | popNamespace(""); |
|---|
| | 184 | consumer.xmlEndNamespace("",value); |
|---|
| | 185 | } |
|---|
| | 186 | |
|---|
| | 187 | // handle typical attribute |
|---|
| | 188 | else{ |
|---|
| | 189 | QName qname = parseQName(name); |
|---|
| | 190 | |
|---|
| | 191 | // handle namespace definition |
|---|
| | 192 | if(qname.ns == "xmlns"){ |
|---|
| | 193 | // create namespace alias |
|---|
| | 194 | popNamespace(qname.local); |
|---|
| | 195 | consumer.xmlEndNamespace(qname.local,value); |
|---|
| | 196 | } |
|---|
| | 197 | } |
|---|
| | 198 | } |
|---|
| | 199 | |
|---|
| | 200 | } |
|---|
| | 201 | |
|---|
| | 202 | void xmlText(char[] text){ |
|---|
| | 203 | consumer.xmlText(text); |
|---|
| | 204 | } |
|---|