├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── example ├── basic.v └── xml ├── file_test.xml ├── v.mod ├── xml └── xml.v └── xml_test.v /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | jobs: 4 | ubuntu-latest: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Installing V 8 | run: cd ~; git clone https://github.com/vlang/v.git; cd v; make CC=clang; sudo ./v symlink 9 | - uses: actions/checkout@v1 10 | - name: Running Test 11 | env: 12 | VFLAGS: -show_c_cmd -cg 13 | run: v version; v test . 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Executables files 2 | xml_test 3 | xml_test.exe 4 | 5 | # Temporary files 6 | fns.txt 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Zen1th 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vwxml 2 | Pure V library for parsing XML. The data is accessed with a tree API accessible directly within the `Node` struct. 3 | 4 | **This library is now archived.** 5 | 6 | ![CI](https://github.com/zenith391/vwxml/workflows/CI/badge.svg) 7 | 8 | Example: this parses `Hello` to 9 | `Node{name=_root_, text=, childrens=[Node{name=thing, text=, childrens=[Node{name=test, text=Hello, childrens=[], attributes=[]}], attributes=[Attribute{name=abc, value=test}]}], attributes=[]}` 10 | (struct printed with `println`). 11 | 12 | It doesn't support (yet): 13 | - CDATA sections 14 | - Error handling 15 | - Schemas (DTD) 16 | 17 | The features listed above will all be supported soon 18 | -------------------------------------------------------------------------------- /example/basic.v: -------------------------------------------------------------------------------- 1 | import xml 2 | 3 | fn main() { 4 | node := xml.parse('HelloWorld') 5 | assert(node.childrens.len == 1) 6 | thing := node.childrens[0] 7 | assert(thing.childrens.len == 2) 8 | eprintln('$node') 9 | for t in thing.childrens { 10 | for a in t.attributes { 11 | println(' (a) $a.name = $a.value') 12 | } 13 | println('---> $t.name') 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/xml: -------------------------------------------------------------------------------- 1 | ../xml -------------------------------------------------------------------------------- /file_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello 5 | World 6 | 9 | 10 | 11 | What great parser we have here! 12 | 13 | 14 | -------------------------------------------------------------------------------- /v.mod: -------------------------------------------------------------------------------- 1 | Module { 2 | name: 'vwxml' 3 | author: 'zenith391' 4 | version: '0.9.0' 5 | repo_url: 'https://github.com/zenith391/vwxml' 6 | vcs: 'git' 7 | tags: ['xml', 'dom'] 8 | category: 'xml' 9 | description: 'Pure V library for parsing XML into a DOM' 10 | } 11 | -------------------------------------------------------------------------------- /xml/xml.v: -------------------------------------------------------------------------------- 1 | module xml 2 | 3 | struct Attribute { 4 | pub mut: 5 | name string 6 | value string 7 | } 8 | 9 | struct ParserState { 10 | mut: 11 | in_head_tag bool 12 | in_attribute_key bool 13 | in_attribute_val bool 14 | attr_key string 15 | attr_val string 16 | in_string bool 17 | head_tag_str string 18 | tag_text string 19 | in_comment bool 20 | word string 21 | tag_attributes []Attribute 22 | } 23 | 24 | struct Node { 25 | pub mut: 26 | attributes []Attribute 27 | name string 28 | text string 29 | childrens []Node 30 | parent &Node 31 | } 32 | 33 | fn can_be_included(ch byte) bool { 34 | return ch != `\n` && ch != `\t` && ch != `\r` 35 | } 36 | 37 | fn unescape_string(str string) string { 38 | return str.replace('<', '<') 39 | .replace('>', '>') 40 | .replace('&', '&') 41 | .replace(''', "'") 42 | .replace('"', '"') 43 | } 44 | 45 | pub fn (mut state ParserState) push_attribute() { 46 | state.tag_attributes << Attribute{state.attr_key, unescape_string(state.attr_val)} 47 | } 48 | 49 | pub fn (attr Attribute) str() string { 50 | return "Attribute{name=" + attr.name + ", value=" + attr.value + "}" 51 | } 52 | 53 | pub fn (node Node) str() string { 54 | return "Node{name=" + node.name + ", text=" + node.text + ", childrens=" + node.childrens.str() + ", attributes=" + node.attributes.str() + "}" 55 | } 56 | 57 | pub fn parse(xml string) Node { 58 | mut root := Node{name: '_root_', parent: &Node(0)} 59 | chars := xml.bytes() 60 | 61 | mut state := ParserState{} // initialize with default parameters 62 | mut curr_node := &root 63 | for ch in chars { 64 | state.word = state.word + ch.str() 65 | if ch == ` ` { 66 | state.word = '' 67 | } 68 | if state.in_comment { 69 | if state.word == '-->' { // comment end 70 | state.in_comment = false 71 | state.word = '' 72 | } 73 | } else { 74 | if state.word == '