Looking for tips on how to decode one ugly ball of JSON

agolangf · · 516 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hi,</p> <p>I&#39;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 &#34;withdraw&#34; and &#34;announce&#34; are optional :</p> <pre><code>{ &#34;time&#34;: 1452881855, &#34;host&#34;: &#34;localhost.localdomain&#34;, &#34;pid&#34;: &#34;7245&#34;, &#34;ppid&#34;: &#34;7244&#34;, &#34;counter&#34;: 3, &#34;type&#34;: &#34;update&#34;, &#34;neighbor&#34;: { &#34;ip&#34;: &#34;192.168.56.103&#34;, &#34;address&#34;: { &#34;local&#34;: &#34;192.168.56.102&#34;, &#34;peer&#34;: &#34;192.168.56.103&#34; }, &#34;asn&#34;: { &#34;local&#34;: &#34;65000&#34;, &#34;peer&#34;: &#34;65000&#34; }, &#34;message&#34;: { &#34;update&#34;: { &#34;attribute&#34;: { &#34;origin&#34;: &#34;igp&#34;, &#34;local-preference&#34;: 100, &#34;extended-community&#34;: [842122844570372] }, &#34;announce&#34;: { &#34;ipv4 mpls-vpn&#34;: { &#34;101.1.101.1&#34;: { &#34;2.6.0.0/16&#34;: { &#34;label&#34;: [1001], &#34;route-distinguisher&#34;: &#34;65000:1&#34; } } } }, &#34;withdraw&#34;: { &#34;ipv4 mpls-vpn&#34;: { &#34;1.2.3.0/25&#34;: { &#34;label&#34;: [1001], &#34;route-distinguisher&#34;: &#34;65000:1&#34; } } } } } } </code></pre> <p>The parts in the [&#34;message&#34;][&#34;Update&#34;] are the challenging ones and identify the gateway/subnet parts of the routes. I&#39;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&#39;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&#39;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 &#34;update&#34;, there may be an &#34;announce&#34; and/or &#34;withdraw&#34; section. </p> <blockquote> <pre><code>&#34;message&#34;: { &#34;update&#34;: { &#34;attribute&#34;: { &#34;origin&#34;: &#34;igp&#34;, &#34;local-preference&#34;: 100, &#34;extended-community&#34;: [842122844570372] }, &#34;announce&#34;: { &#34;ipv4 mpls-vpn&#34;: { &#34;101.1.101.1&#34;: { &#34;2.6.0.0/16&#34;: { &#34;label&#34;: [1001], &#34;route-distinguisher&#34;: &#34;65000:1&#34; } } } }, &#34;withdraw&#34;: { &#34;ipv4 mpls-vpn&#34;: { &#34;1.2.3.0/25&#34;: { &#34;label&#34;: [1001], &#34;route-distinguisher&#34;: &#34;65000:1&#34; } } } </code></pre> </blockquote> <p>In this section, the IP address, &#34;101.1.101.1&#34; 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 &#34;2.6.0.0/16&#34; subnet address underneath.</p> <blockquote> <pre><code> &#34;101.1.101.1&#34;: { &#34;2.6.0.0/16&#34;: { &#34;label&#34;: [1001], &#34;route-distinguisher&#34;: &#34;65000:1&#34; } </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&#39;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 &#34;update&#34; 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&#39;m thinking this is just not a good application for Go</p></pre>russ-: <pre><p>Assuming I&#39;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 &#34;ipv4 mpls-vpn&#34; 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&#39;d change it to use arrays of structured objects where it&#39;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&#39;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&#39;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 &#34;announce&#34; part and/or a &#34;withdraw&#34; 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

516 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传