Commit e7b6fe39 authored by Russ Cox's avatar Russ Cox

xml: new "innerxml" tag to collect inner XML

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