This commit is contained in:
		@@ -35,11 +35,12 @@ pub type Attribute {
 | 
				
			|||||||
pub type Element {
 | 
					pub type Element {
 | 
				
			||||||
  EmptyElem(name: String, attrs: List(Attribute))
 | 
					  EmptyElem(name: String, attrs: List(Attribute))
 | 
				
			||||||
  Element(name: String, attrs: List(Attribute), elements: List(Element))
 | 
					  Element(name: String, attrs: List(Attribute), elements: List(Element))
 | 
				
			||||||
 | 
					  Text(content: String)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn main() {
 | 
					pub fn main() {
 | 
				
			||||||
  parse_document(
 | 
					  parse_document(
 | 
				
			||||||
    "<?xml version=\"1.1\" encoding='UTF-8'?>\r\n   <!-- hello-world -->   \n<a attr='ha &#38;ha' battr='baba' ref='&'/>",
 | 
					    "<?xml version=\"1.1\" encoding='UTF-8'?>\r\n   <!-- hello-world -->   \n<b><a attr='ha &#38;ha' battr='baba' ref='&'/></b>",
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
  |> echo
 | 
					  |> echo
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -70,7 +71,10 @@ fn parse_element(
 | 
				
			|||||||
  doc: String,
 | 
					  doc: String,
 | 
				
			||||||
  doctype: Option(DocType),
 | 
					  doctype: Option(DocType),
 | 
				
			||||||
) -> Result(#(Element, String), Nil) {
 | 
					) -> Result(#(Element, String), Nil) {
 | 
				
			||||||
  try_parsers([parse_empty_elem(_, doctype)], doc)
 | 
					  try_parsers(
 | 
				
			||||||
 | 
					    [parse_empty_elem(_, doctype), parse_tagged_elem(_, doctype)],
 | 
				
			||||||
 | 
					    doc,
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_empty_elem(
 | 
					fn parse_empty_elem(
 | 
				
			||||||
@@ -91,6 +95,89 @@ fn parse_empty_elem(
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_tagged_elem(
 | 
				
			||||||
 | 
					  doc: String,
 | 
				
			||||||
 | 
					  doctype: Option(DocType),
 | 
				
			||||||
 | 
					) -> Result(#(Element, String), Nil) {
 | 
				
			||||||
 | 
					  case doc {
 | 
				
			||||||
 | 
					    "<" <> tail -> {
 | 
				
			||||||
 | 
					      use #(name, doc) <- result.try(parse_name(tail))
 | 
				
			||||||
 | 
					      use #(attrs, doc) <- result.try(parse_attributes(doc, doctype, []))
 | 
				
			||||||
 | 
					      let doc = trim_space(doc)
 | 
				
			||||||
 | 
					      case doc {
 | 
				
			||||||
 | 
					        ">" <> tail -> {
 | 
				
			||||||
 | 
					          use #(content, doc) <- result.try(parse_content(tail, doctype, []))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          case doc {
 | 
				
			||||||
 | 
					            "</" <> tail -> {
 | 
				
			||||||
 | 
					              use #(close_name, doc) <- result.try(parse_name(tail))
 | 
				
			||||||
 | 
					              let doc = trim_space(doc)
 | 
				
			||||||
 | 
					              case doc {
 | 
				
			||||||
 | 
					                ">" <> tail -> {
 | 
				
			||||||
 | 
					                  use <- bool.guard(
 | 
				
			||||||
 | 
					                    when: name != close_name,
 | 
				
			||||||
 | 
					                    return: Error(Nil),
 | 
				
			||||||
 | 
					                  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  Ok(#(Element(name, attrs, content), tail))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                _ -> Error(Nil)
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ -> Error(Nil)
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        _ -> Error(Nil)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    _ -> Error(Nil)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_content(
 | 
				
			||||||
 | 
					  doc: String,
 | 
				
			||||||
 | 
					  doctype: Option(DocType),
 | 
				
			||||||
 | 
					  content: List(Element),
 | 
				
			||||||
 | 
					) -> Result(#(List(Element), String), Nil) {
 | 
				
			||||||
 | 
					  use #(chardata, doc) <- result.try(parse_chardata(doc, doctype, ""))
 | 
				
			||||||
 | 
					  let new_content = case chardata {
 | 
				
			||||||
 | 
					    "" -> content
 | 
				
			||||||
 | 
					    _ -> [Text(chardata), ..content]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case doc {
 | 
				
			||||||
 | 
					    "<" <> _ -> {
 | 
				
			||||||
 | 
					      case try_parsers([parse_element(_, doctype)], doc) {
 | 
				
			||||||
 | 
					        Ok(#(element, doc)) -> parse_content(doc, doctype, [element, ..content])
 | 
				
			||||||
 | 
					        Error(_) -> Ok(#(list.reverse(new_content), doc))
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    _ -> Ok(#(list.reverse(new_content), doc))
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_chardata(
 | 
				
			||||||
 | 
					  doc: String,
 | 
				
			||||||
 | 
					  doctype: Option(DocType),
 | 
				
			||||||
 | 
					  chardata: String,
 | 
				
			||||||
 | 
					) -> Result(#(String, String), Nil) {
 | 
				
			||||||
 | 
					  case doc {
 | 
				
			||||||
 | 
					    "]]>" <> _ -> Error(Nil)
 | 
				
			||||||
 | 
					    "<" <> _ -> Ok(#(chardata, doc))
 | 
				
			||||||
 | 
					    "&" <> _ -> {
 | 
				
			||||||
 | 
					      use #(refval, doc) <- result.try(parse_reference(doc, doctype))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      parse_chardata(doc, doctype, chardata <> refval)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    "" -> Ok(#("", ""))
 | 
				
			||||||
 | 
					    _ -> {
 | 
				
			||||||
 | 
					      let assert Ok(#(char, tail)) = string.pop_grapheme(doc)
 | 
				
			||||||
 | 
					      parse_chardata(tail, doctype, chardata <> char)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn parse_attributes(
 | 
					fn parse_attributes(
 | 
				
			||||||
  doc: String,
 | 
					  doc: String,
 | 
				
			||||||
  doctype: Option(DocType),
 | 
					  doctype: Option(DocType),
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user