英文:
Show namespace prefix in xml.Marshall in go
问题
我正在努力生成一个来自golang的SOAP消息(xml)。我有以下示例。
package main
import (
"encoding/xml"
"fmt"
)
type Envelope struct {
XMLName xml.Name `xml:"Envelope"`
}
func main() {
envelope := Envelope{
XMLName: xml.Name{
Local: "soapenv",
Space: "http://www.w3.org/2003/05/soap-envelope",
},
}
res, _ := xml.Marshal(envelope)
fmt.Print(string(res))
}
这个程序的输出如下所示:
<Envelope></Envelope>
我想要以下带有命名空间前缀的输出:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"></soapenv:Envelope>
有人可以帮我得到我想要的输出吗?
英文:
I'm working on generating a SOAP message(xml) from golang. I have the following example.
package main
import (
"encoding/xml"
"fmt"
)
type Envelope struct {
XMLName xml.Name `xml:"Envelope"`
}
func main() {
envelope := Envelope{
XMLName: xml.Name{
Local: "soapenv",
Space: "http://www.w3.org/2003/05/soap-envelope",
},
}
res, _ := xml.Marshal(envelope)
fmt.Print(string(res))
}
This program prints the output as follows
<Envelope></Envelope>
I want to get the output with namespace prefix as below,
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"></soapenv:Envelope>
Can someone help me to get my desired output??
答案1
得分: 3
你可以在结构体定义中显式地添加xmlns
属性:
type Envelope struct {
XMLName xml.Name `xml:"soapenv:Envelope"`
SoapEnv string `xml:"xmlns:soapenv,attr"`
}
然后实例化它:
e := Envelope{
SoapEnv: "http://www.w3.org/2003/05/soap-envelope",
}
输出结果为:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"></soapenv:Envelope>
更多关于自定义XML的示例,请参考XML文档示例。
英文:
You can add the xmlns
attribute explicitly to your struct definition:
type Envelope struct {
XMLName xml.Name `xml:"soapenv:Envelope"`
SoapEnv string `xml:"xmlns:soapenv,attr"`
}
and then to instantiate it:
e := Envelope{
SoapEnv: "http://www.w3.org/2003/05/soap-envelope",
}
https://go.dev/play/p/LrKNg8PTK2A
Output:
<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"></soapenv:Envelope>
See XML docs example for more XML customizations.
答案2
得分: 1
colm.anseo的答案可以生成你想要的XML。但是生成的XML只是看起来像来自有效模型的XML,但实际上并不是。你将无法使用相同的结构定义对该XML进行解组。
我一整天都在尝试序列化和反序列化XMI,并最终找到了它应该如何工作的线索:你需要在XML标签中完全限定每个节点。也就是说,命名空间(不仅仅是前缀)需要放在标签中定义的名称之前:
type Envelope struct {
XMLName xml.Name `xml:"http://www.w3.org/2003/05/soap-envelope Envelope"`
}
但是你仍然无法得到完全符合你要求的结果。它可能看起来像这样:
<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope"></Envelope>
但至少这是有效的XML,并且应该适合你的用例(假设你的工具链中的其他工具也能正常工作)。你将能够成功解组XML。
问题是,如果你有多个命名空间或需要在属性上使用命名空间会发生什么。同样的情况,将所有标签都用命名空间URL作为前缀。Marshal()会解决如何处理它的问题,例如动态创建命名空间前缀。
示例:
type XMI struct {
XMLName xml.Name `xml:"http://schema.omg.org/spec/XMI/2.1 XMI"`
Version string `xml:"http://schema.omg.org/spec/XMI/2.1 version,attr"`
Model *Model `xml:"http://www.eclipse.org/uml2/5.0.0/UML Model"`
}
这将生成以下XML:
<XMI xmlns="http://schema.omg.org/spec/XMI/2.1" xmlns:_="http://schema.omg.org/spec/XMI/2.1" _:version="2.1">
<Model xmlns="http://www.eclipse.org/uml2/5.0.0/UML" _:id="a7e26bff-10a4-44f7-b225-80e079d812c8" name="model">
<packagedElement _:id="7c141da5-fccf-4da8-8fb8-53bf550f2cfc" xmlns:_XMLSchema-instance="http://www.w3.org/2001/XMLSchema-instance" _XMLSchema-instance:type="uml:PrimitiveType" name="char"></packagedElement>
</Model>
</XMI>
正如你所看到的,Marshal()会为元素生成默认命名空间,并在需要时为属性生成(计算得到的)命名空间前缀。这是有效的XML,但我必须承认很难阅读。
与其他人说golang的encoding/xml有问题不同,我认为它只是...不方便。
英文:
colm.anseo's answer will work for generating XML the way you want it to be. But the generated XML just looks like coming from a valid model, but it isn't. You won't be able to unmarshal that XML with the same struct definition.
I've been fiddling with (de-)serializing XMI the whole day and finally got a clue how it's supposed to work: you need to fully qualify every single node in your xml tags. That is the namespace (not just the prefix) needs to be put in front of the name defined in the tags:
type Envelope struct {
XMLName xml.Name `xml:"http://www.w3.org/2003/05/soap-envelope Envelope"`
}
But still you will not get exactly what you'd like to have. It will most propably look like this:
<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope"></Envelope>
But at least this is valid XML and should fit your use case (assuming other tools in your toolchain play nice). And you will be able to unmarshal XML successfully.
Question is, what happens if you do have more than one namespace or need a namespace on attributes. Well, same story, prefix all tags with the namespace url. Marshal() will sort out how to deal with it, e.g. creating namespace prefixes on the fly.
Example:
type XMI struct {
XMLName xml.Name `xml:"http://schema.omg.org/spec/XMI/2.1 XMI"`
Version string `xml:"http://schema.omg.org/spec/XMI/2.1 version,attr"`
Model *Model `xml:"http://www.eclipse.org/uml2/5.0.0/UML Model"`
}
This will generate XML like this:
<XMI xmlns="http://schema.omg.org/spec/XMI/2.1" xmlns:_="http://schema.omg.org/spec/XMI/2.1" _:version="2.1">
<Model xmlns="http://www.eclipse.org/uml2/5.0.0/UML" _:id="a7e26bff-10a4-44f7-b225-80e079d812c8" name="model">
<packagedElement _:id="7c141da5-fccf-4da8-8fb8-53bf550f2cfc" xmlns:_XMLSchema-instance="http://www.w3.org/2001/XMLSchema-instance" _XMLSchema-instance:type="uml:PrimitiveType" name="char"></packagedElement>
</Model>
</XMI>
As you can see, Marshal() will generate default namespaces for Elements and (computed) namespace prefixes for attributes when required. Valid XML, but hard to read I have to admit.
In contrast to others saying golang's encoding/xml is broken, I think it's just... inconvenient.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论