mirror of
https://github.com/golang/go
synced 2024-11-12 09:50:21 -07:00
make reader more useful
for lower-level clients: * expose p.Skip * expose p.Unmarshal * wildcard struct field "Any" * unmarshal into bool * unmarshal into xml.Name * unmarshal into pointer R=r DELTA=61 (50 added, 5 deleted, 6 changed) OCL=35372 CL=35422
This commit is contained in:
parent
c2ec9583a0
commit
cfdb3a5639
@ -94,6 +94,8 @@ import (
|
|||||||
// * If the XML element contains a sub-element whose name
|
// * If the XML element contains a sub-element whose name
|
||||||
// matches a struct field whose tag is neither "attr" nor "chardata",
|
// matches a struct field whose tag is neither "attr" nor "chardata",
|
||||||
// Unmarshal maps the sub-element to that struct field.
|
// Unmarshal maps the sub-element to that struct field.
|
||||||
|
// Otherwise, if the struct has a field named Any, unmarshal
|
||||||
|
// maps the sub-element to that struct field.
|
||||||
//
|
//
|
||||||
// Unmarshal maps an XML element to a string or []byte by saving the
|
// Unmarshal maps an XML element to a string or []byte by saving the
|
||||||
// concatenation of that elements character data in the string or []byte.
|
// concatenation of that elements character data in the string or []byte.
|
||||||
@ -101,6 +103,14 @@ import (
|
|||||||
// Unmarshal maps an XML element to a slice by extending the length
|
// Unmarshal maps an XML element to a slice by extending the length
|
||||||
// of the slice and mapping the element to the newly created value.
|
// of the slice and mapping the element to the newly created value.
|
||||||
//
|
//
|
||||||
|
// Unmarshal maps an XML element to a bool by setting the bool to true.
|
||||||
|
//
|
||||||
|
// Unmarshal maps an XML element to an xml.Name by recording the
|
||||||
|
// element name.
|
||||||
|
//
|
||||||
|
// Unmarshal maps an XML element to a pointer by setting the pointer
|
||||||
|
// to a freshly allocated value and then mapping the element to that value.
|
||||||
|
//
|
||||||
func Unmarshal(r io.Reader, val interface{}) os.Error {
|
func Unmarshal(r io.Reader, val interface{}) os.Error {
|
||||||
v, ok := reflect.NewValue(val).(*reflect.PtrValue);
|
v, ok := reflect.NewValue(val).(*reflect.PtrValue);
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -108,14 +118,9 @@ func Unmarshal(r io.Reader, val interface{}) os.Error {
|
|||||||
}
|
}
|
||||||
p := NewParser(r);
|
p := NewParser(r);
|
||||||
elem := v.Elem();
|
elem := v.Elem();
|
||||||
for {
|
err := p.unmarshal(elem, nil);
|
||||||
err := p.unmarshal(elem, nil);
|
if err != nil {
|
||||||
if err != nil {
|
return err;
|
||||||
if err == os.EOF {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@ -126,6 +131,20 @@ func (e UnmarshalError) String() string {
|
|||||||
return string(e);
|
return string(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The Parser's Unmarshal method is like xml.Unmarshal
|
||||||
|
// except that it can be passed a pointer to the initial start element,
|
||||||
|
// useful when a client reads some raw XML tokens itself
|
||||||
|
// but also defers to Unmarshal for some elements.
|
||||||
|
// Passing a nil start element indicates that Unmarshal should
|
||||||
|
// read the token stream to find the start element.
|
||||||
|
func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
|
||||||
|
v, ok := reflect.NewValue(val).(*reflect.PtrValue);
|
||||||
|
if !ok {
|
||||||
|
return os.NewError("non-pointer passed to Unmarshal");
|
||||||
|
}
|
||||||
|
return p.unmarshal(v.Elem(), start);
|
||||||
|
}
|
||||||
|
|
||||||
// Unmarshal a single XML element into val.
|
// Unmarshal a single XML element into val.
|
||||||
func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
||||||
// Find start element if we need it.
|
// Find start element if we need it.
|
||||||
@ -142,6 +161,12 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pv, ok := val.(*reflect.PtrValue); ok {
|
||||||
|
zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem());
|
||||||
|
pv.PointTo(zv);
|
||||||
|
val = zv;
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
data []byte;
|
data []byte;
|
||||||
saveData reflect.Value;
|
saveData reflect.Value;
|
||||||
@ -149,6 +174,9 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
|||||||
styp *reflect.StructType;
|
styp *reflect.StructType;
|
||||||
)
|
)
|
||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
|
case *reflect.BoolValue:
|
||||||
|
v.Set(true);
|
||||||
|
|
||||||
case *reflect.SliceValue:
|
case *reflect.SliceValue:
|
||||||
typ := v.Type().(*reflect.SliceType);
|
typ := v.Type().(*reflect.SliceType);
|
||||||
if _, ok := typ.Elem().(*reflect.Uint8Type); ok {
|
if _, ok := typ.Elem().(*reflect.Uint8Type); ok {
|
||||||
@ -182,6 +210,11 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
|
|||||||
saveData = v;
|
saveData = v;
|
||||||
|
|
||||||
case *reflect.StructValue:
|
case *reflect.StructValue:
|
||||||
|
if _, ok := v.Interface().(Name); ok {
|
||||||
|
v.Set(reflect.NewValue(start.Name).(*reflect.StructValue));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
sv = v;
|
sv = v;
|
||||||
typ := sv.Type().(*reflect.StructType);
|
typ := sv.Type().(*reflect.StructType);
|
||||||
styp = typ;
|
styp = typ;
|
||||||
@ -257,8 +290,11 @@ Loop:
|
|||||||
switch t := tok.(type) {
|
switch t := tok.(type) {
|
||||||
case StartElement:
|
case StartElement:
|
||||||
// Sub-element.
|
// Sub-element.
|
||||||
|
// Look up by tag name.
|
||||||
|
// If that fails, fall back to mop-up field named "Any".
|
||||||
if sv != nil {
|
if sv != nil {
|
||||||
k := strings.ToLower(t.Name.Local);
|
k := strings.ToLower(t.Name.Local);
|
||||||
|
any := -1;
|
||||||
for i, n := 0, styp.NumField(); i < n; i++ {
|
for i, n := 0, styp.NumField(); i < n; i++ {
|
||||||
f := styp.Field(i);
|
f := styp.Field(i);
|
||||||
if strings.ToLower(f.Name) == k {
|
if strings.ToLower(f.Name) == k {
|
||||||
@ -267,10 +303,19 @@ Loop:
|
|||||||
}
|
}
|
||||||
continue Loop;
|
continue Loop;
|
||||||
}
|
}
|
||||||
|
if any < 0 && f.Name == "Any" {
|
||||||
|
any = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if any >= 0 {
|
||||||
|
if err := p.unmarshal(sv.FieldByIndex(styp.Field(any).Index), &t); err != nil {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
continue Loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Not saving sub-element but still have to skip over it.
|
// Not saving sub-element but still have to skip over it.
|
||||||
if err := p.skip(); err != nil {
|
if err := p.Skip(); err != nil {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +346,7 @@ Loop:
|
|||||||
// Read tokens until we find the end element.
|
// Read tokens until we find the end element.
|
||||||
// Token is taking care of making sure the
|
// Token is taking care of making sure the
|
||||||
// end element matches the start element we saw.
|
// end element matches the start element we saw.
|
||||||
func (p *Parser) skip() os.Error {
|
func (p *Parser) Skip() os.Error {
|
||||||
for {
|
for {
|
||||||
tok, err := p.Token();
|
tok, err := p.Token();
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -309,7 +354,7 @@ func (p *Parser) skip() os.Error {
|
|||||||
}
|
}
|
||||||
switch t := tok.(type) {
|
switch t := tok.(type) {
|
||||||
case StartElement:
|
case StartElement:
|
||||||
if err := p.skip(); err != nil {
|
if err := p.Skip(); err != nil {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
case EndElement:
|
case EndElement:
|
||||||
|
Loading…
Reference in New Issue
Block a user