This is my XML data:
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/generic.qcow2'/>
<backingStore/>
<target dev='hda' bus='ide'/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
and my struct is:
// struct for get device details from xml
type DiskXmlInfo struct {
Devices []Disk `xml:"devices>disk"`
}
type Disk struct {
Type string `xml:"device,attr"`
// Name string `xml:"target>dev,attr"`
Name string `xml:"target>dev,attr"`
}
I cannot get the target attribute name. How to get the target attribute name?
Thanks in advance.
You can't read attributes with path, like "target> dev,attr". One option is to use separate type for the target, as you already use for the disk:
type Target struct {
Dev string `xml:"dev,attr"`
Bus string `xml:"bus,attr"`
}
type Disk struct {
...
Target Target `xml:"target"`
}
Another option is to use custom unmarshaller.
Related
Hello I'm new at golang and programming and i have a noobish question. i couldn't find the answer on google. The soap server fails with generated code by gowsdl. but i add this xmlns="" to auth tag its works like a charm. So how can i add this to tags not by strings replace but go idiomatic way?
Not accepted by server
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<GetCitiesRequest xmlns="http://www.n11.com/ws/schemas">
<auth> <<<<<<<<<<<<<<<<------------ fails because no xmlns=""
<appKey>xxx</appKey>
<appSecret>xx</appSecret>
</auth>
</GetCitiesRequest>
</Body>
</Envelope>
Accepted by server
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<GetCitiesRequest xmlns="http://www.n11.com/ws/schemas">
<auth xmlns="">
<appKey>[string]</appKey>
<appSecret>[string]</appSecret>
</auth>
</GetCitiesRequest>
</Body>
</Envelope>
im using quick fix:
buffers := new(bytes.Buffer)
buffers.WriteString(strings.ReplaceAll(buffer.String(),"<auth>","<auth xmlns=\"\">"))
req, err := http.NewRequest("POST", s.url, buffers)
what should i add struct tag to see empty xmlns="" ?
type GetCitiesRequest struct {
XMLName xml.Name `xml:"http://www.n11.com/ws/schemas GetCitiesRequest"`
Auth *Authentication `xml:"auth,omitempty" json:"auth,omitempty"`
}
type Authentication struct {
AppKey string `xml:"appKey,omitempty" json:"appKey,omitempty"`
AppSecret string `xml:"appSecret,omitempty" json:"appSecret,omitempty"`
}
Alos i tried;
type Authentication struct {
XMLName xml.Name `xml:""`
AppKey string `xml:"appKey,omitempty" json:"appKey,omitempty"`
AppSecret string `xml:"appSecret,omitempty" json:"appSecret,omitempty"`
}
auth := Authentication{AppKey:"secret",AppSecret:"secret"}
auth.XMLName.Local= "auth"
auth.XMLName.Space = ""
Also i tried auth.XMLName.Space = " " empty space but xml.marshal transform it to escaped character like ""e,#34"
I want to understand how can i do with like pro way but not noob way.
Any help appreciated.
Thank you.
another problem :/ not solved
tried xml:"* categoryId" turns out -> <categoryId xmlns="*">1001770</categoryId>
yet soap api not accepting * character wants <categoryId xmlns="">1001770</categoryId>
type Authentication struct {
Xmlns string `xml:"xmlns,attr" json:"-"`
AppKey string `xml:"appKey,omitempty" json:"appKey,omitempty"`
AppSecret string `xml:"appSecret,omitempty" json:"appSecret,omitempty"`
}
type GetSubCategoriesRequest struct {
XMLName xml.Name `xml:"http://www.n11.com/ws/schemas GetSubCategoriesRequest"`
Auth *Authentication `xml:"auth,omitempty" json:"auth,omitempty"`
CategoryId int64 `xml:"* categoryId,omitempty" json:"categoryId,omitempty"` <<<<<<<-------- i need xmlns=""
}
any help?
https://golang.org/pkg/encoding/xml/#Marshal
a field with tag "name,attr" becomes an attribute with the given name in the XML element.
a field with tag ",attr" becomes an attribute with the field name in the XML element.
type Authentication struct {
Xmlns string `xml:"xmlns,attr" json:"-"`
AppKey string `xml:"appKey,omitempty" json:"appKey,omitempty"`
AppSecret string `xml:"appSecret,omitempty" json:"appSecret,omitempty"`
}
https://play.golang.org/p/iIvlUoaYvgB
I'm new to Go and working with a set of types generated by gowsdl based on the NetSuite SuiteTalk web service definition. It has created the following types:
type BaseRef struct {
XMLName xml.Name `xml:"urn:core_2018_2.platform.webservices.netsuite.com BaseRef"`
Name string `xml:"name,omitempty"`
}
type RecordRef struct {
XMLName xml.Name `xml:"urn:core_2018_2.platform.webservices.netsuite.com RecordRef"`
*BaseRef
InternalId string `xml:"internalId,attr,omitempty"`
ExternalId string `xml:"externalId,attr,omitempty"`
Type *RecordType `xml:"type,attr,omitempty"`
}
type GetRequest struct {
XMLName xml.Name `xml:"urn:messages_2018_2.platform.webservices.netsuite.com GetRequest"`
BaseRef *BaseRef `xml:"baseRef,omitempty"`
}
As I try to use these types it is unhappy in my ability to use the specific type of reference record in a GetRequest structure which is looking for a BaseRef which is what RecordRef is based on.
var partnerRecordType RecordType
partnerRecordType = RecordTypePartner
recordRef := RecordRef{
Type:&partnerRecordType,
InternalId:internalIdString,
}
var getRequest GetRequest
getRequest.BaseRef = &recordRef
The error I get is on the last line is:
cannot use &recordRef (type *RecordRef) as type *BaseRef in assignment
Any thoughts on how to proceed?
Go does not support polymorphism in this way, neither does it support inheritance in way that say C# or Java does. Embedded structs are quite literally just embedded, they do not create a classical inheritance hierarchy. They simply give the wrapping struct all of the exposed methods and fields of the embedded struct (with some subtle caveats - check out the spec)
That said, in your example RecordRef is not related to BaseRef in terms of its type, instead it could be considered to "contain" a pointer to a BaseRef. In order for your program to compile, you will have explicitly assign the embedded BaseRef like so:
getRequest.BaseRef = &recordRef.BaseRef
As this code you are referencing has been auto generated from a WSDL, it may be a little cumbersome to update the GetRequest to provide a BaseRef like data structure in a more polymorphic, flexible fashion, but in order to do so you will need to use Go interfaces.
You could update the GetRequest to have a method with accepts in interface type, say XmlRef which would expose getters that can derive the data you need to assign to the GetRequest
For example
type XmlRef interface {
Name() string
InternalID() string
ExternalID() string
}
func (r *GetRequest) SetRef(ref XmlRef) {
r.BaseRef.Name = ref.Name()
// etc...
}
Then simply implement the interface for RecordRef and any other structs that would need to be used in this context.
If I understand you right, you are looking for a method to access a struct's embbed field. You can simply use recordRef.BaseRef for that purpose.
Further reading: https://golang.org/ref/spec#Struct_types
It is possible to connect to netsuite with the output of go2wsdl but many tweaks are required. A full proof of concept is available here:
https://github.com/mk-j/go-netsuite-soap
But here are some examples of some of the tweaks required:
sed -i 's/urn:.*1.lists.webservices.netsuite.com //' netsuite.go
Tweaking BaseRef and GetRequest:
type BaseRef struct {
Name string `xml:"name,omitempty" json:"name,omitempty"`
InternalId string `xml:"internalId,attr,omitempty" json:"internalId,omitempty"`
ExternalId string `xml:"externalId,attr,omitempty" json:"externalId,omitempty"`
Type *RecordType `xml:"type,attr,omitempty" json:"type,omitempty"`
XsiType string `xml:"xsi:type,attr,omitempty"`
}
type GetRequest struct {
XMLName xml.Name `xml:"get"`
XmlNSXSI string `xml:"xmlns:xsi,attr"`
XmlNSPC string `xml:"xmlns:platformCore,attr"`
BaseRef *BaseRef `xml:"baseRef,omitempty" json:"baseRef,omitempty"`
}
Then this code produced an successful xml response from the soap server:
recordType := netsuite.RecordTypePartner
baseRef :=netsuite.BaseRef{
InternalId:"1234",
Type:&recordType,
XsiType:"platformCore:RecordRef",
}
request := netsuite.GetRequest{
BaseRef:&baseRef,
XmlNSXSI: "http://www.w3.org/2001/XMLSchema-instance",
XmlNSPC:"urn:core_2022_1.platform.webservices.netsuite.com",
}
getResponse, err := service.Get(&request)
Which made the raw request:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header><tokenPassport>[redacted]</tokenPassport></soap:Header>
<soap:Body>
<get xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:platformCore="urn:core_2022_1.platform.webservices.netsuite.com">
<baseRef internalId="1234" type="partner" xsi:type="platformCore:RecordRef"></baseRef>
</get>
</soap:Body>
</soap:Envelope>
Sources used: https://www.zuar.com/blog/netsuite-api-exploring-soap/
I have such xml document and I need to get an array of DATA. I cannot solve this simple task for 4 hours.... want back to node.js :-)
<?xml version="1.0" standalone="no"?>
<RETS ReplyCode="0" ReplyText="Operation Successful" >
<COUNT Records="58951" />
<DELIMITER value="09"/>
<COLUMNS> LN </COLUMNS>
<DATA> 09361303 </DATA>
<DATA> 09333085 </DATA>
<MAXROWS/>
type DATA struct {
DATA string `xml:"DATA"`
}
type Rets struct {
DATA []DATA `xml:"RETS>DATA"`
}
data := &Rets{}
decoder := xml.Unmarshal(body,&data)
fmt.Println(decoder)
There are a couple of tools for turning XML into Go structs. One that is suitable for reading is zek (try it online), and although it is experimental, it can deal with a couple of common XML constructs already.
You can go from a XML file (raw) to a struct with a simple command:
$ curl -sL https://git.io/fN4Pq | zek -e -p -c
This will create a struct plus an example program for testing out the marshalling (the example does very little, it read XML from stdin and turns it into JSON).
Here is an example struct (for some XML take from this repo):
// RETS was generated 2018-09-07 12:11:10 by tir on apollo.local.
type RETS struct {
XMLName xml.Name `xml:"RETS"`
Text string `xml:",chardata"`
ReplyCode string `xml:"ReplyCode,attr"`
ReplyText string `xml:"ReplyText,attr"`
METADATATABLE struct {
Text string `xml:",chardata"`
Resource string `xml:"Resource,attr"`
Class string `xml:"Class,attr"`
Version string `xml:"Version,attr"`
Date string `xml:"Date,attr"`
COLUMNS string `xml:"COLUMNS"` // MetadataEntryID SystemNam...
DATA []string `xml:"DATA"` // 7 City City Ci ...
} `xml:"METADATA-TABLE"`
}
Disclaimer: I wrote zek.
From the xml.Unmarshal docs
If the XML element contains character data, that data is
accumulated in the first struct field that has tag ",chardata".
The struct field may have type []byte or string.
If there is no such field, the character data is discarded.
Use
type DATA struct {
DATA string `xml:",chardata"`
}
type Rets struct {
DATA []DATA `xml:"DATA"`
}
Or in this simple case, you can just use
type Rets struct {
DATA []string `xml:"DATA"`
}
Which collects the charadata from a list of elements by default
We have the following setup in our schema.xml:
<field name="last_modified" type="date" indexed="true" stored="true" multiValued="false" omitTermFreqAndPositions="true"/>
...
<field name="prefix" type="string" indexed="true" stored="true" omitTermFreqAndPositions="true"/>
Our goal is to sort the docs by
prefix=9999 with newest docs (last modified) first
prefix=1004 or prefix=1005 with newest docs (last modified) first
Our code:
{!boost b=recip(ms(NOW,last_modified),3.16e11,1,1)}prefix:9999^1000000 OR {!boost b=recip(ms(NOW,last_modified),3.16e-11,1,1)}prefix:1004^600000 OR {!boost b=recip(ms(NOW,last_modified),3.16e-11,1,1)}prefix:1005^600000
Result:
The query above does not work as expected!
We thought that omitTermFreqAndPositions=true will force to prevent ITF and the scoring should work. But it does not seem so!
Please help us with this :-)
So we found a solution!
Create your own Similarity (a simple java class)
For a better and simpler descriptions how, please read How to compile a custom similarity class for SOLR / Lucene using Eclipse
The class we used
package com.luxactive;
import org.apache.lucene.index.FieldInvertState;
import org.apache.lucene.search.similarities.DefaultSimilarity;
public class MyNewSimilarityClass extends DefaultSimilarity {
#Override
public float coord(int overlap, int maxOverlap) {
return 1.0f;
}
#Override
public float idf(long docFreq, long numDocs) {
return 1.0f;
}
#Override
public float lengthNorm(FieldInvertState arg0) {
return 1.0f;
}
#Override
public float tf(float freq) {
return 1.0f;
}
}
Create a simple jar with your Similarity
Copy the jar to any folder into your solr server, we used:
SOLRFOLDER/solr-4.8.0/example/solr/dih
The next steps need to be done to every collection you have!
Edit the solrconfig.xml at: SOLRFOLDER/solr-4.8.0/example/solr/collection/conf/solrconfig.xml
Add <lib dir="../dih" regex=".*\.jar" /> to import the custom jar
Edit the schema.xml in the same folder
Add the following
<!-- DEFAULT Factory for custom com.luxactive.MyNewSimilarityClass -->
<similarity class="solr.SchemaSimilarityFactory"/>
<!-- TYPE String -->
<fieldType name="no_term_frequency_string" class="solr.StrField" sortMissingLast="true" >
<similarity class="com.luxactive.MyNewSimilarityClass"/>
</fieldType>
<!-- TYPE Date -->
<fieldType name="no_term_frequency_date" class="solr.TrieDateField" sortMissingLast="true" >
<similarity class="com.luxactive.MyNewSimilarityClass"/>
</fieldType>
<!-- TYPE Int-->
<fieldType name="no_term_frequency_int" class="solr.TrieIntField" sortMissingLast="true" >
<similarity class="com.luxactive.MyNewSimilarityClass"/>
</fieldType>
Here you define your own field types (int, string and date) that use the new Similarity class which will return a boost value like defined in the MyNewSimilarityClass.
Now edit the fields you want to use your custom Similaritry by setting theyr type to one you created.
From: <field name="last_modified" type="date" indexed="true" stored="true" multiValued="false" />
To: <field name="last_modified" type="no_term_frequency_date" indexed="true" stored="true" multiValued="false" />
Restart the solr server and enjoy your boosting :)
I am consuming a REST API that returns XML and am trying to Unmarshal the XML and am having issues that appear that the omitempty is not working. Here is an example of a working XML file:
<?xml version='1.0' encoding='UTF-8'?>
<customer uri="/api/customers/339/" id="339">
<name>
<first>Firstname</first>
<last>Lastname</last>
</name>
<email>myemail#example.com</email>
<billing>
<address>
<address1>123 Main St.</address123>
<address2></address2>
<city>Nowhere</city>
<state>IA</state>
<country>USA</country>
<zip>12345</zip>
</address>
</billing>
</customer>
Here is an example of a "bad" record
<?xml version='1.0' encoding='UTF-8'?>
<customer uri="/api/customers/6848/" id="6848">
<name>
<first>Firstname</first>
<last>Lastname</last>
</name>
<email/>
<billing/>
</customer>
Now I have my structs set up like the following:
type Customer struct {
ID int `xml:"id,attr"`
Name *Name `xml:"name,omitempty"`
Billing *Billing `xml:"billing,omitempty"`
}
type Billing struct {
Address *Address `xml:"address,omitempty"`
}
type Address struct {
address_1 string `xml:",omitempty"`
address_2 string `xml:",omitempty"`
city string `xml:",omitempty"`
postal string `xml:",omitempty"`
country string `xml:",omitempty"`
}
type Name struct {
first, last string
}
Reading through all of the records it works when the XML follows the pattern of the first example <billing></billing> but when it hits a record that has something like <billing/> it throws the following error: panic: runtime error: invalid memory address or nil pointer dereference
Can someone help me figure out what's going on and how to resolve it?
You're probably misunderstanding what ,omitempty means. It takes effect when marshalling data, only. If you unmarshal <billing/> onto a pointer field with ,omitempty, it will still initialize the field. Then, since the XML element is empty, the fields of Billing itself won't be set. In practice, if you assume that customer.Billing != nil means customer.Billing.Address != nil, you'll get the observed panic.
Note: http://play.golang.org/p/dClkfOVLXh