1
0
mirror of https://github.com/astaxie/beego.git synced 2025-06-27 22:10:19 +00:00

add vendor

This commit is contained in:
astaxie
2018-07-30 12:05:51 +08:00
parent d55f54a8ab
commit 48acfa08be
496 changed files with 327583 additions and 0 deletions

4
vendor/github.com/beego/goyaml2/README.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
goyaml2
=======
YAML for Golang

41
vendor/github.com/beego/goyaml2/conv.go generated vendored Normal file
View File

@ -0,0 +1,41 @@
package goyaml2
import (
"regexp"
"strconv"
//"time"
)
var (
RE_INT, _ = regexp.Compile("^[0-9,]+$")
RE_FLOAT, _ = regexp.Compile("^[0-9]+[.][0-9]+$")
RE_DATE, _ = regexp.Compile("^[0-9]{4}-[0-9]{2}-[0-9]{2}$")
RE_TIME, _ = regexp.Compile("^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$")
)
func string2Val(str string) interface{} {
tmp := []byte(str)
switch {
case str == "false":
return false
case str == "true":
return true
case RE_INT.Match(tmp):
// TODO check err
_int, _ := strconv.ParseInt(str, 10, 64)
return _int
case RE_FLOAT.Match(tmp):
_float, _ := strconv.ParseFloat(str, 64)
return _float
//TODO support time or Not?
/*
case RE_DATE.Match(tmp):
_date, _ := time.Parse("2006-01-02", str)
return _date
case RE_TIME.Match(tmp):
_time, _ := time.Parse("2006-01-02 03:04:05", str)
return _time
*/
}
return str
}

433
vendor/github.com/beego/goyaml2/reader.go generated vendored Normal file
View File

@ -0,0 +1,433 @@
package goyaml2
import (
"bufio"
"fmt"
"github.com/wendal/errors"
"io"
"log"
"strings"
)
const (
DEBUG = true
MAP_KEY_ONLY = iota
)
func Read(r io.Reader) (interface{}, error) {
yr := &yamlReader{}
yr.br = bufio.NewReader(r)
obj, err := yr.ReadObject(0)
if err == io.EOF {
err = nil
}
if obj == nil {
log.Println("Obj == nil")
}
return obj, err
}
type yamlReader struct {
br *bufio.Reader
nodes []interface{}
lineNum int
lastLine string
}
func (y *yamlReader) ReadObject(minIndent int) (interface{}, error) {
line, err := y.NextLine()
if err != nil {
if err == io.EOF && line != "" {
//log.Println("Read EOF , but still some data here")
} else {
//log.Println("ReadERR", err)
return nil, err
}
}
y.lastLine = line
indent, str := getIndent(line)
if indent < minIndent {
//log.Println("Current Indent Unexpect : ", str, indent, minIndent)
return nil, y.Error("Unexpect Indent", nil)
}
if indent > minIndent {
//log.Println("Change minIndent from %d to %d", minIndent, indent)
minIndent = indent
}
switch str[0] {
case '-':
return y.ReadList(minIndent)
case '[':
fallthrough
case '{':
y.lastLine = ""
_, value, err := y.asMapKeyValue("tmp:" + str)
if err != nil {
return nil, y.Error("Err inline map/list", nil)
}
return value, nil
}
//log.Println("Read Objcet as Map", indent, str)
return y.ReadMap(minIndent)
}
func (y *yamlReader) ReadList(minIndent int) ([]interface{}, error) {
list := []interface{}{}
for {
line, err := y.NextLine()
if err != nil {
return list, err
}
indent, str := getIndent(line)
switch {
case indent < minIndent:
y.lastLine = line
if len(list) == 0 {
return nil, nil
}
return list, nil
case indent == minIndent:
if str[0] != '-' {
y.lastLine = line
return list, nil
}
if len(str) < 2 {
return nil, y.Error("ListItem is Emtry", nil)
}
key, value, err := y.asMapKeyValue(str[1:])
if err != nil {
return nil, err
}
switch value {
case nil:
list = append(list, key)
case MAP_KEY_ONLY:
return nil, y.Error("Not support List-Map yet", nil)
default:
_map := map[string]interface{}{key.(string): value}
list = append(list, _map)
_line, _err := y.NextLine()
if _err != nil && _err != io.EOF {
return nil, err
}
if _line == "" {
return list, nil
}
y.lastLine = _line
_indent, _str := getIndent(line)
if _indent >= minIndent+2 {
switch _str[0] {
case '-':
return nil, y.Error("Unexpect", nil)
case '[':
return nil, y.Error("Unexpect", nil)
case '{':
return nil, y.Error("Unexpect", nil)
}
// look like a map
_map2, _err := y.ReadMap(_indent)
if _map2 != nil {
_map2[key.(string)] = value
}
if err != nil {
return list, _err
}
}
}
continue
default:
return nil, y.Error("Bad Indent\n"+line, nil)
}
}
panic("ERROR")
return nil, errors.New("Impossible")
}
func (y *yamlReader) ReadMap(minIndent int) (map[string]interface{}, error) {
_map := map[string]interface{}{}
//log.Println("ReadMap", minIndent)
OUT:
for {
line, err := y.NextLine()
if err != nil {
return _map, err
}
indent, str := getIndent(line)
//log.Printf("Indent : %d, str = %s", indent, str)
switch {
case indent < minIndent:
y.lastLine = line
if len(_map) == 0 {
return nil, nil
}
return _map, nil
case indent == minIndent:
key, value, err := y.asMapKeyValue(str)
if err != nil {
return nil, err
}
//log.Println("Key=", key, "value=", value)
switch value {
case nil:
return nil, y.Error("Unexpect", nil)
case MAP_KEY_ONLY:
//log.Println("KeyOnly, read inner Map", key)
//--------------------------------------
_line, err := y.NextLine()
if err != nil {
if err == io.EOF {
if _line == "" {
// Emtry map item?
_map[key.(string)] = nil
return _map, err
}
} else {
return nil, y.Error("ERR?", err)
}
}
y.lastLine = _line
_indent, _str := getIndent(_line)
if _indent < minIndent {
return _map, nil
}
////log.Println("##>>", _indent, _str)
if _indent == minIndent {
if _str[0] == '-' {
//log.Println("Read Same-Indent ListItem for Map")
_list, err := y.ReadList(minIndent)
if _list != nil {
_map[key.(string)] = _list
}
if err != nil {
return _map, nil
}
continue OUT
} else {
// Emtry map item?
_map[key.(string)] = nil
continue OUT
}
}
//--------------------------------------
//log.Println("Read Map Item", _indent, _str)
obj, err := y.ReadObject(_indent)
if obj != nil {
_map[key.(string)] = obj
}
if err != nil {
return _map, err
}
default:
_map[key.(string)] = value
}
default:
//log.Println("Bad", indent, str)
return nil, y.Error("Bad Indent\n"+line, nil)
}
}
panic("ERROR")
return nil, errors.New("Impossible")
}
func (y *yamlReader) NextLine() (line string, err error) {
if y.lastLine != "" {
line = y.lastLine
y.lastLine = ""
//log.Println("Return lastLine", line)
return
}
for {
line, err = y.br.ReadString('\n')
y.lineNum++
if err != nil {
return
}
if strings.HasPrefix(line, "---") || strings.HasPrefix(line, "#") {
continue
}
line = strings.TrimRight(line, "\n\t\r ")
if line == "" {
continue
}
//log.Println("Return Line", line)
return
}
//log.Println("Impossbible : " + line)
return // impossbile!
}
func getIndent(str string) (int, string) {
indent := 0
for i, s := range str {
switch s {
case ' ':
indent++
case '\t':
indent += 4
default:
return indent, str[i:]
}
}
panic("Invalid indent : " + str)
return -1, ""
}
func (y *yamlReader) asMapKeyValue(str string) (key interface{}, val interface{}, err error) {
tokens := splitToken(str)
key = tokens[0]
if len(tokens) == 1 {
return key, nil, nil
}
if tokens[1] != ":" {
return "", nil, y.Error("Unexpect "+str, nil)
}
if len(tokens) == 2 {
return key, MAP_KEY_ONLY, nil
}
if len(tokens) == 3 {
return key, tokens[2], nil
}
switch tokens[2] {
case "[":
list := []interface{}{}
for i := 3; i < len(tokens)-1; i++ {
list = append(list, tokens[i])
}
return key, list, nil
case "{":
_map := map[string]interface{}{}
for i := 3; i < len(tokens)-1; i += 4 {
//log.Println(">>>", i, tokens[i])
if i > len(tokens)-2 {
return "", nil, y.Error("Unexpect "+str, nil)
}
if tokens[i+1] != ":" {
return "", nil, y.Error("Unexpect "+str, nil)
}
_map[tokens[i].(string)] = tokens[i+2]
if (i + 3) < (len(tokens) - 1) {
if tokens[i+3] != "," {
return "", "", y.Error("Unexpect "+str, nil)
}
} else {
break
}
}
return key, _map, nil
}
//log.Println(str, tokens)
return "", nil, y.Error("Unexpect "+str, nil)
}
func splitToken(str string) (tokens []interface{}) {
str = strings.Trim(str, "\r\t\n ")
if str == "" {
panic("Impossbile")
return
}
tokens = []interface{}{}
lastPos := 0
for i := 0; i < len(str); i++ {
switch str[i] {
case ':':
fallthrough
case '{':
fallthrough
case '[':
fallthrough
case '}':
fallthrough
case ']':
fallthrough
case ',':
if i > lastPos {
tokens = append(tokens, str[lastPos:i])
}
tokens = append(tokens, str[i:i+1])
lastPos = i + 1
case ' ':
if i > lastPos {
tokens = append(tokens, str[lastPos:i])
}
lastPos = i + 1
case '\'':
//log.Println("Scan End of String")
i++
start := i
for ; i < len(str); i++ {
if str[i] == '\'' {
//log.Println("Found End of String", start, i)
break
}
}
tokens = append(tokens, str[start:i])
lastPos = i + 1
case '"':
i++
start := i
for ; i < len(str); i++ {
if str[i] == '"' {
break
}
}
tokens = append(tokens, str[start:i])
lastPos = i + 1
}
}
////log.Println("last", lastPos)
if lastPos < len(str) {
tokens = append(tokens, str[lastPos:])
}
if len(tokens) == 1 {
tokens[0] = string2Val(tokens[0].(string))
return
}
if tokens[1] == ":" {
if len(tokens) == 2 {
return
}
if tokens[2] == "{" || tokens[2] == "[" {
return
}
str = strings.Trim(strings.SplitN(str, ":", 2)[1], "\t ")
if len(str) > 2 {
if str[0] == '\'' && str[len(str)-1] == '\'' {
str = str[1 : len(str)-1]
} else if str[0] == '"' && str[len(str)-1] == '"' {
str = str[1 : len(str)-1]
}
}
val := string2Val(str)
tokens = []interface{}{tokens[0], tokens[1], val}
return
}
if len(str) > 2 {
if str[0] == '\'' && str[len(str)-1] == '\'' {
str = str[1 : len(str)-1]
} else if str[0] == '"' && str[len(str)-1] == '"' {
str = str[1 : len(str)-1]
}
}
val := string2Val(str)
tokens = []interface{}{val}
return
}
func (y *yamlReader) Error(msg string, err error) error {
if err != nil {
return errors.New(fmt.Sprintf("line %d : %s : %v", y.lineNum, msg, err.Error()))
}
return errors.New(fmt.Sprintf("line %d >> %s", y.lineNum, msg))
}

