dongyunwei8596 2017-07-26 17:08 采纳率: 100%
浏览 39
已采纳

Golang将XML属性编组为接口

I'm trying to unmarshal some XML into a structure with an interface{} type. However whenever I try to run it, the code doesn't pick up anything at all. All of the other elements appear to work fine, and if I set the type to string or []byte it will work, however I need it to be more flexible than that.

The element I am interested in is on line 32 - FloorRefID

https://play.golang.org/p/Ehr8qx1aWf

<?xml version="1.0" encoding="UTF-8"?>
    <Locations totalPages="1" currentPage="1" pageSize="25">
       <WirelessClientLocation macAddress="00:00:00:00:00:00">
          <MapInfo mapHierarchyString="Head office&gt;Ground floor&gt;Store" floorRefId="-1122334455667789">
             <Image imageName="floorPlan1.png" />
          </MapInfo>
          <MapCoordinate x="2850" y="3000" unit="FEET" />
       </WirelessClientLocation>
       <WirelessClientLocation macAddress="11:11:11:11:11:11">
          <MapInfo mapHierarchyString="Head office&gt;Ground floor&gt;Store" floorRefId="-1122334455667789">
            <Image imageName="floorPlan1.png" />
          </MapInfo>
          <MapCoordinate x="10.72" y="76.49" unit="FEET" />
       </WirelessClientLocation>
       <WirelessClientLocation macAddress="26:cd:96:46:0b:2b">
          <MapInfo floorRefId="0" />
          <MapCoordinate x="51.52" y="4.2" unit="FEET" />
       </WirelessClientLocation>
    </Locations>

To give some context; I am working on a project integrating with a vendor in which sometimes we receive the data as XML and sometimes as JSON. I wanted to build something that could unmarshal the structure for both, rather than duplicating the structure set. It has many substructures which means that its a lot more work to keep 2 structures which are almost identical except for this one attribute.

When we receive the JSON data, the field can be given as a string or a number.

I have read that you cannot unmarshal into an interface, but does anyone know of a way around this issue for my scenario?

  • 写回答

1条回答 默认 最新

  • dongpiao1983 2017-07-26 17:23
    关注

    Its important to check the returned error always.

    if err := xml.Unmarshal([]byte(xmlRawData), &xmlData); err != nil {
        fmt.Println(err)
    }
    

    The error you're getting is

    cannot unmarshal into interface {}
    

    Empty interface cannot be unmarshalled since the empty interface doesn't have any exported fields to map the xml keys/values to.

    However there is way to get around. Implementing xml.Unmarshaler interface on your VendorMapInfo struct.

    Example: Your updated code

    type VendorMapInfo struct {
        MapHierarchyString string      `xml:"mapHierarchyString,attr"`
        FloorRefID         interface{} `xml:"floorRefId,attr"`
        Image              Image       `xml:"Image"`
        FloorDimension     VendorFloorDimension
    }
    
    type Image struct {
        Name string `xml:"imageName,attr"`
    }
    
    func (mf *VendorMapInfo) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
        // Attributes
        for _, attr := range start.Attr {
            switch attr.Name.Local {
            case "mapHierarchyString":
                mf.MapHierarchyString = attr.Value
            case "floorRefId":
                mf.FloorRefID = findFloorRefIDType(attr.Value)
            }
        }
    
        for {
            token, err := d.Token()
            if err != nil {
                return err
            }
    
            switch el := token.(type) {
            case xml.StartElement:
                if el.Name.Local == "Image" {
                    item := new(Image)
                    if err = d.DecodeElement(item, &el); err != nil {
                        return err
                    }
                    mf.Image = *item
                }
            case xml.EndElement:
                if el == start.End() {
                    return nil
                }
            }
        }
    
        return nil
    }
    

    Complete code, play link: https://play.golang.org/p/wZQOsQv0Nq

    Output:

    {Locations:{Space: Local:} WirelessClientLocation:[{MacAddress:00:00:00:00:00:00 MapInfo:{MapHierarchyString:Head office>Ground floor>Store FloorRefID:-1122334455667789 Image:{Name:floorPlan1.png} FloorDimension:{Length:0 Width:0 Height:0 OffsetX:0 OffsetY:0 Unit:}}} {MacAddress:11:11:11:11:11:11 MapInfo:{MapHierarchyString:Head office>Ground floor>Store FloorRefID:-1122334455667789 Image:{Name:floorPlan1.png} FloorDimension:{Length:0 Width:0 Height:0 OffsetX:0 OffsetY:0 Unit:}}} {MacAddress:26:cd:96:46:0b:2b MapInfo:{MapHierarchyString: FloorRefID:0 Image:{Name:} FloorDimension:{Length:0 Width:0 Height:0 OffsetX:0 OffsetY:0 Unit:}}}]}
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)