golang从XML自动生成Go结构体定义插件库zek的使用

使用zek库从XML自动生成Go结构体定义

zek是一个用于从XML文档创建Go结构体的原型工具。它由莱比锡大学图书馆开发,旨在缩短从原始XML到可访问XML数据的Go结构体的时间。

基本用法

给定一个XML文件,可以通过以下命令生成Go结构体:

$ curl -s https://raw.githubusercontent.com/miku/zek/master/fixtures/e.xml | zek -e

// Rss was generated 2018-08-30 20:24:14 by tir on sol.
type Rss struct {
    XMLName xml.Name `xml:"rss"`
    Text    string   `xml:",chardata"`
    Rdf     string   `xml:"rdf,attr"`
    Dc      string   `xml:"dc,attr"`
    Geoscan string   `xml:"geoscan,attr"`
    Media   string   `xml:"media,attr"`
    Gml     string   `xml:"gml,attr"`
    Taxo    string   `xml:"taxo,attr"`
    Georss  string   `xml:"georss,attr"`
    Content string   `xml:"content,attr"`
    Geo     string   `xml:"geo,attr"`
    Version string   `xml:"version,attr"`
    Channel struct {
        Text          string `xml:",chardata"`
        Title         string `xml:"title"`         // ESS New Releases (Display...
        Link          string `xml:"link"`          // http://tinyurl.com/ESSNew...
        Description   string `xml:"description"`   // New releases from the Ear...
        LastBuildDate string `xml:"lastBuildDate"` // Mon, 27 Nov 2017 00:06:35...
        Item          []struct {
            Text        string `xml:",chardata"`
            Title       string `xml:"title"`       // Surficial geology, Aberde...
            Link        string `xml:"link"`        // https://geoscan.nrcan.gc....
            Description string `xml:"description"` // Geological Survey of Cana...
            Guid        struct {
                Text        string `xml:",chardata"` // 304279, 306212, 306175, 3...
                IsPermaLink string `xml:"isPermaLink,attr"`
            } `xml:"guid"`
            PubDate       string   `xml:"pubDate"`      // Fri, 24 Nov 2017 00:00:00...
            Polygon       []string `xml:"polygon"`      // 64.0000 -98.0000 64.0000 ...
            Download      string   `xml:"download"`     // https://geoscan.nrcan.gc....
            License       string   `xml:"license"`      // http://data.gc.ca/eng/ope...
            Author        string   `xml:"author"`       // Geological Survey of Cana...
            Source        string   `xml:"source"`       // Geological Survey of Cana...
            SndSeries     string   `xml:"SndSeries"`    // Bedford Institute of Ocea...
            Publisher     string   `xml:"publisher"`    // Natural Resources Canada,...
            Edition       string   `xml:"edition"`      // prelim., surficial data m...
            Meeting       string   `xml:"meeting"`      // Geological Association of...
            Documenttype  string   `xml:"documenttype"` // serial, open file, serial...
            Language      string   `xml:"language"`     // English, English, English...
            Maps          string   `xml:"maps"`         // 1 map, 5 maps, Publicatio...
            Mapinfo       string   `xml:"mapinfo"`      // surficial geology, surfic...
            Medium        string   `xml:"medium"`       // on-line; digital, digital...
            Province      string   `xml:"province"`     // Nunavut, Northwest Territ...
            Nts           string   `xml:"nts"`          // 066B, 095J; 095N; 095O; 0...
            Area          string   `xml:"area"`         // Aberdeen Lake, Mackenzie ...
            Subjects      string   `xml:"subjects"`
            Program       string   `xml:"program"`       // GEM2: Geo-mapping for Ene...
            Project       string   `xml:"project"`       // Rae Province Project Mana...
            Projectnumber string   `xml:"projectnumber"` // 340521, 343202, 340557, 3...
            Abstract      string   `xml:"abstract"`      // This new surficial geolog...
            Links         string   `xml:"links"`         // Online - En ligne (PDF, 9...
            Readme        string   `xml:"readme"`        // readme | https://geoscan....
            PPIid         string   `xml:"PPIid"`         // 34532, 35096, 35438, 2563...
        } `xml:"item"`
    } `xml:"channel"`
}

