新增gxml解析xml,开发中

This commit is contained in:
John
2017-12-29 00:03:32 +08:00
parent 7fdf2ca870
commit 0df40febf1
5 changed files with 396 additions and 47 deletions

View File

@ -7,7 +7,7 @@ import (
"strconv"
)
// 这是一个使用go进行json语法解析的解析器效率没有官方的json解析高仅作学习参考
// 这是一个自己开发的,使用go进行json语法解析的解析器效率没有官方的json解析高仅作学习参考
const (
gJSON_CHAR_BRACE_LEFT = rune('{')

232
g/encoding/gxml/gxml.go Normal file
View File

@ -0,0 +1,232 @@
package gxml
import (
"fmt"
"strings"
"strconv"
"io/ioutil"
"encoding/xml"
)
// xml解析结果存放数组
type Xml struct {
// 注意这是一个指针
value *interface{}
}
// 一个xml变量
type XmlVar interface{}
// 编码go变量为xml字符串并返回xml字符串指针
func Encode (v interface{}) ([]byte, error) {
return xml.Marshal(v)
}
// 解码字符串为interface{}变量
func Decode (b []byte) (interface{}, error) {
var v interface{}
if err := DecodeTo(b, &v); err == nil {
return nil, err
} else {
return v, nil
}
}
// 解析xml字符串为go变量注意第二个参数为指针
func DecodeTo (b []byte, v interface{}) error {
return xml.Unmarshal(b, v)
}
// 解析xml字符串为gxml.Xml对象并返回操作对象指针
func DecodeToXml (b []byte) (*Xml, error) {
if v, err := Decode(b); err != nil {
return &Xml{&v}, nil
} else {
return nil, err
}
}
// 加载xml文件内容并转换为xml对象
func Load (path string) (*Xml, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
var result interface{}
if err := xml.Unmarshal(data, &result); err != nil {
return nil, err
}
return &Xml{ &result }, nil
}
// 将变量转换为Xml对象进行处理该变量至少应当是一个map或者array否者转换没有意义
func NewXml(v *interface{}) *Xml {
return &Xml{ v }
}
// 将指定的xml内容转换为指定结构返回查找失败或者转换失败目标对象转换为nil
// 注意第二个参数需要给的是变量地址
func (p *Xml) GetToVar(pattern string, v interface{}) error {
r := p.Get(pattern)
if r != nil {
if t, err := Encode(r); err == nil {
return DecodeTo(t, v)
} else {
return err
}
} else {
v = nil
}
return nil
}
// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与xml类型不匹配那么将会返回nil
func (p *Xml) GetMap(pattern string) map[string]interface{} {
result := p.Get(pattern)
if result != nil {
if r, ok := result.(map[string]interface{}); ok {
return r
}
}
return nil
}
// 将检索值转换为Xml对象指针返回
func (p *Xml) GetXml(pattern string) *Xml {
result := p.Get(pattern)
if result != nil {
return &Xml{&result}
}
return nil
}
// 获得一个数组[]interface{},方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与xml类型不匹配那么将会返回nil
func (p *Xml) GetArray(pattern string) []interface{} {
result := p.Get(pattern)
if result != nil {
if r, ok := result.([]interface{}); ok {
return r
}
}
return nil
}
// 返回指定xml中的string
func (p *Xml) GetString(pattern string) string {
result := p.Get(pattern)
if result != nil {
if r, ok := result.(string); ok {
return r
}
}
return ""
}
// 返回指定xml中的bool
func (p *Xml) GetBool(pattern string) bool {
result := p.Get(pattern)
if result != nil {
str := fmt.Sprintf("%v", result)
if str != "" && str != "0" && str != "false" {
return true
}
}
return false
}
// 返回指定xml中的float64
func (p *Xml) GetFloat64(pattern string) float64 {
result := p.Get(pattern)
if result != nil {
if r, ok := result.(float64); ok {
return r
}
}
return 0
}
// 返回指定xml中的float64->int
func (p *Xml) GetInt(pattern string) int {
return int(p.GetFloat64(pattern))
}
// 返回指定xml中的float64->int64
func (p *Xml) GetInt64(pattern string) int64 {
return int64(p.GetFloat64(pattern))
}
// 根据约定字符串方式访问xml解析数据参数形如 "items.name.first", "list.0"
// 返回的结果类型的interface{},因此需要自己做类型转换
// 如果找不到对应节点的数据返回nil
func (p *Xml) Get(pattern string) interface{} {
var result interface{}
pointer := p.value
array := strings.Split(pattern, ".")
length := len(array)
for i:= 0; i < length; i++ {
switch (*pointer).(type) {
case map[string]interface{}:
if v, ok := (*pointer).(map[string]interface{})[array[i]]; ok {
if i == length - 1 {
result = v
} else {
pointer = &v
}
} else {
return nil
}
case []interface{}:
if isNumeric(array[i]) {
n, err := strconv.Atoi(array[i])
if err == nil && len((*pointer).([]interface{})) > n {
if i == length - 1 {
result = (*pointer).([]interface{})[n]
break;
} else {
pointer = &(*pointer).([]interface{})[n]
}
}
} else {
return nil
}
default:
return nil
}
}
return result
}
// 转换为map[string]interface{}类型,如果转换失败返回nil
func (p *Xml) ToMap() map[string]interface{} {
pointer := p.value
switch (*pointer).(type) {
case map[string]interface{}:
return (*pointer).(map[string]interface{})
default:
return nil
}
}
// 转换为[]interface{}类型,如果转换失败返回nil
func (p *Xml) ToArray() []interface{} {
pointer := p.value
switch (*pointer).(type) {
case []interface{}:
return (*pointer).([]interface{})
default:
return nil
}
}
// 判断所给字符串是否为数字
func isNumeric(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] < byte('0') || s[i] > byte('9') {
return false
}
}
return true
}

View File

@ -0,0 +1,32 @@
package gxml_test
import (
"testing"
"fmt"
"encoding/xml"
)
var content = `<?xml version="1.0" encoding="utf-8"?>
<servers version="1">
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
</servers>`
func Test_Xml(t *testing.T) {
//xml, err := gxml.Decode(bytes.TrimSpace([]byte(content)))
//if err != nil {
// glog.Error(err)
//}
//v := make(map[string]interface{})
v := make([]interface{}, 0)
e := xml.Unmarshal([]byte(content), &v)
fmt.Println(e)
fmt.Println(v)
}

View File

@ -1,5 +1,44 @@
// 通用数据验证工具
// 本来打算取名gvalidator的名字太长了缩写一下
/*
参考https://laravel.com/docs/5.5/validation#available-validation-rules
规则如下:
required 格式required 说明:必需参数
required_if 格式required_if:field,value,... 说明:必需参数(当给定字段值与所给任意值相等时)
required_with 格式required_with:foo,bar,... 说明:必需参数(当所给定任意字段值不为空时)
required_with_all 格式required_with_all:foo,bar,... 说明:必须参数(当所给定所有字段值都不为空时)
date 格式date 说明参数为常用日期类型格式2006-01-02, 20060102, 2006.01.02
date_format 格式date_format:format 说明判断日期是否为指定的日期格式format为Go日期格式(可以包含时间)
email 格式email 说明EMAIL邮箱地址
phone 格式phone 说明:手机号
telephone 格式telephone 说明:国内座机电话号码,"XXXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"、"XXXXXXXX"
passport 格式passport 说明:通用帐号规则(字母开头只能包含字母、数字和下划线长度在6~18之间)
password 格式password 说明:通用密码(任意可见字符长度在6~18之间)
password2 格式password2 说明:中等强度密码(在弱密码的基础上,必须包含大小写字母和数字)
password3 格式password3 说明:强等强度密码(在弱密码的基础上,必须包含大小写字母、数字和特殊字符)
postcode 格式id_number 说明:中国邮政编码
id_number 格式id_number 说明:公民身份证号码
qq 格式qq 说明腾讯QQ号码
ip 格式ip 说明IP地址(IPv4)
mac 格式mac 说明MAC地址
url 格式url 说明URL
length 格式length:min,max 说明参数长度为min到max
min_length 格式min_length:min 说明参数长度最小为min
max_length 格式max_length:max 说明参数长度最大为max
between 格式between:min,max 说明参数大小为min到max
min 格式min:min 说明参数最小为min
max 格式max:max 说明参数最大为max
json 格式json 说明判断数据格式为JSON
xml 格式xml 说明判断数据格式为XML
integer 格式integer 说明:整数
float 格式float 说明:浮点数
boolean 格式boolean 说明:布尔值(1,true,on,yes:true | 0,false,off,no,"":false)
same 格式same:field 说明参数值必需与field参数的值相同
different 格式different:field 说明参数值不能与field参数的值相同
in 格式in:foo,bar,... 说明参数值应该在foo,bar,...中
not_in 格式not_in:foo,bar,... 说明参数值不应该在foo,bar,...中
regex 格式regex:pattern 说明参数值应当满足正则匹配规则pattern(使用preg_match判断)
*/
package gvalid
import (
@ -70,56 +109,104 @@ func CheckRule(value, rule string, values...map[string]string) map[string]string
match = !(value == "")
break
//// 必须字段(当给定字段值与所给任意值相等时)
//case "required_if":
// array := strings.Split(strings.TrimSpace(ruleval), ",")
// for _, v := range array {
// if strings.Compare(value, strings.TrimSpace(v)) == 0 {
// match = true
// break
// }
// }
// break
//
//// 必须字段(当所给定任意字段值不为空时)
//case "required_with":
// $ruleMatch = false;
// $tmpArray = explode(',', $ruleAttr);
// foreach ($tmpArray as $v) {
//if (!empty(self::$_currentData[$v])) {
//$ruleMatch = true;
//break
//}
//}
// break
//
// // 必须字段(当所给定所有字段值都不为空时)
//case "required_with_all":
// $tmpArray = explode(',', $ruleAttr);
// foreach ($tmpArray as $v) {
//if (empty(self::$_currentData[$v])) {
//$ruleMatch = false;
//break
//}
//}
// break
// 必须字段(当给定字段值与所给任意值相等时)
case "required_if":
required := false
array := strings.Split(strings.TrimSpace(ruleval), ",")
// 必须为偶数,才能是键值对匹配
if len(array)%2 == 0 {
for i := 0; i < len(array); {
tk := array[i]
tv := array[i + 1]
if v, ok := params[tk]; ok {
if strings.Compare(tv, v) == 0 {
required = true
break
}
}
i += 2
}
}
if required {
match = !(value == "")
} else {
match = true
}
break
// 必须字段(当所给定任意字段值不为空时)
case "required_with":
required := false
array := strings.Split(strings.TrimSpace(ruleval), ",")
for i := 0; i < len(array); i++ {
if v, ok := params[array[i]]; ok {
if v != "" {
required = true
break
}
}
}
if required {
match = !(value == "")
} else {
match = true
}
break
// 必须字段(当所给定所有字段值都不为空时)
case "required_with_all":
required := true
array := strings.Split(strings.TrimSpace(ruleval), ",")
for i := 0; i < len(array); i++ {
if v, ok := params[array[i]]; ok {
if v == "" {
required = false
break
}
}
}
if required {
match = !(value == "")
} else {
match = true
}
break
// 日期格式,
case "date":
for _, v := range []string{"2006-01-02", "20060102", "2006.01.02"} {
if _, err := gtime.StrToTime(value, v); err == nil {
match = true
break
}
}
break
// 日期格式,需要给定日期格式
case "date":
case "date_format":
if _, err := gtime.StrToTime(value, ruleval); err == nil {
match = true
}
break
// // 两字段值应相同(非敏感字符判断,非类型判断)
//case "same":
// $ruleMatch = (isset(self::$_currentData[$ruleAttr]) && $value == self::$_currentData[$ruleAttr]);
// break
//
// // 两字段值不应相同(非敏感字符判断,非类型判断)
//case "different":
// $ruleMatch = (!isset(self::$_currentData[$ruleAttr]) || $value != self::$_currentData[$ruleAttr]);
// break
// 两字段值应相同(非敏感字符判断,非类型判断)
case "same":
if v, ok := params[ruleval]; ok {
if strings.Compare(value, v) == 0 {
match = true
}
}
break
// 两字段值不应相同(非敏感字符判断,非类型判断)
case "different":
match = true
if v, ok := params[ruleval]; ok {
if strings.Compare(value, v) == 0 {
match = false
}
}
break
// 字段值应当在指定范围中
case "in":
@ -161,9 +248,7 @@ func CheckRule(value, rule string, values...map[string]string) map[string]string
match = gregx.IsMatchString(`^13[\d]{9}$|^14[5,7]{1}\d{8}$|^15[^4]{1}\d{8}$|^17[0,3,5,6,7,8]{1}\d{8}$|^18[\d]{9}$`, value)
break
/*
* 国内座机电话号码:"XXXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"、"XXXXXXXX"
*/
// 国内座机电话号码:"XXXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"、"XXXXXXXX"
case "telephone":
match = gregx.IsMatchString(`^((\d{3,4})|\d{3,4}-)?\d{7,8}$`, value)
break