<p>I am building a server that will receive varying structured XML payloads. Some will be similar but with added/missing nodes, some will be a totally different object.</p>
<p>Luckily I can read the root node and figure out the type of object, but even then I have to first unmarshal the XML to find out what type it is.</p>
<pre><code><Message Type="sometype">
</code></pre>
<p>or</p>
<pre><code><Message Type="someothertype">
</code></pre>
<p>The built in XML processor requires a rigid struct, so I am tinkering with <a href="https://github.com/clbanning/mxj" rel="nofollow">https://github.com/clbanning/mxj</a> which allows me to decode into a map[string]interface{} type. This is pretty ugly still and requires multiple node and type checks.</p>
<pre><code>mv, _ := mxj.NewMapXml([]byte(XML))
var t map[string]interface{}
if mv["Message"] != nil {
t = mv["Message"].(map[string]interface{})
if t["-Type"] != nil {
switch t["-Type"] {
case "sometype":
processSomeType(XML)
case "someothertype:
processSomeOtherType(XML)
}
}
}
</code></pre>
<p>Is there a better way than decoding twice? I think if I can accurately pull the Type out without decoding the entire thing into map[string]interface{} then re-decoding it into one of my rigid structs I will be fine. </p>
<p>One thought was to just build a very basic parser to scan for the type and then decode to whatever struct matches.</p>
<hr/>**评论:**<br/><br/>JokerSp3: <pre><p>I will try to get you a code example later but look at using a custom unmarshal function on a struct that can handle all message types</p></pre>jerf: <pre><p>First, just to set expectations, any convenient mechanism for dealing with XML must necessarily fail on some XML.</p>
<p>But it sounds to me like you will probably be OK with encoding/xml, because the Decoder object has what seems to be a little-understood feature, which is that it can be used as a hybrid of a SAX parser using <code>Token</code> and a struct decoder using <code>DecodeElement</code>. See for example <a href="https://play.golang.org/p/4RE1JpEqVf" rel="nofollow">https://play.golang.org/p/4RE1JpEqVf</a> .</p>
<p>This allows you to examine any wrapper elements up to and including the first element of the thing you want to parse before having to decide on a type, without double-parsing.</p>
<p>The downside is you will do a bit of parsing yourself. You may want to write some convenience functions for doing things like "get me the next start element", since <code>Token</code> will return all the whitespace as char data, for instance.</p></pre>RwKroon: <pre><p>It's not an option to have clients send a header with message type?</p></pre>NikkoTheGreeko: <pre><p>No, It's data coming from a Fortune 50 company. Having them change the API is highly unlikely.</p>
<p>To top of my frustration, it's a brand new system that was just launched and they decided to use XML instead of JSON.</p></pre>RwKroon: <pre><p>Is there some plaintext you can grep on maybe? Cheaper than double decoding...</p></pre>clbanning: <pre><p>clbanning/mxj is not the best for a simple switch{} statement - try something like <a href="https://play.golang.org/p/rKaJVqypx_" rel="nofollow">https://play.golang.org/p/rKaJVqypx_</a></p></pre>NikkoTheGreeko: <pre><p>So you suggest unmarshaling twice?</p></pre>clbanning: <pre><p>Stylistically, that's the simplest unless you want to work with a map[string]interface{} value. If all the "types" are known your code will be much cleaner. clbanning/mxj was originally designed for a message bus where messages could have any structure the connected services wanted to use - there are lots of other examples in clbanning/mxj/examples subdirectory, as well.</p></pre>NikkoTheGreeko: <pre><p>Ya, this is a message bus. I am pretty sure I know ahead of time all the possible different structures, but there are dozens of combinations.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传