29
vendor/github.com/beego/goyaml2/types.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
package goyaml2
const (
N_Map = iota
N_List
N_String
)
type Node interface {
Type() int
}
type MapNode map[string]interface{}
type ListNode []interface{}
type StringNode string
func (m *MapNode) Type() int {
return N_Map
}
func (l *ListNode) Type() int {
return N_List
}
func (s *StringNode) Type() int {
return N_String
}

9
vendor/github.com/beego/goyaml2/writer.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
package goyaml2
import (
"io"
)
func Write(w io.Writer, v interface{}) error {
return nil
}

28
vendor/github.com/beego/x2j/LICENSE generated vendored Normal file
View File

@ -0,0 +1,28 @@
Copyright (c) 2012-2013 Charles Banning <clbanning@gmail.com>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

157
vendor/github.com/beego/x2j/README generated vendored Normal file
View File

@ -0,0 +1,157 @@
x2j.go - Unmarshal dynamic / arbitrary XML docs and extract values (using wildcards, if necessary).
ANNOUNCEMENTS
20 December 2013:
Non-UTF8 character sets supported via the X2jCharsetReader variable.
12 December 2013:
For symmetry, the package j2x has functions that marshal JSON strings and
map[string]interface{} values to XML encoded strings: http://godoc.org/github.com/clbanning/j2x.
Also, ToTree(), ToMap(), ToJson(), ToJsonIndent(), ReaderValuesFromTagPath() and ReaderValuesForTag() use io.Reader instead of string or []byte.
If you want to process a stream of XML messages check out XmlMsgsFromReader().
MOTIVATION
I make extensive use of JSON for messaging and typically unmarshal the messages into
map[string]interface{} variables. This is easily done using json.Unmarshal from the
standard Go libraries. Unfortunately, many legacy solutions use structured
XML messages; in those environments the applications would have to be refitted to
interoperate with my components.
The better solution is to just provide an alternative HTTP handler that receives
XML doc messages and parses it into a map[string]interface{} variable and then reuse
all the JSON-based code. The Go xml.Unmarshal() function does not provide the same
option of unmarshaling XML messages into map[string]interface{} variables. So I wrote
a couple of small functions to fill this gap.
Of course, once the XML doc was unmarshal'd into a map[string]interface{} variable it
was just a matter of calling json.Marshal() to provide it as a JSON string. Hence 'x2j'
rather than just 'x2m'.
USAGE
The package is fairly well self-documented. (http://godoc.org/github.com/clbanning/x2j)
The one really useful function is:
- Unmarshal(doc []byte, v interface{}) error
where v is a pointer to a variable of type 'map[string]interface{}', 'string', or
any other type supported by xml.Unmarshal().
To retrieve a value for specific tag use:
- DocValue(doc, path string, attrs ...string) (interface{},error)
- MapValue(m map[string]interface{}, path string, attr map[string]interface{}, recast ...bool) (interface{}, error)
The 'path' argument is a period-separated tag hierarchy - also known as dot-notation.
It is the program's responsibility to cast the returned value to the proper type; possible
types are the normal JSON unmarshaling types: string, float64, bool, []interface, map[string]interface{}.
To retrieve all values associated with a tag occurring anywhere in the XML document use:
- ValuesForTag(doc, tag string) ([]interface{}, error)
- ValuesForKey(m map[string]interface{}, key string) []interface{}
Demos: http://play.golang.org/p/m8zP-cpk0O
http://play.golang.org/p/cIteTS1iSg
http://play.golang.org/p/vd8pMiI21b
Returned values should be one of map[string]interface, []interface{}, or string.
All the values assocated with a tag-path that may include one or more wildcard characters -
'*' - can also be retrieved using:
- ValuesFromTagPath(doc, path string, getAttrs ...bool) ([]interface{}, error)
- ValuesFromKeyPath(map[string]interface{}, path string, getAttrs ...bool) []interface{}
Demos: http://play.golang.org/p/kUQnZ8VuhS
http://play.golang.org/p/l1aMHYtz7G
NOTE: care should be taken when using "*" at the end of a path - i.e., "books.book.*". See
the x2jpath_test.go case on how the wildcard returns all key values and collapses list values;
the same message structure can load a []interface{} or a map[string]interface{} (or an interface{})
value for a tag.
See the test cases in "x2jpath_test.go" and programs in "example" subdirectory for more.
XML PARSING CONVENTIONS
- Attributes are parsed to map[string]interface{} values by prefixing a hyphen, '-',
to the attribute label.
- If the element is a simple element and has attributes, the element value
is given the key '#text' for its map[string]interface{} representation. (See
the 'atomFeedString.xml' test data, below.)
BULK PROCESSING OF MESSAGE FILES
Sometime messages may be logged into files for transmission via FTP (e.g.) and subsequent
processing. You can use the bulk XML message processor to convert files of XML messages into
map[string]interface{} values with custom processing and error handler functions. See
the notes and test code for:
- XmlMsgsFromFile(fname string, phandler func(map[string]interface{}) bool, ehandler func(error) bool,recast ...bool) error
IMPLEMENTATION NOTES
Nothing fancy here, just brute force.
- Use xml.Decoder to parse the XML doc and build a tree.
- Walk the tree and load values into a map[string]interface{} variable, 'm', as
appropriate.
- Use json.Marshaler to convert 'm' to JSON.
As for testing:
- Copy an XML doc into 'x2j_test.xml'.
- Run "go test" and you'll get a full dump.
("pathTestString.xml" and "atomFeedString.xml" are test data from "read_test.go"
in the encoding/xml directory of the standard package library.)
USES
- putting a XML API on our message hub middleware (http://jsonhub.net)
- loading XML data into NoSQL database, such as, mongoDB
PERFORMANCE IMPROVEMENTS WITH GO 1.1 and 1.2
Upgrading to Go 1.1 environment results in performance improvements for XML and JSON
unmarshalling, in general. The x2j package gets an average performance boost of 40%.
----- Go 1.0.2 ----- ----------- Go 1.1 -----------
iterations ns/op iterations ns/op % improved
Benchmark_UseXml-4 100000 18776 200000 10377 45%
Benchmark_UseX2j-4 50000 55323 50000 33958 39%
Benchmark_UseJson-4 1000000 2257 1000000 1484 34%
Benchmark_UseJsonToMap-4 1000000 2531 1000000 1566 38%
BenchmarkBig_UseXml-4 100000 28918 100000 15876 45%
BenchmarkBig_UseX2j-4 20000 86338 50000 52661 39%
BenchmarkBig_UseJson-4 500000 4448 1000000 2664 40%
BenchmarkBig_UseJsonToMap-4 200000 9076 500000 5753 37%
BenchmarkBig3_UseXml-4 50000 42224 100000 24686 42%
BenchmarkBig3_UseX2j-4 10000 147407 20000 84332 43%
BenchmarkBig3_UseJson-4 500000 5921 500000 3930 34%
BenchmarkBig3_UseJsonToMap-4 200000 13037 200000 8670 33%
The x2j package gets an additional 15-20% performance boost going to Go 1.2.
------ Go 1.1 ------ ----------- Go 1.2 -----------
iterations ns/op iterations ns/op % improved
Benchmark_UseXml-4 200000 10377 200000 11031 -6%
Benchmark_UseX2j-4 50000 33958 100000 29188 14%
Benchmark_UseJson-4 1000000 1484 1000000 1347 9%
Benchmark_UseJsonToMap-4 1000000 1566 1000000 1434 8%
BenchmarkBig_UseXml-4 100000 15876 100000 16585 -4%
BenchmarkBig_UseX2j-4 50000 52661 50000 43452 17%
BenchmarkBig_UseJson-4 1000000 2664 1000000 2523 5%
BenchmarkBig_UseJsonToMap-4 500000 5753 500000 4992 13%
BenchmarkBig3_UseXml-4 100000 24686 100000 24348 1%
BenchmarkBig3_UseX2j-4 20000 84332 50000 66736 21%
BenchmarkBig3_UseJson-4 500000 3930 500000 3733 5%
BenchmarkBig3_UseJsonToMap-4 200000 8670 200000 7810 10%

54
vendor/github.com/beego/x2j/atomFeedString.xml generated vendored Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us" updated="2009-10-04T01:35:58+00:00"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><link href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></link><id>http://codereview.appspot.com/</id><author><name>rietveld&lt;&gt;</name></author><entry><title>rietveld: an attempt at pubsubhubbub
</title><link href="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html">
An attempt at adding pubsubhubbub support to Rietveld.
http://code.google.com/p/pubsubhubbub
http://code.google.com/p/rietveld/issues/detail?id=155
The server side of the protocol is trivial:
1. add a &amp;lt;link rel=&amp;quot;hub&amp;quot; href=&amp;quot;hub-server&amp;quot;&amp;gt; tag to all
feeds that will be pubsubhubbubbed.
2. every time one of those feeds changes, tell the hub
with a simple POST request.
I have tested this by adding debug prints to a local hub
server and checking that the server got the right publish
requests.
I can&amp;#39;t quite get the server to work, but I think the bug
is not in my code. I think that the server expects to be
able to grab the feed and see the feed&amp;#39;s actual URL in
the link rel=&amp;quot;self&amp;quot;, but the default value for that drops
the :port from the URL, and I cannot for the life of me
figure out how to get the Atom generator deep inside
django not to do that, or even where it is doing that,
or even what code is running to generate the Atom feed.
(I thought I knew but I added some assert False statements
and it kept running!)
Ignoring that particular problem, I would appreciate
feedback on the right way to get the two values at
the top of feeds.py marked NOTE(rsc).
</summary></entry><entry><title>rietveld: correct tab handling
</title><link href="http://codereview.appspot.com/124106" rel="alternate"></link><updated>2009-10-03T23:02:17+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:0a2a4f19bb815101f0ba2904aed7c35a</id><summary type="html">
This fixes the buggy tab rendering that can be seen at
http://codereview.appspot.com/116075/diff/1/2
The fundamental problem was that the tab code was
not being told what column the text began in, so it
didn&amp;#39;t know where to put the tab stops. Another problem
was that some of the code assumed that string byte
offsets were the same as column offsets, which is only
true if there are no tabs.
In the process of fixing this, I cleaned up the arguments
to Fold and ExpandTabs and renamed them Break and
_ExpandTabs so that I could be sure that I found all the
call sites. I also wanted to verify that ExpandTabs was
not being used from outside intra_region_diff.py.
</summary></entry></feed> `

20
vendor/github.com/beego/x2j/pathTestString.xml generated vendored Normal file
View File

@ -0,0 +1,20 @@
<Result>
<Before>1</Before>
<Items>
<Item1>
<Value>A</Value>
</Item1>
<Item2>
<Value>B</Value>
</Item2>
<Item1>
<Value>C</Value>
<Value>D</Value>
</Item1>
<_>
<Value>E</Value>
</_>
</Items>
<After>2</After>
</Result>

105
vendor/github.com/beego/x2j/reader2j.go generated vendored Normal file
View File

@ -0,0 +1,105 @@
// io.Reader --> map[string]interface{} or JSON string
// nothing magic - just implements generic Go case
package x2j
import (
"encoding/json"
"encoding/xml"
"io"
)
// ToTree() - parse a XML io.Reader to a tree of Nodes
func ToTree(rdr io.Reader) (*Node, error) {
p := xml.NewDecoder(rdr)
p.CharsetReader = X2jCharsetReader
n, perr := xmlToTree("", nil, p)
if perr != nil {
return nil, perr
}
return n, nil
}
// ToMap() - parse a XML io.Reader to a map[string]interface{}
func ToMap(rdr io.Reader, recast ...bool) (map[string]interface{}, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
n, err := ToTree(rdr)
if err != nil {
return nil, err
}
m := make(map[string]interface{})
m[n.key] = n.treeToMap(r)
return m, nil
}
// ToJson() - parse a XML io.Reader to a JSON string
func ToJson(rdr io.Reader, recast ...bool) (string, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
m, merr := ToMap(rdr, r)
if m == nil || merr != nil {
return "", merr
}
b, berr := json.Marshal(m)
if berr != nil {
return "", berr
}
return string(b), nil
}
// ToJsonIndent - the pretty form of ReaderToJson
func ToJsonIndent(rdr io.Reader, recast ...bool) (string, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
m, merr := ToMap(rdr, r)
if m == nil || merr != nil {
return "", merr
}
b, berr := json.MarshalIndent(m, "", " ")
if berr != nil {
return "", berr
}
// NOTE: don't have to worry about safe JSON marshaling with json.Marshal, since '<' and '>" are reservedin XML.
return string(b), nil
}
// ReaderValuesFromTagPath - io.Reader version of ValuesFromTagPath()
func ReaderValuesFromTagPath(rdr io.Reader, path string, getAttrs ...bool) ([]interface{}, error) {
var a bool
if len(getAttrs) == 1 {
a = getAttrs[0]
}
m, err := ToMap(rdr)
if err != nil {
return nil, err
}
return ValuesFromKeyPath(m, path, a), nil
}
// ReaderValuesForTag - io.Reader version of ValuesForTag()
func ReaderValuesForTag(rdr io.Reader, tag string) ([]interface{}, error) {
m, err := ToMap(rdr)
if err != nil {
return nil, err
}
return ValuesForKey(m, tag), nil
}

29
vendor/github.com/beego/x2j/songTextString.xml generated vendored Normal file
View File

@ -0,0 +1,29 @@
<msg mtype="alert" mpriority="1">
<text>help me!</text>
<song title="A Long Time" author="Mayer Hawthorne">
<verses>
<verse name="verse 1" no="1">
<line no="1">Henry was a renegade</line>
<line no="2">Didn't like to play it safe</line>
<line no="3">One component at a time</line>
<line no="4">There's got to be a better way</line>
<line no="5">Oh, people came from miles around</line>
<line no="6">Searching for a steady job</line>
<line no="7">Welcome to the Motor Town</line>
<line no="8">Booming like an atom bomb</line>
</verse>
<verse name="verse 2" no="2">
<line no="1">Oh, Henry was the end of the story</line>
<line no="2">Then everything went wrong</line>
<line no="3">And we'll return it to its former glory</line>
<line no="4">But it just takes so long</line>
</verse>
</verses>
<chorus>
<line no="1">It's going to take a long time</line>
<line no="2">It's going to take it, but we'll make it one day</line>
<line no="3">It's going to take a long time</line>
<line no="4">It's going to take it, but we'll make it one day</line>
</chorus>
</song>
</msg>

656
vendor/github.com/beego/x2j/x2j.go generated vendored Normal file
View File

@ -0,0 +1,656 @@
// Unmarshal dynamic / arbitrary XML docs and extract values (using wildcards, if necessary).
// Copyright 2012-2013 Charles Banning. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file
/*
Unmarshal dynamic / arbitrary XML docs and extract values (using wildcards, if necessary).
One useful function is:
- Unmarshal(doc []byte, v interface{}) error
where v is a pointer to a variable of type 'map[string]interface{}', 'string', or
any other type supported by xml.Unmarshal().
To retrieve a value for specific tag use:
- DocValue(doc, path string, attrs ...string) (interface{},error)
- MapValue(m map[string]interface{}, path string, attr map[string]interface{}, recast ...bool) (interface{}, error)
The 'path' argument is a period-separated tag hierarchy - also known as dot-notation.
It is the program's responsibility to cast the returned value to the proper type; possible
types are the normal JSON unmarshaling types: string, float64, bool, []interface, map[string]interface{}.
To retrieve all values associated with a tag occurring anywhere in the XML document use:
- ValuesForTag(doc, tag string) ([]interface{}, error)
- ValuesForKey(m map[string]interface{}, key string) []interface{}
Demos: http://play.golang.org/p/m8zP-cpk0O
http://play.golang.org/p/cIteTS1iSg
http://play.golang.org/p/vd8pMiI21b
Returned values should be one of map[string]interface, []interface{}, or string.
All the values assocated with a tag-path that may include one or more wildcard characters -
'*' - can also be retrieved using:
- ValuesFromTagPath(doc, path string, getAttrs ...bool) ([]interface{}, error)
- ValuesFromKeyPath(map[string]interface{}, path string, getAttrs ...bool) []interface{}
Demos: http://play.golang.org/p/kUQnZ8VuhS
http://play.golang.org/p/l1aMHYtz7G
NOTE: care should be taken when using "*" at the end of a path - i.e., "books.book.*". See
the x2jpath_test.go case on how the wildcard returns all key values and collapses list values;
the same message structure can load a []interface{} or a map[string]interface{} (or an interface{})
value for a tag.
See the test cases in "x2jpath_test.go" and programs in "example" subdirectory for more.
XML PARSING CONVENTIONS
- Attributes are parsed to map[string]interface{} values by prefixing a hyphen, '-',
to the attribute label.
- If the element is a simple element and has attributes, the element value
is given the key '#text' for its map[string]interface{} representation. (See
the 'atomFeedString.xml' test data, below.)
io.Reader HANDLING
ToTree(), ToMap(), ToJson(), and ToJsonIndent() provide parsing of messages from an io.Reader.
If you want to handle a message stream, look at XmlMsgsFromReader().
NON-UTF8 CHARACTER SETS
Use the X2jCharsetReader variable to assign io.Reader for alternative character sets.
*/
package x2j
import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
"regexp"
"strconv"
"strings"
)
// If X2jCharsetReader != nil, it will be used to decode the doc or stream if required
// import charset "code.google.com/p/go-charset/charset"
// ...
// x2j.X2jCharsetReader = charset.NewReader
// s, err := x2j.DocToJson(doc)
var X2jCharsetReader func(charset string, input io.Reader)(io.Reader, error)
type Node struct {
dup bool // is member of a list
attr bool // is an attribute
key string // XML tag
val string // element value
nodes []*Node
}
// DocToJson - return an XML doc as a JSON string.
// If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible.
func DocToJson(doc string, recast ...bool) (string, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
m, merr := DocToMap(doc, r)
if m == nil || merr != nil {
return "", merr
}
b, berr := json.Marshal(m)
if berr != nil {
return "", berr
}
// NOTE: don't have to worry about safe JSON marshaling with json.Marshal, since '<' and '>" are reservedin XML.
return string(b), nil
}
// DocToJsonIndent - return an XML doc as a prettified JSON string.
// If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible.
// Note: recasting is only applied to element values, not attribute values.
func DocToJsonIndent(doc string, recast ...bool) (string, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
m, merr := DocToMap(doc, r)
if m == nil || merr != nil {
return "", merr
}
b, berr := json.MarshalIndent(m, "", " ")
if berr != nil {
return "", berr
}
// NOTE: don't have to worry about safe JSON marshaling with json.Marshal, since '<' and '>" are reservedin XML.
return string(b), nil
}
// DocToMap - convert an XML doc into a map[string]interface{}.
// (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().)
// If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible.
// Note: recasting is only applied to element values, not attribute values.
func DocToMap(doc string, recast ...bool) (map[string]interface{}, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
n, err := DocToTree(doc)
if err != nil {
return nil, err
}
m := make(map[string]interface{})
m[n.key] = n.treeToMap(r)
return m, nil
}
// DocToTree - convert an XML doc into a tree of nodes.
func DocToTree(doc string) (*Node, error) {
// xml.Decoder doesn't properly handle whitespace in some doc
// see songTextString.xml test case ...
reg, _ := regexp.Compile("[ \t\n\r]*<")
doc = reg.ReplaceAllString(doc, "<")
b := bytes.NewBufferString(doc)
p := xml.NewDecoder(b)
p.CharsetReader = X2jCharsetReader
n, berr := xmlToTree("", nil, p)
if berr != nil {
return nil, berr
}
return n, nil
}
// (*Node)WriteTree - convert a tree of nodes into a printable string.
// 'padding' is the starting indentation; typically: n.WriteTree().
func (n *Node) WriteTree(padding ...int) string {
var indent int
if len(padding) == 1 {
indent = padding[0]
}
var s string
if n.val != "" {
for i := 0; i < indent; i++ {
s += " "
}
s += n.key + " : " + n.val + "\n"
} else {
for i := 0; i < indent; i++ {
s += " "
}
s += n.key + " :" + "\n"
for _, nn := range n.nodes {
s += nn.WriteTree(indent + 1)
}
}
return s
}
// xmlToTree - load a 'clean' XML doc into a tree of *Node.
func xmlToTree(skey string, a []xml.Attr, p *xml.Decoder) (*Node, error) {
n := new(Node)
n.nodes = make([]*Node, 0)
if skey != "" {
n.key = skey
if len(a) > 0 {
for _, v := range a {
na := new(Node)
na.attr = true
na.key = `-` + v.Name.Local
na.val = v.Value
n.nodes = append(n.nodes, na)
}
}
}
for {
t, err := p.Token()
if err != nil {
return nil, err
}
switch t.(type) {
case xml.StartElement:
tt := t.(xml.StartElement)
// handle root
if n.key == "" {
n.key = tt.Name.Local
if len(tt.Attr) > 0 {
for _, v := range tt.Attr {
na := new(Node)
na.attr = true
na.key = `-` + v.Name.Local
na.val = v.Value
n.nodes = append(n.nodes, na)
}
}
} else {
nn, nnerr := xmlToTree(tt.Name.Local, tt.Attr, p)
if nnerr != nil {
return nil, nnerr
}
n.nodes = append(n.nodes, nn)
}
case xml.EndElement:
// scan n.nodes for duplicate n.key values
n.markDuplicateKeys()
return n, nil
case xml.CharData:
tt := string(t.(xml.CharData))
if len(n.nodes) > 0 {
nn := new(Node)
nn.key = "#text"
nn.val = tt
n.nodes = append(n.nodes, nn)
} else {
n.val = tt
}
default:
// noop
}
}
// Logically we can't get here, but provide an error message anyway.
return nil, errors.New("Unknown parse error in xmlToTree() for: " + n.key)
}
// (*Node)markDuplicateKeys - set node.dup flag for loading map[string]interface{}.
func (n *Node) markDuplicateKeys() {
l := len(n.nodes)
for i := 0; i < l; i++ {
if n.nodes[i].dup {
continue
}
for j := i + 1; j < l; j++ {
if n.nodes[i].key == n.nodes[j].key {
n.nodes[i].dup = true
n.nodes[j].dup = true
}
}
}
}
// (*Node)treeToMap - convert a tree of nodes into a map[string]interface{}.
// (Parses to map that is structurally the same as from json.Unmarshal().)
// Note: root is not instantiated; call with: "m[n.key] = n.treeToMap(recast)".
func (n *Node) treeToMap(r bool) interface{} {
if len(n.nodes) == 0 {
return recast(n.val, r)
}
m := make(map[string]interface{}, 0)
for _, v := range n.nodes {
// just a value
if !v.dup && len(v.nodes) == 0 {
m[v.key] = recast(v.val, r)
continue
}
// a list of values
if v.dup {
var a []interface{}
if vv, ok := m[v.key]; ok {
a = vv.([]interface{})
} else {
a = make([]interface{}, 0)
}
a = append(a, v.treeToMap(r))
m[v.key] = interface{}(a)
continue
}
// it's a unique key
m[v.key] = v.treeToMap(r)
}
return interface{}(m)
}
// recast - try to cast string values to bool or float64
func recast(s string, r bool) interface{} {
if r {
// handle numeric strings ahead of boolean
if f, err := strconv.ParseFloat(s, 64); err == nil {
return interface{}(f)
}
// ParseBool treats "1"==true & "0"==false
if b, err := strconv.ParseBool(s); err == nil {
return interface{}(b)
}
}
return interface{}(s)
}
// WriteMap - dumps the map[string]interface{} for examination.
// 'offset' is initial indentation count; typically: WriteMap(m).
// NOTE: with XML all element types are 'string'.
// But code written as generic for use with maps[string]interface{} values from json.Unmarshal().
// Or it can handle a DocToMap(doc,true) result where values have been recast'd.
func WriteMap(m interface{}, offset ...int) string {
var indent int
if len(offset) == 1 {
indent = offset[0]
}
var s string
switch m.(type) {
case nil:
return "[nil] nil"
case string:
return "[string] " + m.(string)
case float64:
return "[float64] " + strconv.FormatFloat(m.(float64), 'e', 2, 64)
case bool:
return "[bool] " + strconv.FormatBool(m.(bool))
case []interface{}:
s += "[[]interface{}]"
for i, v := range m.([]interface{}) {
s += "\n"
for i := 0; i < indent; i++ {
s += " "
}
s += "[item: " + strconv.FormatInt(int64(i), 10) + "]"
switch v.(type) {
case string, float64, bool:
s += "\n"
default:
// noop
}
for i := 0; i < indent; i++ {
s += " "
}
s += WriteMap(v, indent+1)
}
case map[string]interface{}:
for k, v := range m.(map[string]interface{}) {
s += "\n"
for i := 0; i < indent; i++ {
s += " "
}
// s += "[map[string]interface{}] "+k+" :"+WriteMap(v,indent+1)
s += k + " :" + WriteMap(v, indent+1)
}
default:
// shouldn't ever be here ...
s += fmt.Sprintf("unknown type for: %v", m)
}
return s
}
// ------------------------ value extraction from XML doc --------------------------
// DocValue - return a value for a specific tag
// 'doc' is a valid XML message.
// 'path' is a hierarchy of XML tags, e.g., "doc.name".
// 'attrs' is an OPTIONAL list of "name:value" pairs for attributes.
// Note: 'recast' is not enabled here. Use DocToMap(), NewAttributeMap(), and MapValue() calls for that.
func DocValue(doc, path string, attrs ...string) (interface{}, error) {
n, err := DocToTree(doc)
if err != nil {
return nil, err
}
m := make(map[string]interface{})
m[n.key] = n.treeToMap(false)
a, aerr := NewAttributeMap(attrs...)
if aerr != nil {
return nil, aerr
}
v, verr := MapValue(m, path, a)
if verr != nil {
return nil, verr
}
return v, nil
}
// MapValue - retrieves value based on walking the map, 'm'.
// 'm' is the map value of interest.
// 'path' is a period-separated hierarchy of keys in the map.
// 'attr' is a map of attribute "name:value" pairs from NewAttributeMap(). May be 'nil'.
// If the path can't be traversed, an error is returned.
// Note: the optional argument 'r' can be used to coerce attribute values, 'attr', if done so for 'm'.
func MapValue(m map[string]interface{}, path string, attr map[string]interface{}, r ...bool) (interface{}, error) {
// attribute values may have been recasted during map construction; default is 'false'.
if len(r) == 1 && r[0] == true {
for k, v := range attr {
attr[k] = recast(v.(string), true)
}
}
// parse the path
keys := strings.Split(path, ".")
// initialize return value to 'm' so a path of "" will work correctly
var v interface{} = m
var ok bool
var okey string
var isMap bool = true
if keys[0] == "" && len(attr) == 0 {
return v, nil
}
for _, key := range keys {
if !isMap {
return nil, errors.New("no keys beyond: " + okey)
}
if v, ok = m[key]; !ok {
return nil, errors.New("no key in map: " + key)
} else {
switch v.(type) {
case map[string]interface{}:
m = v.(map[string]interface{})
isMap = true
default:
isMap = false
}
}
// save 'key' for error reporting
okey = key
}
// match attributes; value is "#text" or nil
if attr == nil {
return v, nil
}
return hasAttributes(v, attr)
}
// hasAttributes() - interface{} equality works for string, float64, bool
func hasAttributes(v interface{}, a map[string]interface{}) (interface{}, error) {
switch v.(type) {
case []interface{}:
// run through all entries looking one with matching attributes
for _, vv := range v.([]interface{}) {
if vvv, vvverr := hasAttributes(vv, a); vvverr == nil {
return vvv, nil
}
}
return nil, errors.New("no list member with matching attributes")
case map[string]interface{}:
// do all attribute name:value pairs match?
nv := v.(map[string]interface{})
for key, val := range a {
if vv, ok := nv[key]; !ok {
return nil, errors.New("no attribute with name: " + key[1:])
} else if val != vv {
return nil, errors.New("no attribute key:value pair: " + fmt.Sprintf("%s:%v", key[1:], val))
}
}
// they all match; so return value associated with "#text" key.
if vv, ok := nv["#text"]; ok {
return vv, nil
} else {
// this happens when another element is value of tag rather than just a string value
return nv, nil
}
}
return nil, errors.New("no match for attributes")
}
// NewAttributeMap() - generate map of attributes=value entries as map["-"+string]string.
// 'kv' arguments are "name:value" pairs that appear as attributes, name="value".
// If len(kv) == 0, the return is (nil, nil).
func NewAttributeMap(kv ...string) (map[string]interface{}, error) {
if len(kv) == 0 {
return nil, nil
}
m := make(map[string]interface{}, 0)
for _, v := range kv {
vv := strings.Split(v, ":")
if len(vv) != 2 {
return nil, errors.New("attribute not \"name:value\" pair: " + v)
}
// attributes are stored as keys prepended with hyphen
m["-"+vv[0]] = interface{}(vv[1])
}
return m, nil
}
//------------------------- get values for key ----------------------------
// ValuesForTag - return all values in doc associated with 'tag'.
// Returns nil if the 'tag' does not occur in the doc.
// If there is an error encounted while parsing doc, that is returned.
// If you want values 'recast' use DocToMap() and ValuesForKey().
func ValuesForTag(doc, tag string) ([]interface{}, error) {
m, err := DocToMap(doc)
if err != nil {
return nil, err
}
return ValuesForKey(m, tag), nil
}
// ValuesForKey - return all values in map associated with 'key'
// Returns nil if the 'key' does not occur in the map
func ValuesForKey(m map[string]interface{}, key string) []interface{} {
ret := make([]interface{}, 0)
hasKey(m, key, &ret)
if len(ret) > 0 {
return ret
}
return nil
}
// hasKey - if the map 'key' exists append it to array
// if it doesn't do nothing except scan array and map values
func hasKey(iv interface{}, key string, ret *[]interface{}) {
switch iv.(type) {
case map[string]interface{}:
vv := iv.(map[string]interface{})
if v, ok := vv[key]; ok {
*ret = append(*ret, v)
}
for _, v := range iv.(map[string]interface{}) {
hasKey(v, key, ret)
}
case []interface{}:
for _, v := range iv.([]interface{}) {
hasKey(v, key, ret)
}
}
}
// ======== 2013.07.01 - x2j.Unmarshal, wraps xml.Unmarshal ==============
// Unmarshal - wraps xml.Unmarshal with handling of map[string]interface{}
// and string type variables.
// Usage: x2j.Unmarshal(doc,&m) where m of type map[string]interface{}
// x2j.Unmarshal(doc,&s) where s of type string (Overrides xml.Unmarshal().)
// x2j.Unmarshal(doc,&struct) - passed to xml.Unmarshal()
// x2j.Unmarshal(doc,&slice) - passed to xml.Unmarshal()
func Unmarshal(doc []byte, v interface{}) error {
switch v.(type) {
case *map[string]interface{}:
m, err := ByteDocToMap(doc)
vv := *v.(*map[string]interface{})
for k, v := range m {
vv[k] = v
}
return err
case *string:
s, err := ByteDocToJson(doc)
*(v.(*string)) = s
return err
default:
b := bytes.NewBuffer(doc)
p := xml.NewDecoder(b)
p.CharsetReader = X2jCharsetReader
return p.Decode(v)
// return xml.Unmarshal(doc, v)
}
return nil
}
// ByteDocToJson - return an XML doc as a JSON string.
// If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible.
func ByteDocToJson(doc []byte, recast ...bool) (string, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
m, merr := ByteDocToMap(doc, r)
if m == nil || merr != nil {
return "", merr
}
b, berr := json.Marshal(m)
if berr != nil {
return "", berr
}
// NOTE: don't have to worry about safe JSON marshaling with json.Marshal, since '<' and '>" are reservedin XML.
return string(b), nil
}
// ByteDocToMap - convert an XML doc into a map[string]interface{}.
// (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().)
// If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible.
// Note: recasting is only applied to element values, not attribute values.
func ByteDocToMap(doc []byte, recast ...bool) (map[string]interface{}, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
n, err := ByteDocToTree(doc)
if err != nil {
return nil, err
}
m := make(map[string]interface{})
m[n.key] = n.treeToMap(r)
return m, nil
}
// ByteDocToTree - convert an XML doc into a tree of nodes.
func ByteDocToTree(doc []byte) (*Node, error) {
// xml.Decoder doesn't properly handle whitespace in some doc
// see songTextString.xml test case ...
reg, _ := regexp.Compile("[ \t\n\r]*<")
doc = reg.ReplaceAll(doc, []byte("<"))
b := bytes.NewBuffer(doc)
p := xml.NewDecoder(b)
p.CharsetReader = X2jCharsetReader
n, berr := xmlToTree("", nil, p)
if berr != nil {
return nil, berr
}
return n, nil
}

127
vendor/github.com/beego/x2j/x2j_bulk.go generated vendored Normal file
View File

@ -0,0 +1,127 @@
// Copyright 2012-2013 Charles Banning. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file
// x2j_bulk.go: Process files with multiple XML messages.
// Extends x2m_bulk.go to work with JSON strings rather than map[string]interface{}.
package x2j
import (
"bytes"
"encoding/json"
"io"
"os"
"regexp"
)
// XmlMsgsFromFileAsJson()
// 'fname' is name of file
// 'phandler' is the JSON string processing handler. Return of 'false' stops further processing.
// 'ehandler' is the parsing error handler. Return of 'false' stops further processing and returns error.
// Note: phandler() and ehandler() calls are blocking, so reading and processing of messages is serialized.
// This means that you can stop reading the file on error or after processing a particular message.
// To have reading and handling run concurrently, pass arguments to a go routine in handler and return true.
func XmlMsgsFromFileAsJson(fname string, phandler func(string)(bool), ehandler func(error)(bool), recast ...bool) error {
var r bool
if len(recast) == 1 {
r = recast[0]
}
fi, fierr := os.Stat(fname)
if fierr != nil {
return fierr
}
fh, fherr := os.Open(fname)
if fherr != nil {
return fherr
}
defer fh.Close()
buf := make([]byte,fi.Size())
_, rerr := fh.Read(buf)
if rerr != nil {
return rerr
}
doc := string(buf)
// xml.Decoder doesn't properly handle whitespace in some doc
// see songTextString.xml test case ...
reg,_ := regexp.Compile("[ \t\n\r]*<")
doc = reg.ReplaceAllString(doc,"<")
b := bytes.NewBufferString(doc)
for {
s, serr := XmlBufferToJson(b,r)
if serr != nil && serr != io.EOF {
if ok := ehandler(serr); !ok {
// caused reader termination
return serr
}
}
if s != "" {
if ok := phandler(s); !ok {
break
}
}
if serr == io.EOF {
break
}
}
return nil
}
// XmlBufferToJson - process XML message from a bytes.Buffer
// 'b' is the buffer
// Optional argument 'recast' coerces values to float64 or bool where possible.
func XmlBufferToJson(b *bytes.Buffer,recast ...bool) (string,error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
n,err := XmlBufferToTree(b)
if err != nil {
return "", err
}
m := make(map[string]interface{})
m[n.key] = n.treeToMap(r)
j, jerr := json.Marshal(m)
return string(j), jerr
}
// ============================= io.Reader version for stream processing ======================
// XmlMsgsFromReaderAsJson() - io.Reader version of XmlMsgsFromFileAsJson
// 'rdr' is an io.Reader for an XML message (stream)
// 'phandler' is the JSON string processing handler. Return of 'false' stops further processing.
// 'ehandler' is the parsing error handler. Return of 'false' stops further processing and returns error.
// Note: phandler() and ehandler() calls are blocking, so reading and processing of messages is serialized.
// This means that you can stop reading the file on error or after processing a particular message.
// To have reading and handling run concurrently, pass arguments to a go routine in handler and return true.
func XmlMsgsFromReaderAsJson(rdr io.Reader, phandler func(string)(bool), ehandler func(error)(bool), recast ...bool) error {
var r bool
if len(recast) == 1 {
r = recast[0]
}
for {
s, serr := ToJson(rdr,r)
if serr != nil && serr != io.EOF {
if ok := ehandler(serr); !ok {
// caused reader termination
return serr
}
}
if s != "" {
if ok := phandler(s); !ok {
break
}
}
if serr == io.EOF {
break
}
}
return nil
}

29
vendor/github.com/beego/x2j/x2j_test.xml generated vendored Normal file
View File

@ -0,0 +1,29 @@
<msg mtype="alert" mpriority="1">
<text>help me!</text>
<song title="A Long Time" author="Mayer Hawthorne">
<verses>
<verse name="verse 1" no="1">
<line no="1">Henry was a renegade</line>
<line no="2">Didn't like to play it safe</line>
<line no="3">One component at a time</line>
<line no="4">There's got to be a better way</line>
<line no="5">Oh, people came from miles around</line>
<line no="6">Searching for a steady job</line>
<line no="7">Welcome to the Motor Town</line>
<line no="8">Booming like an atom bomb</line>
</verse>
<verse name="verse 2" no="2">
<line no="1">Oh, Henry was the end of the story</line>
<line no="2">Then everything went wrong</line>
<line no="3">And we'll return it to its former glory</line>
<line no="4">But it just takes so long</line>
</verse>
</verses>
<chorus>
<line no="1">It's going to take a long time</line>
<line no="2">It's going to take it, but we'll make it one day</line>
<line no="3">It's going to take a long time</line>
<line no="4">It's going to take it, but we'll make it one day</line>
</chorus>
</song>
</msg>

125
vendor/github.com/beego/x2j/x2j_valuesFrom.go generated vendored Normal file
View File

@ -0,0 +1,125 @@
// Copyright 2012-2013 Charles Banning. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file
// x2j_valuesFrom.go: Extract values from an arbitrary XML doc. Tag path can include wildcard characters.
package x2j
import (
"strings"
)
// ------------------- sweep up everything for some point in the node tree ---------------------
// ValuesFromTagPath - deliver all values for a path node from a XML doc
// If there are no values for the path 'nil' is returned.
// A return value of (nil, nil) means that there were no values and no errors parsing the doc.
// 'doc' is the XML document
// 'path' is a dot-separated path of tag nodes
// 'getAttrs' can be set 'true' to return attribute values for "*"-terminated path
// If a node is '*', then everything beyond is scanned for values.
// E.g., "doc.books' might return a single value 'book' of type []interface{}, but
// "doc.books.*" could return all the 'book' entries as []map[string]interface{}.
// "doc.books.*.author" might return all the 'author' tag values as []string - or
// "doc.books.*.author.lastname" might be required, depending on he schema.
func ValuesFromTagPath(doc, path string, getAttrs ...bool) ([]interface{}, error) {
var a bool
if len(getAttrs) == 1 {
a = getAttrs[0]
}
m, err := DocToMap(doc)
if err != nil {
return nil, err
}
v := ValuesFromKeyPath(m, path, a)
return v, nil
}
// ValuesFromKeyPath - deliver all values for a path node from a map[string]interface{}
// If there are no values for the path 'nil' is returned.
// 'm' is the map to be walked
// 'path' is a dot-separated path of key values
// 'getAttrs' can be set 'true' to return attribute values for "*"-terminated path
// If a node is '*', then everything beyond is walked.
// E.g., see ValuesFromTagPath documentation.
func ValuesFromKeyPath(m map[string]interface{}, path string, getAttrs ...bool) []interface{} {
var a bool
if len(getAttrs) == 1 {
a = getAttrs[0]
}
keys := strings.Split(path, ".")
ret := make([]interface{}, 0)
valuesFromKeyPath(&ret, m, keys, a)
if len(ret) == 0 {
return nil
}
return ret
}
func valuesFromKeyPath(ret *[]interface{}, m interface{}, keys []string, getAttrs bool) {
lenKeys := len(keys)
// load 'm' values into 'ret'
// expand any lists
if lenKeys == 0 {
switch m.(type) {
case map[string]interface{}:
*ret = append(*ret, m)
case []interface{}:
for _, v := range m.([]interface{}) {
*ret = append(*ret, v)
}
default:
*ret = append(*ret, m)
}
return
}
// key of interest
key := keys[0]
switch key {
case "*": // wildcard - scan all values
switch m.(type) {
case map[string]interface{}:
for k, v := range m.(map[string]interface{}) {
if string(k[:1]) == "-" && !getAttrs { // skip attributes?
continue
}
valuesFromKeyPath(ret, v, keys[1:], getAttrs)
}
case []interface{}:
for _, v := range m.([]interface{}) {
switch v.(type) {
// flatten out a list of maps - keys are processed
case map[string]interface{}:
for kk, vv := range v.(map[string]interface{}) {
if string(kk[:1]) == "-" && !getAttrs { // skip attributes?
continue
}
valuesFromKeyPath(ret, vv, keys[1:], getAttrs)
}
default:
valuesFromKeyPath(ret, v, keys[1:], getAttrs)
}
}
}
default: // key - must be map[string]interface{}
switch m.(type) {
case map[string]interface{}:
if v, ok := m.(map[string]interface{})[key]; ok {
valuesFromKeyPath(ret, v, keys[1:], getAttrs)
}
case []interface{}: // may be buried in list
for _, v := range m.([]interface{}) {
switch v.(type) {
case map[string]interface{}:
if vv, ok := v.(map[string]interface{})[key]; ok {
valuesFromKeyPath(ret, vv, keys[1:], getAttrs)
}
}
}
}
}
}

201
vendor/github.com/beego/x2j/x2m_bulk.go generated vendored Normal file
View File

@ -0,0 +1,201 @@
// Copyright 2012-2013 Charles Banning. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file
// x2m_bulk.go: Process files with multiple XML messages.
package x2j
import (
"bytes"
"encoding/xml"
"errors"
"io"
"os"
"regexp"
"sync"
)
// XmlMsgsFromFile()
// 'fname' is name of file
// 'phandler' is the map processing handler. Return of 'false' stops further processing.
// 'ehandler' is the parsing error handler. Return of 'false' stops further processing and returns error.
// Note: phandler() and ehandler() calls are blocking, so reading and processing of messages is serialized.
// This means that you can stop reading the file on error or after processing a particular message.
// To have reading and handling run concurrently, pass arguments to a go routine in handler and return true.
func XmlMsgsFromFile(fname string, phandler func(map[string]interface{})(bool), ehandler func(error)(bool), recast ...bool) error {
var r bool
if len(recast) == 1 {
r = recast[0]
}
fi, fierr := os.Stat(fname)
if fierr != nil {
return fierr
}
fh, fherr := os.Open(fname)
if fherr != nil {
return fherr
}
defer fh.Close()
buf := make([]byte,fi.Size())
_, rerr := fh.Read(buf)
if rerr != nil {
return rerr
}
doc := string(buf)
// xml.Decoder doesn't properly handle whitespace in some doc
// see songTextString.xml test case ...
reg,_ := regexp.Compile("[ \t\n\r]*<")
doc = reg.ReplaceAllString(doc,"<")
b := bytes.NewBufferString(doc)
for {
m, merr := XmlBufferToMap(b,r)
if merr != nil && merr != io.EOF {
if ok := ehandler(merr); !ok {
// caused reader termination
return merr
}
}
if m != nil {
if ok := phandler(m); !ok {
break
}
}
if merr == io.EOF {
break
}
}
return nil
}
// XmlBufferToMap - process XML message from a bytes.Buffer
// 'b' is the buffer
// Optional argument 'recast' coerces map values to float64 or bool where possible.
func XmlBufferToMap(b *bytes.Buffer,recast ...bool) (map[string]interface{},error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
n,err := XmlBufferToTree(b)
if err != nil {
return nil, err
}
m := make(map[string]interface{})
m[n.key] = n.treeToMap(r)
return m,nil
}
// BufferToTree - derived from DocToTree()
func XmlBufferToTree(b *bytes.Buffer) (*Node, error) {
p := xml.NewDecoder(b)
p.CharsetReader = X2jCharsetReader
n, berr := xmlToTree("",nil,p)
if berr != nil {
return nil, berr
}
return n,nil
}
// XmlBuffer - create XML decoder buffer for a string from anywhere, not necessarily a file.
type XmlBuffer struct {
cnt uint64
str *string
buf *bytes.Buffer
}
var mtx sync.Mutex
var cnt uint64
var activeXmlBufs = make(map[uint64]*XmlBuffer)
// NewXmlBuffer() - creates a bytes.Buffer from a string with multiple messages
// Use Close() function to release the buffer for garbage collection.
func NewXmlBuffer(s string) *XmlBuffer {
// xml.Decoder doesn't properly handle whitespace in some doc
// see songTextString.xml test case ...
reg,_ := regexp.Compile("[ \t\n\r]*<")
s = reg.ReplaceAllString(s,"<")
b := bytes.NewBufferString(s)
buf := new(XmlBuffer)
buf.str = &s
buf.buf = b
mtx.Lock()
defer mtx.Unlock()
buf.cnt = cnt ; cnt++
activeXmlBufs[buf.cnt] = buf
return buf
}
// BytesNewXmlBuffer() - creates a bytes.Buffer from b with possibly multiple messages
// Use Close() function to release the buffer for garbage collection.
func BytesNewXmlBuffer(b []byte) *XmlBuffer {
bb := bytes.NewBuffer(b)
buf := new(XmlBuffer)
buf.buf = bb
mtx.Lock()
defer mtx.Unlock()
buf.cnt = cnt ; cnt++
activeXmlBufs[buf.cnt] = buf
return buf
}
// Close() - release the buffer address for garbage collection
func (buf *XmlBuffer)Close() {
mtx.Lock()
defer mtx.Unlock()
delete(activeXmlBufs,buf.cnt)
}
// NextMap() - retrieve next XML message in buffer as a map[string]interface{} value.
// The optional argument 'recast' will try and coerce values to float64 or bool as appropriate.
func (buf *XmlBuffer)NextMap(recast ...bool) (map[string]interface{}, error) {
var r bool
if len(recast) == 1 {
r = recast[0]
}
if _, ok := activeXmlBufs[buf.cnt]; !ok {
return nil, errors.New("Buffer is not active.")
}
return XmlBufferToMap(buf.buf,r)
}
// ============================= io.Reader version for stream processing ======================
// XmlMsgsFromReader() - io.Reader version of XmlMsgsFromFile
// 'rdr' is an io.Reader for an XML message (stream)
// 'phandler' is the map processing handler. Return of 'false' stops further processing.
// 'ehandler' is the parsing error handler. Return of 'false' stops further processing and returns error.
// Note: phandler() and ehandler() calls are blocking, so reading and processing of messages is serialized.
// This means that you can stop reading the file on error or after processing a particular message.
// To have reading and handling run concurrently, pass arguments to a go routine in handler and return true.
func XmlMsgsFromReader(rdr io.Reader, phandler func(map[string]interface{})(bool), ehandler func(error)(bool), recast ...bool) error {
var r bool
if len(recast) == 1 {
r = recast[0]
}
for {
m, merr := ToMap(rdr,r)
if merr != nil && merr != io.EOF {
if ok := ehandler(merr); !ok {
// caused reader termination
return merr
}
}
if m != nil {
if ok := phandler(m); !ok {
break
}
}
if merr == io.EOF {
break
}
}
return nil
}

67
vendor/github.com/beego/x2j/x2m_bulk.xml generated vendored Normal file
View File

@ -0,0 +1,67 @@
<msg mtype="alert" mpriority="1">
<text>help me!</text>
<song title="A Long Time" author="Mayer Hawthorne">
<verses>
<verse name="verse 1" no="1">
<line no="1">Henry was a renegade</line>
<line no="2">Didn't like to play it safe</line>
<line no="3">One component at a time</line>
<line no="4">There's got to be a better way</line>
<line no="5">Oh, people came from miles around</line>
<line no="6">Searching for a steady job</line>
<line no="7">Welcome to the Motor Town</line>
<line no="8">Booming like an atom bomb</line>
</verse>
<verse name="verse 2" no="2">
<line no="1">Oh, Henry was the end of the story</line>
<line no="2">Then everything went wrong</line>
<line no="3">And we'll return it to its former glory</line>
<line no="4">But it just takes so long</line>
</verse>
</verses>
<chorus>
<line no="1">It's going to take a long time</line>
<line no="2">It's going to take it, but we'll make it one day</line>
<line no="3">It's going to take a long time</line>
<line no="4">It's going to take it, but we'll make it one day</line>
</chorus>
</song>
</msg>
<msg mtype="alert" mpriority="1">
<text>help me!</text>
<song title="A Long Time" author="Mayer Hawthorne">
<verses>
<verse name="verse 1" no="1">
<line no="1">Henry was a renegade</line>
<line no="2">Didn't like to play it safe</line>
<line no="3">One component at a time</line>
<line no="4">There's got to be a better way</line>
<line no="5">Oh, people came from miles around</line>
<line no="6">Searching for a steady job</line>
<line no="7">Welcome to the Motor Town</line>
<line no="8">Booming like an atom bomb</line>
</verse>
</verses>
</song>
</msg>
<msg mtype="alert" mpriority="1">
<text>help me!</text>
<song title="A Long Time" author="Mayer Hawthorne">
<chorus>
<line no="1">It's going to take a long time</line>
<line no="2">It's going to take it, but we'll make it one day</line>
<line no="3">It's going to take a long time</line>
<line no="4">It's going to take it, but we'll make it one day</line>
</chorus>
</song>
</msg>
<msg mtype="alert" mpriority="1">
<text>help me!</text>
<song title="A Long Time" author="Mayer Hawthorne">
<chorus>
<line no="1">It's going to take a long time</line>
<line no="2">It's going to take it, but we'll make it one day</line>
<line no="3">It's going to take a long time</line>
<line no="4">It's going to take it, but we'll make it one day</line>
</song>
</msg>