]> Cypherpunks repositories - gostls13.git/commitdiff
xml: new "innerxml" tag to collect inner XML
authorRuss Cox <rsc@golang.org>
Wed, 21 Apr 2010 23:27:31 +0000 (16:27 -0700)
committerRuss Cox <rsc@golang.org>
Wed, 21 Apr 2010 23:27:31 +0000 (16:27 -0700)
R=r
CC=golang-dev
https://golang.org/cl/971041

src/pkg/xml/read.go
src/pkg/xml/read_test.go
src/pkg/xml/xml.go

index 45db7daa36500328b1db2cccaeb6e6bd5cd99f0a..9204660b37ea7d5767fa48b9c191cd06dffbab2b 100644 (file)
@@ -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
 }
 
index 3b8d572ec9f797bc04ea8b73bcfce0d1d47c7de2..68bb010f2f247e3b170df65f1407ffc848541361 100644 (file)
@@ -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{
index 3737fbec91f994647522b0c847dafc8a6de4a8a2..410b0f77cac1efcf7bd4e2ad6e9dc1c1e951e788 100644 (file)
@@ -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")