This commit is contained in:
@@ -39,16 +39,16 @@ pub type Element {
|
|||||||
|
|
||||||
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 ha' battr='baba' ref='&ref;'/>",
|
"<?xml version=\"1.1\" encoding='UTF-8'?>\r\n <!-- hello-world --> \n<a attr='ha &#38;ha' battr='baba' ref='&'/>",
|
||||||
)
|
)
|
||||||
|> echo
|
|> echo
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_entities() -> dict.Dict(String, Entity) {
|
pub fn default_entities() -> dict.Dict(String, Entity) {
|
||||||
dict.from_list([
|
dict.from_list([
|
||||||
#("lt", InternalEntity("&#60;")),
|
#("lt", InternalEntity("<")),
|
||||||
#("gt", InternalEntity("#62;")),
|
#("gt", InternalEntity(">")),
|
||||||
#("amp", InternalEntity("&#38;")),
|
#("amp", InternalEntity("&")),
|
||||||
#("apos", InternalEntity("'")),
|
#("apos", InternalEntity("'")),
|
||||||
#("quot", InternalEntity(""")),
|
#("quot", InternalEntity(""")),
|
||||||
])
|
])
|
||||||
@@ -60,7 +60,7 @@ fn parse_document(doc: String) -> Result(Document, Nil) {
|
|||||||
use #(element, doc) <- result.try(parse_element(doc, doctype))
|
use #(element, doc) <- result.try(parse_element(doc, doctype))
|
||||||
let doc = parse_misc(doc)
|
let doc = parse_misc(doc)
|
||||||
|
|
||||||
case doc |> echo {
|
case doc {
|
||||||
"" -> Ok(Document(decl, doctype, Some(element)))
|
"" -> Ok(Document(decl, doctype, Some(element)))
|
||||||
_ -> Error(Nil)
|
_ -> Error(Nil)
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ fn parse_empty_elem(
|
|||||||
doc: String,
|
doc: String,
|
||||||
doctype: Option(DocType),
|
doctype: Option(DocType),
|
||||||
) -> Result(#(Element, String), Nil) {
|
) -> Result(#(Element, String), Nil) {
|
||||||
case doc |> echo {
|
case doc {
|
||||||
"<" <> tail -> {
|
"<" <> tail -> {
|
||||||
use #(name, doc) <- result.try(parse_name(tail))
|
use #(name, doc) <- result.try(parse_name(tail))
|
||||||
use #(attrs, doc) <- result.try(parse_attributes(doc, doctype, []))
|
use #(attrs, doc) <- result.try(parse_attributes(doc, doctype, []))
|
||||||
@@ -184,19 +184,19 @@ fn parse_reference(
|
|||||||
";" <> tail -> {
|
";" <> tail -> {
|
||||||
use value <- result.try(int.base_parse(digits, 16))
|
use value <- result.try(int.base_parse(digits, 16))
|
||||||
use codepoint <- result.try(string.utf_codepoint(value))
|
use codepoint <- result.try(string.utf_codepoint(value))
|
||||||
Ok(#("", string.from_utf_codepoints([codepoint]) <> tail))
|
Ok(#(string.from_utf_codepoints([codepoint]), tail))
|
||||||
}
|
}
|
||||||
_ -> Error(Nil)
|
_ -> Error(Nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ -> {
|
_ -> {
|
||||||
use #(digits, doc) <- result.try(parse_multiple(tail, parse_digit))
|
use #(digits, doc) <- result.try(parse_multiple(tail, parse_digit))
|
||||||
|
|
||||||
case doc {
|
case doc {
|
||||||
";" <> tail -> {
|
";" <> tail -> {
|
||||||
use value <- result.try(int.base_parse(digits, 10))
|
use value <- result.try(int.base_parse(digits, 10))
|
||||||
use codepoint <- result.try(string.utf_codepoint(value))
|
use codepoint <- result.try(string.utf_codepoint(value))
|
||||||
Ok(#("", string.from_utf_codepoints([codepoint]) <> tail))
|
|
||||||
|
Ok(#(string.from_utf_codepoints([codepoint]), tail))
|
||||||
}
|
}
|
||||||
_ -> Error(Nil)
|
_ -> Error(Nil)
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,10 @@ fn parse_reference(
|
|||||||
use #(name, doc) <- result.try(parse_name(tail))
|
use #(name, doc) <- result.try(parse_name(tail))
|
||||||
|
|
||||||
case doc {
|
case doc {
|
||||||
";" <> tail -> Ok(#(char <> name <> ";", tail))
|
";" <> tail -> {
|
||||||
|
use value <- result.try(process_reference(name, doctype))
|
||||||
|
Ok(#("", value <> tail))
|
||||||
|
}
|
||||||
_ -> Error(Nil)
|
_ -> Error(Nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,6 +218,36 @@ fn parse_reference(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_reference(
|
||||||
|
ref: String,
|
||||||
|
doctype: Option(DocType),
|
||||||
|
) -> Result(String, Nil) {
|
||||||
|
case doctype {
|
||||||
|
Some(DocType(_, entities)) -> {
|
||||||
|
get_reference(entities, ref)
|
||||||
|
}
|
||||||
|
None -> {
|
||||||
|
get_reference(default_entities(), ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_reference(
|
||||||
|
entities: dict.Dict(String, Entity),
|
||||||
|
ref: String,
|
||||||
|
) -> Result(String, Nil) {
|
||||||
|
case dict.get(entities, ref) {
|
||||||
|
Ok(InternalEntity(val)) -> Ok(val)
|
||||||
|
Ok(PublicExternalEntity(_, _)) | Ok(SystemExternalEntity(_)) -> Error(Nil)
|
||||||
|
Error(_) -> {
|
||||||
|
case entities == default_entities() {
|
||||||
|
True -> Error(Nil)
|
||||||
|
False -> get_reference(default_entities(), ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_name(doc: String) -> Result(#(String, String), Nil) {
|
fn parse_name(doc: String) -> Result(#(String, String), Nil) {
|
||||||
case parse_name_start_char(doc) {
|
case parse_name_start_char(doc) {
|
||||||
Ok(#(char, tail)) -> {
|
Ok(#(char, tail)) -> {
|
||||||
|
|||||||
Reference in New Issue
Block a user