lex.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // Package xml is an XML1.0 lexer following the specifications at http://www.w3.org/TR/xml/.
  2. package xml // import "github.com/tdewolff/parse/xml"
  3. import (
  4. "io"
  5. "strconv"
  6. "github.com/tdewolff/parse"
  7. "github.com/tdewolff/parse/buffer"
  8. )
  9. // TokenType determines the type of token, eg. a number or a semicolon.
  10. type TokenType uint32
  11. // TokenType values.
  12. const (
  13. ErrorToken TokenType = iota // extra token when errors occur
  14. CommentToken
  15. DOCTYPEToken
  16. CDATAToken
  17. StartTagToken
  18. StartTagPIToken
  19. StartTagCloseToken
  20. StartTagCloseVoidToken
  21. StartTagClosePIToken
  22. EndTagToken
  23. AttributeToken
  24. TextToken
  25. )
  26. // String returns the string representation of a TokenType.
  27. func (tt TokenType) String() string {
  28. switch tt {
  29. case ErrorToken:
  30. return "Error"
  31. case CommentToken:
  32. return "Comment"
  33. case DOCTYPEToken:
  34. return "DOCTYPE"
  35. case CDATAToken:
  36. return "CDATA"
  37. case StartTagToken:
  38. return "StartTag"
  39. case StartTagPIToken:
  40. return "StartTagPI"
  41. case StartTagCloseToken:
  42. return "StartTagClose"
  43. case StartTagCloseVoidToken:
  44. return "StartTagCloseVoid"
  45. case StartTagClosePIToken:
  46. return "StartTagClosePI"
  47. case EndTagToken:
  48. return "EndTag"
  49. case AttributeToken:
  50. return "Attribute"
  51. case TextToken:
  52. return "Text"
  53. }
  54. return "Invalid(" + strconv.Itoa(int(tt)) + ")"
  55. }
  56. ////////////////////////////////////////////////////////////////
  57. // Lexer is the state for the lexer.
  58. type Lexer struct {
  59. r *buffer.Lexer
  60. err error
  61. inTag bool
  62. text []byte
  63. attrVal []byte
  64. }
  65. // NewLexer returns a new Lexer for a given io.Reader.
  66. func NewLexer(r io.Reader) *Lexer {
  67. return &Lexer{
  68. r: buffer.NewLexer(r),
  69. }
  70. }
  71. // Err returns the error encountered during lexing, this is often io.EOF but also other errors can be returned.
  72. func (l *Lexer) Err() error {
  73. err := l.r.Err()
  74. if err != nil {
  75. return err
  76. }
  77. return l.err
  78. }
  79. // Restore restores the NULL byte at the end of the buffer.
  80. func (l *Lexer) Restore() {
  81. l.r.Restore()
  82. }
  83. // Next returns the next Token. It returns ErrorToken when an error was encountered. Using Err() one can retrieve the error message.
  84. func (l *Lexer) Next() (TokenType, []byte) {
  85. l.text = nil
  86. var c byte
  87. if l.inTag {
  88. l.attrVal = nil
  89. for { // before attribute name state
  90. if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' {
  91. l.r.Move(1)
  92. continue
  93. }
  94. break
  95. }
  96. if c == 0 {
  97. l.err = parse.NewErrorLexer("unexpected null character", l.r)
  98. return ErrorToken, nil
  99. } else if c != '>' && (c != '/' && c != '?' || l.r.Peek(1) != '>') {
  100. return AttributeToken, l.shiftAttribute()
  101. }
  102. start := l.r.Pos()
  103. l.inTag = false
  104. if c == '/' {
  105. l.r.Move(2)
  106. l.text = l.r.Lexeme()[start:]
  107. return StartTagCloseVoidToken, l.r.Shift()
  108. } else if c == '?' {
  109. l.r.Move(2)
  110. l.text = l.r.Lexeme()[start:]
  111. return StartTagClosePIToken, l.r.Shift()
  112. } else {
  113. l.r.Move(1)
  114. l.text = l.r.Lexeme()[start:]
  115. return StartTagCloseToken, l.r.Shift()
  116. }
  117. }
  118. for {
  119. c = l.r.Peek(0)
  120. if c == '<' {
  121. if l.r.Pos() > 0 {
  122. return TextToken, l.r.Shift()
  123. }
  124. c = l.r.Peek(1)
  125. if c == '/' {
  126. l.r.Move(2)
  127. return EndTagToken, l.shiftEndTag()
  128. } else if c == '!' {
  129. l.r.Move(2)
  130. if l.at('-', '-') {
  131. l.r.Move(2)
  132. return CommentToken, l.shiftCommentText()
  133. } else if l.at('[', 'C', 'D', 'A', 'T', 'A', '[') {
  134. l.r.Move(7)
  135. return CDATAToken, l.shiftCDATAText()
  136. } else if l.at('D', 'O', 'C', 'T', 'Y', 'P', 'E') {
  137. l.r.Move(8)
  138. return DOCTYPEToken, l.shiftDOCTYPEText()
  139. }
  140. l.r.Move(-2)
  141. } else if c == '?' {
  142. l.r.Move(2)
  143. l.inTag = true
  144. return StartTagPIToken, l.shiftStartTag()
  145. }
  146. l.r.Move(1)
  147. l.inTag = true
  148. return StartTagToken, l.shiftStartTag()
  149. } else if c == 0 {
  150. if l.r.Pos() > 0 {
  151. return TextToken, l.r.Shift()
  152. }
  153. l.err = parse.NewErrorLexer("unexpected null character", l.r)
  154. return ErrorToken, nil
  155. }
  156. l.r.Move(1)
  157. }
  158. }
  159. // Text returns the textual representation of a token. This excludes delimiters and additional leading/trailing characters.
  160. func (l *Lexer) Text() []byte {
  161. return l.text
  162. }
  163. // AttrVal returns the attribute value when an AttributeToken was returned from Next.
  164. func (l *Lexer) AttrVal() []byte {
  165. return l.attrVal
  166. }
  167. ////////////////////////////////////////////////////////////////
  168. // The following functions follow the specifications at http://www.w3.org/html/wg/drafts/html/master/syntax.html
  169. func (l *Lexer) shiftDOCTYPEText() []byte {
  170. inString := false
  171. inBrackets := false
  172. for {
  173. c := l.r.Peek(0)
  174. if c == '"' {
  175. inString = !inString
  176. } else if (c == '[' || c == ']') && !inString {
  177. inBrackets = (c == '[')
  178. } else if c == '>' && !inString && !inBrackets {
  179. l.text = l.r.Lexeme()[9:]
  180. l.r.Move(1)
  181. return l.r.Shift()
  182. } else if c == 0 {
  183. l.text = l.r.Lexeme()[9:]
  184. return l.r.Shift()
  185. }
  186. l.r.Move(1)
  187. }
  188. }
  189. func (l *Lexer) shiftCDATAText() []byte {
  190. for {
  191. c := l.r.Peek(0)
  192. if c == ']' && l.r.Peek(1) == ']' && l.r.Peek(2) == '>' {
  193. l.text = l.r.Lexeme()[9:]
  194. l.r.Move(3)
  195. return l.r.Shift()
  196. } else if c == 0 {
  197. l.text = l.r.Lexeme()[9:]
  198. return l.r.Shift()
  199. }
  200. l.r.Move(1)
  201. }
  202. }
  203. func (l *Lexer) shiftCommentText() []byte {
  204. for {
  205. c := l.r.Peek(0)
  206. if c == '-' && l.r.Peek(1) == '-' && l.r.Peek(2) == '>' {
  207. l.text = l.r.Lexeme()[4:]
  208. l.r.Move(3)
  209. return l.r.Shift()
  210. } else if c == 0 {
  211. return l.r.Shift()
  212. }
  213. l.r.Move(1)
  214. }
  215. }
  216. func (l *Lexer) shiftStartTag() []byte {
  217. nameStart := l.r.Pos()
  218. for {
  219. if c := l.r.Peek(0); c == ' ' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 {
  220. break
  221. }
  222. l.r.Move(1)
  223. }
  224. l.text = l.r.Lexeme()[nameStart:]
  225. return l.r.Shift()
  226. }
  227. func (l *Lexer) shiftAttribute() []byte {
  228. nameStart := l.r.Pos()
  229. var c byte
  230. for { // attribute name state
  231. if c = l.r.Peek(0); c == ' ' || c == '=' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 {
  232. break
  233. }
  234. l.r.Move(1)
  235. }
  236. nameEnd := l.r.Pos()
  237. for { // after attribute name state
  238. if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' {
  239. l.r.Move(1)
  240. continue
  241. }
  242. break
  243. }
  244. if c == '=' {
  245. l.r.Move(1)
  246. for { // before attribute value state
  247. if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' {
  248. l.r.Move(1)
  249. continue
  250. }
  251. break
  252. }
  253. attrPos := l.r.Pos()
  254. delim := c
  255. if delim == '"' || delim == '\'' { // attribute value single- and double-quoted state
  256. l.r.Move(1)
  257. for {
  258. c = l.r.Peek(0)
  259. if c == delim {
  260. l.r.Move(1)
  261. break
  262. } else if c == 0 {
  263. break
  264. }
  265. l.r.Move(1)
  266. if c == '\t' || c == '\n' || c == '\r' {
  267. l.r.Lexeme()[l.r.Pos()-1] = ' '
  268. }
  269. }
  270. } else { // attribute value unquoted state
  271. for {
  272. if c = l.r.Peek(0); c == ' ' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 {
  273. break
  274. }
  275. l.r.Move(1)
  276. }
  277. }
  278. l.attrVal = l.r.Lexeme()[attrPos:]
  279. } else {
  280. l.r.Rewind(nameEnd)
  281. l.attrVal = nil
  282. }
  283. l.text = l.r.Lexeme()[nameStart:nameEnd]
  284. return l.r.Shift()
  285. }
  286. func (l *Lexer) shiftEndTag() []byte {
  287. for {
  288. c := l.r.Peek(0)
  289. if c == '>' {
  290. l.text = l.r.Lexeme()[2:]
  291. l.r.Move(1)
  292. break
  293. } else if c == 0 {
  294. l.text = l.r.Lexeme()[2:]
  295. break
  296. }
  297. l.r.Move(1)
  298. }
  299. end := len(l.text)
  300. for end > 0 {
  301. if c := l.text[end-1]; c == ' ' || c == '\t' || c == '\n' || c == '\r' {
  302. end--
  303. continue
  304. }
  305. break
  306. }
  307. l.text = l.text[:end]
  308. return l.r.Shift()
  309. }
  310. ////////////////////////////////////////////////////////////////
  311. func (l *Lexer) at(b ...byte) bool {
  312. for i, c := range b {
  313. if l.r.Peek(i) != c {
  314. return false
  315. }
  316. }
  317. return true
  318. }