安装

使用以下命令安装zek:

$ go install github.com/miku/zek/cmd/zek@latest

命令选项

$ zek -h
  -B    use a fixed banner string (e.g. for CI)
  -C    emit less compact struct
  -F    skip formatting
  -I    use verbatim innerxml instead of chardata
  -P string
        if set, write out struct within a package with the given name
  -S int
        read at most this many tags, approximately (0=unlimited)
  -c    emit more compact struct (noop, as this is the default since 0.1.7)
  -d    debug output
  -e    add comments with example
  -j    add JSON tags
  -m    omit empty Text fields
  -max-examples int
        limit number of examples (default 10)
  -n string
        use a different name for the top-level struct
  -o string
        if set, write to output file, not stdout
  -p    write out an example program
  -s    strict parsing and writing
  -t string
        emit struct for tag matching this name
  -u    filter out duplicated examples
  -version
        show version
  -x int
        max chars for example (default 25)

示例程序

zek可以生成一个示例程序来解析XML:

$ zek -C -p < fixtures/a.xml > sample.go && go run sample.go < fixtures/a.xml | jq . && rm sample.go
{
  "XMLName": {
    "Space": "",
    "Local": "a"
  },
  "Text": ""
}

更复杂的示例:

$ zek < fixtures/d.xml
// Root was generated 2019-06-11 16:27:04 by tir on hayiti.
type Root struct {
        XMLName xml.Name `xml:"root"`
        Text    string   `xml:",chardata"`
        A       []struct {
                Text string `xml:",chardata"`
                B    []struct {
                        Text string `xml:",chardata"`
                        C    string `xml:"c"`
                        D    string `xml:"d"`
                } `xml:"b"`
        } `xml:"a"`
}

$ zek -p < fixtures/d.xml > sample.go && go run sample.go < fixtures/d.xml | jq . && rm sample.go
{
  "XMLName": {
    "Space": "",
    "Local": "root"
  },
  "Text": "\n\n\n\n",
  "A": [
    {
      "Text": "\n  \n  \n",
      "B": [
        {
          "Text": "\n    \n  ",
          "C": "Hi",
          "D": ""
        },
        {
          "Text": "\n    \n    \n  ",
          "C": "World",
          "D": ""
        }
      ]
    },
    {
      "Text": "\n  \n",
      "B": [
        {
          "Text": "\n    \n  ",
          "C": "Hello",
          "D": ""
        }
      ]
    },
    {
      "Text": "\n  \n",
      "B": [
        {
          "Text": "\n    \n  ",
          "C": "",
          "D": "World"
        }
      ]
    }
  ]
}

生成包

如果你想在构建过程中包含生成的文件,可以使用-P-o选项:

$ zek -P mypkg -o data.go < fixtures/b.xml

这将在data.go文件中写入以下内容:

// Code generated by zek; DO NOT EDIT.

package mypkg

import "encoding/xml"

// A was generated 2021-09-16 11:23:06 by tir on trieste.
type A struct {
        XMLName xml.Name `xml:"a"`
        Text    string   `xml:",chardata"`
        B       string   `xml:"b"`
}

优缺点

优点:

  • 适用于非递归结构
  • 不需要XSD或DTD
  • 相对方便访问属性、子元素和文本
  • 生成单一结构体,表示形式紧凑
  • 简单的用户界面
  • 带有示例的注释
  • 跨多个文件的模式推断

缺点:

  • 实验性、早期、不稳定原型
  • 不支持递归类型
  • 没有类型推断,所有内容都作为字符串访问

zek是一个有用的工具,可以帮助开发者快速从XML文档生成Go结构体,从而简化XML数据的处理过程。


更多关于golang从XML自动生成Go结构体定义插件库zek的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang从XML自动生成Go结构体定义插件库zek的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用 zek 从 XML 自动生成 Go 结构体定义

