Commit 6dbed72b authored by Paul Warren's avatar Paul Warren
Browse files

Add support for xml:lang attributes.

Maintain the currently effective xml:lang attribute value, and expose it
to unmarshaled structs with tag ",lang"
parent ad28ff38
......@@ -87,6 +87,10 @@ import (
//
// * A struct field with tag "-" is never unmarshalled into.
//
// * If the struct has a field of type []byte or string with tag
// ",lang", Unmarshal records the value of the currently applicable
// xml:lang declaration.
//
// Unmarshal maps an XML element to a string or []byte by saving the
// concatenation of that element's character data in the string or
// []byte. The saved []byte is never nil.
......@@ -431,6 +435,15 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
}
}
case fLang:
t := finfo.value(sv)
switch t.Kind() {
case reflect.String:
t.SetString(string(p.lang))
case reflect.Slice:
t.Set(reflect.ValueOf(p.lang))
}
case fCharData:
if !saveData.IsValid() {
saveData = finfo.value(sv)
......
......@@ -32,13 +32,14 @@ const (
fElement fieldFlags = 1 << iota
fAttr
fCharData
fLang
fInnerXml
fComment
fAny
fOmitEmpty
fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny
fMode = fElement | fAttr | fCharData | fLang | fInnerXml | fComment | fAny
)
var tinfoMap = make(map[reflect.Type]*typeInfo)
......@@ -132,6 +133,8 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
finfo.flags |= fAttr
case "chardata":
finfo.flags |= fCharData
case "lang":
finfo.flags |= fLang
case "innerxml":
finfo.flags |= fInnerXml
case "comment":
......@@ -148,7 +151,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
switch mode := finfo.flags & fMode; mode {
case 0:
finfo.flags |= fElement
case fAttr, fCharData, fInnerXml, fComment, fAny:
case fAttr, fCharData, fInnerXml, fComment, fAny, fLang:
if f.Name == "XMLName" || tag != "" && mode != fAttr {
valid = false
}
......
......@@ -194,6 +194,7 @@ type Decoder struct {
nextToken Token
nextByte int
ns map[string]string
lang string
err error
line int
offset int64
......@@ -266,6 +267,10 @@ func (d *Decoder) Token() (t Token, err error) {
d.pushNs(a.Name.Local, v, ok)
d.ns[a.Name.Local] = a.Value
}
if a.Name.Space == "xml" && a.Name.Local == "lang" {
d.pushLang(d.lang)
d.lang = a.Value
}
if a.Name.Space == "" && a.Name.Local == "xmlns" {
// Default space for untagged names
v, ok := d.ns[""]
......@@ -340,6 +345,7 @@ type stack struct {
const (
stkStart = iota
stkNs
stkLang
stkEOF
)
......@@ -379,7 +385,7 @@ func (d *Decoder) pushEOF() {
}
// The stkNs entries below a start are associated with that
// element too; skip over them.
for start.next != nil && start.next.kind == stkNs {
for start.next != nil && (start.next.kind == stkNs || start.next.kind == stkLang) {
start = start.next
}
s := d.free
......@@ -418,6 +424,13 @@ func (d *Decoder) pushNs(local string, url string, ok bool) {
s.ok = ok
}
// Record that we are changing the value of xml:lang.
// Store old language in s.name.Local
func (d *Decoder) pushLang(lang string) {
s := d.push(stkLang)
s.name.Local = lang
}
// Creates a SyntaxError with the current line number.
func (d *Decoder) syntaxError(msg string) error {
return &SyntaxError{Msg: msg, Line: d.line}
......@@ -455,10 +468,15 @@ func (d *Decoder) popElement(t *EndElement) bool {
// translations that were associated with the element we just closed.
for d.stk != nil && d.stk.kind != stkStart && d.stk.kind != stkEOF {
s := d.pop()
if s.ok {
d.ns[s.name.Local] = s.name.Space
} else {
delete(d.ns, s.name.Local)
switch {
case s.kind == stkNs:
if s.ok {
d.ns[s.name.Local] = s.name.Space
} else {
delete(d.ns, s.name.Local)
}
case s.kind == stkLang:
d.lang = s.name.Local
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment