<p>Hi,</p>
<p>I'm taking VPNv4 routing updates in JSON format from a BGP control plane. The JSON is non-deterministic and sometimes uses keys as data. This would be a typical output (just note that "withdraw" and "announce" are optional :</p>
<pre><code>{
"time": 1452881855,
"host": "localhost.localdomain",
"pid": "7245",
"ppid": "7244",
"counter": 3,
"type": "update",
"neighbor": {
"ip": "192.168.56.103",
"address": {
"local": "192.168.56.102",
"peer": "192.168.56.103"
},
"asn": {
"local": "65000",
"peer": "65000"
},
"message": {
"update": {
"attribute": {
"origin": "igp",
"local-preference": 100,
"extended-community": [842122844570372]
},
"announce": {
"ipv4 mpls-vpn": {
"101.1.101.1": {
"2.6.0.0/16": {
"label": [1001],
"route-distinguisher": "65000:1"
}
}
}
},
"withdraw": {
"ipv4 mpls-vpn": {
"1.2.3.0/25": {
"label": [1001],
"route-distinguisher": "65000:1"
}
}
}
}
}
}
</code></pre>
<p>The parts in the ["message"]["Update"] are the challenging ones and identify the gateway/subnet parts of the routes. I've tried decoding into a struct for the fixed parts and a raw message for the non-deterministic parts, then converting the raw message to map[string]interface{}, but it is cumbersome and ugly doing all the type asserts. I've done this in Python and it is pretty straight forward, but I was trying to convert this app into Go just to compare languages.</p>
<hr/>**评论:**<br/><br/>alienwork: <pre><p>I've found this tool to be really useful for this kind of thing</p>
<p><a href="https://mholt.github.io/json-to-go/" rel="nofollow">https://mholt.github.io/json-to-go/</a></p></pre>icholy: <pre><p>Which parts are non-deterministic and how?</p></pre>CatButler: <pre><p>Under "update", there may be an "announce" and/or "withdraw" section. </p>
<blockquote>
<pre><code>"message": {
"update": {
"attribute": {
"origin": "igp",
"local-preference": 100,
"extended-community": [842122844570372]
},
"announce": {
"ipv4 mpls-vpn": {
"101.1.101.1": {
"2.6.0.0/16": {
"label": [1001],
"route-distinguisher": "65000:1"
}
}
}
},
"withdraw": {
"ipv4 mpls-vpn": {
"1.2.3.0/25": {
"label": [1001],
"route-distinguisher": "65000:1"
}
}
}
</code></pre>
</blockquote>
<p>In this section, the IP address, "101.1.101.1" is the key, but it is also data. It identifies a gateway. There could be multiple gateways in the message, each keyed by their IP address. The same goes for the "2.6.0.0/16" subnet address underneath.</p>
<blockquote>
<pre><code> "101.1.101.1": {
"2.6.0.0/16": {
"label": [1001],
"route-distinguisher": "65000:1"
}
</code></pre>
</blockquote></pre>tv64738: <pre><p>So, a map inside a map?</p>
<pre><code>type Update struct {
Announce map[string]map[string]Announcement
}
type Announcement struct {
Label []uint32
RouteDistinguisher string
}
</code></pre></pre>CatButler: <pre><p>I've protoyped around parsing only partial message, and came up with this. <a href="https://play.golang.org/p/eVRdxMgs-D" rel="nofollow">https://play.golang.org/p/eVRdxMgs-D</a></p>
<p>I still would have to parse all the way down to the "update" key just to determine if which sections are there, then treat the rest as raw messages. Still that is significantly harder than my Python code. I'm thinking this is just not a good application for Go</p></pre>russ-: <pre><p>Assuming I've understood the problem, and that the keys are unknown but the depths are fixed, I think the piece you are missing is that json.Unmarshal works just fine with map[string]struct{...}. I reworked your prototype with straight Unmarshal, using maps of strings to structs where appropriate: <a href="https://play.golang.org/p/8dAanVHxvO" rel="nofollow">https://play.golang.org/p/8dAanVHxvO</a></p>
<p>If entries in the object keyed by "ipv4 mpls-vpn" can be arbitrarily deep, things get more complicated, but you might still be able to set up e.g. recursive structs to unwind it.</p>
<p>That all said, this is kind of a weird JSON blob, so if changing it is in scope, I'd change it to use arrays of structured objects where it's currently using maps from arbitrary keys to structured objects.</p></pre>CatButler: <pre><blockquote>
<p>I think the piece you are missing is that json.Unmarshal works just fine with map[string]struct{...}</p>
</blockquote>
<p>Ah, now things make sense.</p>
<p>Luckily, no things aren't arbitrarily deep. The Announcement structures repeat, but it is just the keys that are different and not known ahead of time. Sadly, the JSON comes from a 3rd party app, so I don't have control over it. </p>
<p>The JSON is a decode of a Border Gateway Protocol update message. I still have to deal with the fact that it can have an "announce" part and/or a "withdraw" part in the message, but I think I now get the concept.</p>
<p>Thanks.</p></pre>noustuff: <pre><p>Maybe useful - <a href="https://github.com/mitchellh/mapstructure" rel="nofollow">https://github.com/mitchellh/mapstructure</a></p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传