mirror of
https://github.com/vlang/v.git
synced 2025-08-04 02:07:28 -04:00
97 lines
2.5 KiB
V
97 lines
2.5 KiB
V
module xml
|
|
|
|
fn (node XMLNode) validate(elements map[string]DTDElement, entities map[string]string) !XMLNode {
|
|
mut children := []XMLNodeContents{cap: node.children.len}
|
|
|
|
valid_elements := elements[node.name].definition
|
|
mut validate_node_children := node.name in elements
|
|
|
|
// Check if the node will match everything
|
|
if valid_elements.len == 1 && valid_elements[0] == '#PCDATA' {
|
|
validate_node_children = false
|
|
}
|
|
|
|
for child in node.children {
|
|
match child {
|
|
XMLNode {
|
|
if validate_node_children {
|
|
name := child.name
|
|
if name !in valid_elements {
|
|
return error('Invalid child element ${name} for ${node.name}')
|
|
}
|
|
}
|
|
children << child.validate(elements, entities)!
|
|
}
|
|
string {
|
|
children << unescape_text(child, entities: entities)!
|
|
}
|
|
else {
|
|
// Ignore other nodes
|
|
children << child
|
|
}
|
|
}
|
|
}
|
|
|
|
return XMLNode{
|
|
name: node.name
|
|
attributes: node.attributes
|
|
children: children
|
|
}
|
|
}
|
|
|
|
// validate checks the document is well-formed and valid. It returns a new
|
|
// document with the parsed entities expanded when validation is successful.
|
|
// Otherwise it returns an error.
|
|
pub fn (doc XMLDocument) validate() !XMLDocument {
|
|
// The document is well-formed because we were able to parse it properly.
|
|
match doc.doctype.dtd {
|
|
DocumentTypeDefinition {
|
|
// Store the element and entity definitions
|
|
mut elements := map[string]DTDElement{}
|
|
mut entities := default_entities.clone()
|
|
mut reverse_entities := default_entities_reverse.clone()
|
|
|
|
for item in doc.doctype.dtd.list {
|
|
match item {
|
|
DTDElement {
|
|
name := item.name
|
|
if name in elements {
|
|
return error('Duplicate element definition for ${name}')
|
|
}
|
|
elements[name] = item
|
|
}
|
|
DTDEntity {
|
|
name := item.name
|
|
if name in entities {
|
|
return error('Duplicate entity definition for ${name}')
|
|
}
|
|
entities[name] = item.value
|
|
reverse_entities[item.value] = name
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now validate the document against the elements and entities.
|
|
new_root := doc.root.validate(elements, entities)!
|
|
|
|
// Check the DOCTYPE name matches the root name
|
|
if doc.doctype.name.len > 0 && doc.doctype.name != new_root.name {
|
|
return error('Root element ${new_root.name} does not match DOCTYPE ${doc.doctype.name}')
|
|
}
|
|
|
|
return XMLDocument{
|
|
version: doc.version
|
|
encoding: doc.encoding
|
|
doctype: doc.doctype
|
|
comments: doc.comments
|
|
root: new_root
|
|
parsed_reverse_entities: reverse_entities
|
|
}
|
|
}
|
|
string {
|
|
// TODO: Validate the document against the DTD string.
|
|
return doc
|
|
}
|
|
}
|
|
}
|