zek 是一个强大的 Go 库,用于从 XML 文档自动生成 Go 结构体定义。它能够分析 XML 结构并创建对应的 Go 类型,大大简化了处理 XML 数据的工作。

安装 zek

go get github.com/miku/zek

基本使用方法

1. 从 XML 生成 Go 结构体

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/miku/zek"
)

func main() {
	// 示例 XML 数据
	xmlData := `
	<bookstore>
		<book category="cooking">
			<title lang="en">Everyday Italian</title>
			<author>Giada De Laurentiis</author>
			<year>2005</year>
			<price>30.00</price>
		</book>
		<book category="children">
			<title lang="en">Harry Potter</title>
			<author>J.K. Rowling</author>
			<year>2005</year>
			<price>29.99</price>
		</book>
	</bookstore>
	`

	// 解析 XML 并生成结构体
	root, err := zek.ParseString(xmlData)
	if err != nil {
		log.Fatal(err)
	}

	// 生成 Go 代码
	code, err := zek.Render(root)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(code)
}

2. 自定义生成选项

// 使用配置选项
config := zek.Config{
	PackageName: "models",  // 指定包名
	RootElement: "bookstore",  // 指定根元素
	SkipComments: true,  // 跳过注释
}

code, err := zek.RenderWithConfig(root, config)
if err != nil {
	log.Fatal(err)
}

fmt.Println(code)

3. 从文件读取 XML

func generateFromFile(filename string) {
	// 读取 XML 文件
	xmlFile, err := os.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}

	root, err := zek.Parse(xmlFile)
	if err != nil {
		log.Fatal(err)
	}

	code, err := zek.Render(root)
	if err != nil {
		log.Fatal(err)
	}

	// 将生成的代码写入文件
	err = os.WriteFile("generated.go", []byte(code), 0644)
	if err != nil {
		log.Fatal(err)
	}
}

高级特性

1. 处理 XML 属性

zek 会自动将 XML 属性转换为结构体字段。例如,对于 <title lang="en">,会生成:

type Title struct {
	Lang string `xml:"lang,attr"`
	Text string `xml:",chardata"`
}

2. 处理重复元素

对于重复出现的同名元素,zek 会生成切片类型的字段:

type Bookstore struct {
	Book []Book `xml:"book"`
}

3. 类型推断

zek 会尝试推断字段类型:

  • 数字值转换为 float64
  • “true”/“false” 转换为 bool
  • 其他作为字符串处理

实际应用示例

假设我们有一个复杂的 XML 配置文件:

<config>
	<server>
		<host>127.0.0.1</host>
		<port>8080</port>
		<ssl enabled="true">
			<cert>server.crt</cert>
			<key>server.key</key>
		</ssl>
	</server>
	<database>
		<name>appdb</name>
		<user>admin</user>
		<password>secret</password>
		<connections max="100" idle="10"/>
	</database>
</config>

使用 zek 生成的 Go 结构体:

package models

type Config struct {
	Server   Server   `xml:"server"`
	Database Database `xml:"database"`
}

type Server struct {
	Host string `xml:"host"`
	Port int    `xml:"port"`
	Ssl  Ssl    `xml:"ssl"`
}

type Ssl struct {
	Enabled bool   `xml:"enabled,attr"`
	Cert    string `xml:"cert"`
	Key     string `xml:"key"`
}

type Database struct {
	Name        string      `xml:"name"`
	User        string      `xml:"user"`
	Password    string      `xml:"password"`
	Connections Connections `xml:"connections"`
}

type Connections struct {
	Max  int `xml:"max,attr"`
	Idle int `xml:"idle,attr"`
}

注意事项

  1. 对于大型 XML 文件,zek 可能需要调整内存设置
  2. 生成的代码可能需要手动调整以符合项目规范
  3. 复杂的 XML 命名空间支持可能需要额外处理
  4. 生成的代码通常需要配合 encoding/xml 包使用

zek 是一个强大的工具,可以显著减少处理 XML 数据时的样板代码编写工作,特别适合需要与 XML 接口交互的项目。

回到顶部