Go XML suppression of automatically generated tags? - go

I'm trying to implement an XML format under Go that was originally written in Fortran. The format is already specified so I'm not free to make changes to the standard. Unfortunately, the format includes data that is not enclosed by an XML tag, thus I would like to suppress the automatic tag creation provided by xml.Marshal.
I've investigated all the standard option associated with marshalling,as documented at : https://golang.org/pkg/encoding/xml/
By default marshalling will use the structure variable name, which can be overridden by the xml: definition. As far as I can tell there is no definition that suppresses the tag name.
type SAO_FREQUENCY_LIST struct {
Type string `xml:",attr"`
SigFig int `xml:",attr"`
Units string `xml:",attr"`
Description string `xml:",attr"`
Frequencies string `xml:""`
}
I want the XML output to be as follows:
<FrequencyList Type="float" SigFig="5" Units="MHz" Description="Nominal Frequency">
3.7 3.8
</FrequencyList>"
By default xml.MarshalIndent(..) yields:
<FrequencyList Type="float" SigFig="5" Units="MHz" Description="”Nominal Frequency">
<Frequencies>3.7 3.8</Frequencies>
</FrequencyList>

You can use the ,chardata modifier to indicate that the value of a struct member should be used as character data for the XML element. For your example, this would be:
type FrequencyList struct {
...
Frequencies string `xml:",chardata"`
}
You can experiment with an example using this change here: https://play.golang.org/p/oBa8HuE-57d

Related

Fetch value from XML using dynamic tag in ESQL

I have an xml
<family>
<child_one>ROY</child_one>
<child_two>VIC</child_two>
</family>
I want to fetch the value from the XML based on the dynamic tag in ESQL. I have tried like this
SET dynamicTag = 'child_'||num;
SET value = InputRoot.XMLNSC.parent.(XML.Element)dynamicTag;
Here num is the value received from the input it can be one or two. The result should be value = ROY if num is one and value is VIC if num is two.
The chapter ESQL field reference overview describes this use case:
Because the names of the fields appear in the ESQL program, they must be known when the program is written. This limitation can be avoided by using the alternative syntax that uses braces ( { ... } ).
So can change your code like this:
SET value = InputRoot.XMLNSC.parent.(XMLNSC.Element){dynamicTag};
Notice the change of the element type as well, see comment of #kimbert.

Lookup field by tag

Consider the following struct
type Test struct {
A string `t1:"x"`,
B string `t1:"y"`,
}
Using the reflect package, is there any way for me to get "A" if I know that t1 tag has value "x"?
Using the reflect package, is there any way for me to get "A" if I know that t1 tag has value "x"?
Not a direct one.
You must iterate over all fields and check if the field has the appropriate tag.
(Note that two fields may have the same tag, so looking up by tag would not really work.)

How do I make protobuf case-insensitive?

I have a protobuf contract like this,
message Car{
string carId = 1;
}
I generate java classes from this contract and use it to parse JSON request.
Now if my JSON has "CarID" or "carid" then protobuf generated java classes don't recognize that field. How do I make it case-insensitive?
The protobuff descriptor (.proto) are case insensitive. If you try to compile:
message Car{
string carId = 1;
string carid =2;
}
You will have the compilation error:
CARID_FIELD_NUMBER is already defined in ...
Also you have to know that for proto3, the JSON parser are dealing with lowerCamelCase. As stated on reference guide:
https://developers.google.com/protocol-buffers/docs/proto3#json
Use proto field name instead of lowerCamelCase name: By default proto3
JSON printer should convert the field name to lowerCamelCase and use
that as the JSON name. An implementation may provide an option to use
proto field name as the JSON name instead. Proto3 JSON parsers are
required to accept both the converted lowerCamelCase name and the
proto field name.
From your parser point of view "carID" and "CarID" are the same, because it will automatically convert "CarID" to "carID". But "carId" and "carid" will always be different.

How to return localized content from WebAPI? Strings work but not numbers

Given this ApiController:
public string TestString() {
return "The value is: " + 1.23;
}
public double TestDouble() {
return 1.23;
}
With the browser's language set to "fr-FR", the following happens:
/apiController/TestString yields
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">The value is: 1,23</string>
/apiController/TestDouble yields
<double xmlns="http://schemas.microsoft.com/2003/10/Serialization/">1.23</double>
I would expect TestDouble() to yield 1,23 in the XML. Can anyone explain why this isn't the case and, more importantly, how to make it so that it does?
It is because the conversion from double to string happens at different stage for each API. For the TestString API, double.ToString() is used to convert the number to a string using CurrentCulture of the current thread and it happens when the TestString method is called. Meanwhile, the double number which is returned by TestDouble is serialized to string during the serialization step which uses GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Culture.
In my opinion, both should use InvariantCulture. On the consumer side, the values will be parsed and be formatted with the correct culture.
Update: this is only used for JsonFormatter. XmlFormatter doesn't have such a setting.
Update 2:
It seems (decimal) numbers need special converter to make it culture-aware:
Handling decimal values in Newtonsoft.Json
Btw, if you want o change data format per action/request, you can try the last piece of code of the following link: http://tostring.it/2012/07/18/customize-json-result-in-web-api/

Unmarshal with global namespace

I have the following XML:
<rss version="2.0">
<channel>
...
<item>
<link>http://stackoverflow.com</link>
<atom:link xmlns:atom="http://www.w3.org/2005/Atom" href="http://stackoverflow.com"/>
...
</item>
</channel>
</rss>
I want to extract the link attribute, I have the following struct:
type Item struct {
Link string `xml:"http://www.w3.org/2005/Atom link"`
}
I know, that I need a prefix to get the Link, but because there is no namespace given (in form of an xmls-Attribute, but I don't know, how.
I could, of course, save all :*link-Attributes to a slice, but I'm sure there is a better solution.
Thanks in advance!
The namespace handling in the standard library encoding/xml package seems to be a big ad-hoc, and having elements in different namespaces with the same name seems to be a trigger.
Ideally you'd be able to decode the given XML into the following structures:
type Rss struct {
Items []Item `xml:"channel>item"`
}
type Item struct {
Link string `xml:"link"`
AtomLink AtomLink `xml:"http://www.w3.org/2005/Atom link"`
}
type AtomLink struct {
Href string `xml:"href,attr"`
}
But this results in the error main.Item field "Link" with tag "link" conflicts with field "AtomLink" with tag "http://www.w3.org/2005/Atom link" (as seen in http://play.golang.org/p/LgW-vm4euL).
However, if we decide that we want to ignore the <atom:link> element by commenting out the Item.AtomLink field, we end up decoding an empty string, since xml:"link" matches <link> elements in any namespace rather than just the blank namespace. The final <atom:link> element is empty, so doesn't return anything.
A couple of possible work arounds include:
Only try to decode the <atom:link> element, since it can be selected uniquely. This may not be useful if you're also processing RSS feeds without Atom namespace elements.
Collect the contents of all <link> elements by modifying the Item struct to use:
Links []string `xml:"link"`
And then discard any empty strings in the slice.
At the end of the day, the package will need some way to refer to the blank namespace. That may require new syntax in order to keep existing programs functioning though.

Resources