mirror of
https://github.com/golang/go
synced 2024-11-11 20:01:37 -07:00
xml: new "innerxml" tag to collect inner XML
R=r CC=golang-dev https://golang.org/cl/971041
This commit is contained in:
parent
57d9de3ac8
commit
e7b6fe3989
@ -76,6 +76,10 @@ import (
|
||||
//
|
||||
// Unmarshal maps an XML element to a struct using the following rules:
|
||||
//
|
||||
// * If the struct has a field of type []byte or string with tag "innerxml",
|
||||
// Unmarshal accumulates the raw XML nested inside the element
|
||||
// in that field. The rest of the rules still apply.
|
||||
//
|
||||
// * If the struct has a field named XMLName of type xml.Name,
|
||||
// Unmarshal records the element name in that field.
|
||||
//
|
||||
@ -198,12 +202,15 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
||||
}
|
||||
|
||||
var (
|
||||
data []byte
|
||||
saveData reflect.Value
|
||||
comment []byte
|
||||
saveComment reflect.Value
|
||||
sv *reflect.StructValue
|
||||
styp *reflect.StructType
|
||||
data []byte
|
||||
saveData reflect.Value
|
||||
comment []byte
|
||||
saveComment reflect.Value
|
||||
saveXML reflect.Value
|
||||
saveXMLIndex int
|
||||
saveXMLData []byte
|
||||
sv *reflect.StructValue
|
||||
styp *reflect.StructType
|
||||
)
|
||||
switch v := val.(type) {
|
||||
default:
|
||||
@ -316,6 +323,17 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
||||
if saveData == nil {
|
||||
saveData = sv.FieldByIndex(f.Index)
|
||||
}
|
||||
|
||||
case "innerxml":
|
||||
if saveXML == nil {
|
||||
saveXML = sv.FieldByIndex(f.Index)
|
||||
if p.saved == nil {
|
||||
saveXMLIndex = 0
|
||||
p.saved = new(bytes.Buffer)
|
||||
} else {
|
||||
saveXMLIndex = p.savedOffset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -324,6 +342,10 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
||||
// Process sub-elements along the way.
|
||||
Loop:
|
||||
for {
|
||||
var savedOffset int
|
||||
if saveXML != nil {
|
||||
savedOffset = p.savedOffset()
|
||||
}
|
||||
tok, err := p.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -361,6 +383,12 @@ Loop:
|
||||
}
|
||||
|
||||
case EndElement:
|
||||
if saveXML != nil {
|
||||
saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
|
||||
if saveXMLIndex == 0 {
|
||||
p.saved = nil
|
||||
}
|
||||
}
|
||||
break Loop
|
||||
|
||||
case CharData:
|
||||
@ -491,6 +519,13 @@ Loop:
|
||||
t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
|
||||
}
|
||||
|
||||
switch t := saveXML.(type) {
|
||||
case *reflect.StringValue:
|
||||
t.Set(string(saveXMLData))
|
||||
case *reflect.SliceValue:
|
||||
t.Set(reflect.NewValue(saveXMLData).(*reflect.SliceValue))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ func TestUnmarshalFeed(t *testing.T) {
|
||||
t.Fatalf("Unmarshal: %s", err)
|
||||
}
|
||||
if !reflect.DeepEqual(f, rssFeed) {
|
||||
t.Fatalf("have %#v\nwant %#v\n\n%#v", f)
|
||||
t.Fatalf("have %#v\nwant %#v", f, rssFeed)
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,9 +102,10 @@ type Link struct {
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
URI string
|
||||
Email string
|
||||
Name string
|
||||
URI string
|
||||
Email string
|
||||
InnerXML string "innerxml"
|
||||
}
|
||||
|
||||
type Text struct {
|
||||
@ -124,7 +125,8 @@ var rssFeed = Feed{
|
||||
Id: "http://codereview.appspot.com/",
|
||||
Updated: "2009-10-04T01:35:58+00:00",
|
||||
Author: Person{
|
||||
Name: "rietveld",
|
||||
Name: "rietveld",
|
||||
InnerXML: "<name>rietveld</name>",
|
||||
},
|
||||
Entry: []Entry{
|
||||
Entry{
|
||||
@ -134,7 +136,8 @@ var rssFeed = Feed{
|
||||
},
|
||||
Updated: "2009-10-04T01:35:58+00:00",
|
||||
Author: Person{
|
||||
Name: "email-address-removed",
|
||||
Name: "email-address-removed",
|
||||
InnerXML: "<name>email-address-removed</name>",
|
||||
},
|
||||
Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a",
|
||||
Summary: Text{
|
||||
@ -180,7 +183,8 @@ the top of feeds.py marked NOTE(rsc).
|
||||
},
|
||||
Updated: "2009-10-03T23:02:17+00:00",
|
||||
Author: Person{
|
||||
Name: "email-address-removed",
|
||||
Name: "email-address-removed",
|
||||
InnerXML: "<name>email-address-removed</name>",
|
||||
},
|
||||
Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a",
|
||||
Summary: Text{
|
||||
|
@ -165,6 +165,7 @@ type Parser struct {
|
||||
|
||||
r io.ReadByter
|
||||
buf bytes.Buffer
|
||||
saved *bytes.Buffer
|
||||
stk *stack
|
||||
free *stack
|
||||
needClose bool
|
||||
@ -698,6 +699,9 @@ func (p *Parser) getc() (b byte, ok bool) {
|
||||
if p.err != nil {
|
||||
return 0, false
|
||||
}
|
||||
if p.saved != nil {
|
||||
p.saved.WriteByte(b)
|
||||
}
|
||||
}
|
||||
if b == '\n' {
|
||||
p.line++
|
||||
@ -705,6 +709,16 @@ func (p *Parser) getc() (b byte, ok bool) {
|
||||
return b, true
|
||||
}
|
||||
|
||||
// Return saved offset.
|
||||
// If we did ungetc (nextByte >= 0), have to back up one.
|
||||
func (p *Parser) savedOffset() int {
|
||||
n := p.saved.Len()
|
||||
if p.nextByte >= 0 {
|
||||
n--
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Must read a single byte.
|
||||
// If there is no byte to read,
|
||||
// set p.err to SyntaxError("unexpected EOF")
|
||||
|
Loading…
Reference in New Issue
Block a user