mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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
3 changed files with 66 additions and 13 deletions
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
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 {
|
||||||
// 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:
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
||||||
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) {
|
||||||
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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
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{
|
||||||
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{
|
||||||
},
|
},
|
||||||
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).
|
||||||
},
|
},
|
||||||
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 {
|
||||||
|
|
||||||
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) {
|
||||||
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) {
|
||||||
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")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue