mirror of
https://github.com/vlang/v.git
synced 2025-09-16 16:02:29 +03:00
vlib: add an encoding.xml
module with parser, validation, entity encoding, unit tests (#19708)
This commit is contained in:
parent
01022e918e
commit
35558df96c
48 changed files with 2004 additions and 1 deletions
96
vlib/encoding/xml/validation.v
Normal file
96
vlib/encoding/xml/validation.v
Normal file
|
@ -0,0 +1,96 @@
|
|||
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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue