-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxmlname.go
109 lines (96 loc) · 2.65 KB
/
xmlname.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package dom
import (
"strings"
"unicode"
"unicode/utf8"
)
// TODO: XMLName as struct, with local part and namespace?
// XMLName represents an XML Name according to the specification at https://www.w3.org/TR/xml/#NT-Name.
// The name can be validated using the IsValid() function, which will return true if
// the name is valid, or false if the name is invalid.
type XMLName string
// GetPrefix gets the prefix of the XMLName. For example, the following:
// name := XMLName("pfx:element")
// fmt.Println(name.GetPrefix())
// will output:
// pfx
// XML names without a prefix will return an empty string.
func (n XMLName) GetPrefix() string {
s := string(n)
if index := strings.Index(s, ":"); index >= 0 {
return s[0:index]
}
return ""
}
// GetLocalPart gets the local part of the XMLName. For example, the following:
// name := XMLName("pfx:element")
// fmt.Println(name)
// will output:
// element
func (n XMLName) GetLocalPart() string {
s := string(n)
if index := strings.Index(s, ":"); index >= 0 {
return s[index+1:]
}
return s
}
// IsValid returns true if the given XMLName is valid according to the XML specification.
func (n XMLName) IsValid() bool {
name := string(n)
if len(name) == 0 {
return false
}
// Decode the first rune in the name
r, size := utf8.DecodeRuneInString(string(name))
// RuneError = \xFF\xFD, unicode replacement character.
if r == utf8.RuneError && size == 1 {
return false
}
// Check if the first rune is in the nameStartChars range.
if !unicode.Is(nameStartChars, r) {
return false
}
for size < len(name) {
name = name[size:]
r, size = utf8.DecodeRuneInString(name)
if r == utf8.RuneError && size == 1 {
return false
}
// Check if the decoded rune in the sliced string is in the nameStartChars or nameChars
if !unicode.Is(nameStartChars, r) && !unicode.Is(nameChars, r) {
return false
}
}
return true
}
// nameStartChars is the valid start characters an XML Name must start with.
// Note that the table must be in sorted order, and non overlapping.
var nameStartChars = &unicode.RangeTable{
R16: []unicode.Range16{
{0x003A, 0x003A, 1}, // :
{0x0041, 0x005A, 1}, // A-Z
{0x005F, 0x005F, 1}, // _
{0x0061, 0x007A, 1}, // a-z
{0x00C0, 0x00D6, 1},
{0x00D8, 0x00F6, 1},
{0x00F8, 0x02FF, 1},
{0x0370, 0x037D, 1},
{0x037F, 0x1FFF, 1},
{0x200C, 0x200D, 1},
{0x2070, 0x218F, 1},
{0x2C00, 0x2FEF, 1},
{0x3001, 0xD7FF, 1},
{0xF900, 0xFDCF, 1},
{0xFDF0, 0xFFFD, 1},
},
}
var nameChars = &unicode.RangeTable{
R16: []unicode.Range16{
{0x002D, 0x002D, 1}, // -
{0x002E, 0x002E, 1}, // .
{0x0030, 0x0039, 1}, // 0-9
{0x00B7, 0x00B7, 1},
{0x0300, 0x036F, 1},
{0x203F, 0x2040, 1},
},
}