mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
encoding/xml: predefine xml name space prefix
Also change prefix generation to use more human-friendly prefixes. Fixes #5040. R=golang-dev, r, bradfitz CC=golang-dev https://golang.org/cl/7777047
This commit is contained in:
parent
8c2b6226f7
commit
bdf8bf6adc
3 changed files with 97 additions and 21 deletions
|
|
@ -126,6 +126,70 @@ type printer struct {
|
|||
depth int
|
||||
indentedIn bool
|
||||
putNewline bool
|
||||
attrNS map[string]string // map prefix -> name space
|
||||
attrPrefix map[string]string // map name space -> prefix
|
||||
}
|
||||
|
||||
// createAttrPrefix finds the name space prefix attribute to use for the given name space,
|
||||
// defining a new prefix if necessary. It returns the prefix and whether it is new.
|
||||
func (p *printer) createAttrPrefix(url string) (prefix string, isNew bool) {
|
||||
if prefix = p.attrPrefix[url]; prefix != "" {
|
||||
return prefix, false
|
||||
}
|
||||
|
||||
// The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml"
|
||||
// and must be referred to that way.
|
||||
// (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
|
||||
// but users should not be trying to use that one directly - that's our job.)
|
||||
if url == xmlURL {
|
||||
return "xml", false
|
||||
}
|
||||
|
||||
// Need to define a new name space.
|
||||
if p.attrPrefix == nil {
|
||||
p.attrPrefix = make(map[string]string)
|
||||
p.attrNS = make(map[string]string)
|
||||
}
|
||||
|
||||
// Pick a name. We try to use the final element of the path
|
||||
// but fall back to _.
|
||||
prefix = strings.TrimRight(url, "/")
|
||||
if i := strings.LastIndex(prefix, "/"); i >= 0 {
|
||||
prefix = prefix[i+1:]
|
||||
}
|
||||
if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
|
||||
prefix = "_"
|
||||
}
|
||||
if strings.HasPrefix(prefix, "xml") {
|
||||
// xmlanything is reserved.
|
||||
prefix = "_" + prefix
|
||||
}
|
||||
if p.attrNS[prefix] != "" {
|
||||
// Name is taken. Find a better one.
|
||||
for p.seq++; ; p.seq++ {
|
||||
if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
|
||||
prefix = id
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.attrPrefix[url] = prefix
|
||||
p.attrNS[prefix] = url
|
||||
|
||||
p.WriteString(`xmlns:`)
|
||||
p.WriteString(prefix)
|
||||
p.WriteString(`="`)
|
||||
EscapeText(p, []byte(url))
|
||||
p.WriteString(`" `)
|
||||
|
||||
return prefix, true
|
||||
}
|
||||
|
||||
// deleteAttrPrefix removes an attribute name space prefix.
|
||||
func (p *printer) deleteAttrPrefix(prefix string) {
|
||||
delete(p.attrPrefix, p.attrNS[prefix])
|
||||
delete(p.attrNS, prefix)
|
||||
}
|
||||
|
||||
// marshalValue writes one or more XML elements representing val.
|
||||
|
|
@ -212,17 +276,11 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
|
|||
}
|
||||
p.WriteByte(' ')
|
||||
if finfo.xmlns != "" {
|
||||
p.WriteString("xmlns:")
|
||||
p.seq++
|
||||
id := "_" + strconv.Itoa(p.seq)
|
||||
p.WriteString(id)
|
||||
p.WriteString(`="`)
|
||||
// TODO: EscapeString, to avoid the allocation.
|
||||
if err := EscapeText(p, []byte(finfo.xmlns)); err != nil {
|
||||
return err
|
||||
prefix, created := p.createAttrPrefix(finfo.xmlns)
|
||||
if created {
|
||||
defer p.deleteAttrPrefix(prefix)
|
||||
}
|
||||
p.WriteString(`" `)
|
||||
p.WriteString(id)
|
||||
p.WriteString(prefix)
|
||||
p.WriteByte(':')
|
||||
}
|
||||
p.WriteString(finfo.name)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue