Last active
March 27, 2017 15:49
-
-
Save angch/ed3c8ba950d99a2adc7bd7f57283c247 to your computer and use it in GitHub Desktop.
xmlstruct.go (for https://www.youtube.com/watch?v=fGwEZmb_HuU)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
///////////////////////////////////////////////////////////////// | |
//Code generated by chidley https://github.com/gnewton/chidley // | |
///////////////////////////////////////////////////////////////// | |
import ( | |
"bufio" | |
"compress/bzip2" | |
"compress/gzip" | |
"encoding/json" | |
"encoding/xml" | |
"flag" | |
"fmt" | |
"io" | |
"io/ioutil" | |
"log" | |
"os" | |
"runtime" | |
"strings" | |
) | |
const ( | |
JsonOut = iota | |
XmlOut | |
CountAll | |
) | |
var toJson bool = false | |
var toXml bool = false | |
var oneLevelDown bool = false | |
var countAll bool = false | |
var musage bool = false | |
var uniqueFlags = []*bool{ | |
&toJson, | |
&toXml, | |
&countAll} | |
var filename = "" | |
func init() { | |
flag.BoolVar(&toJson, "j", toJson, "Convert to JSON") | |
flag.BoolVar(&toXml, "x", toXml, "Convert to XML") | |
flag.BoolVar(&countAll, "c", countAll, "Count each instance of XML tags") | |
flag.BoolVar(&oneLevelDown, "s", oneLevelDown, "Stream XML by using XML elements one down from the root tag. Good for huge XML files (see http://blog.davidsingleton.org/parsing-huge-xml-files-with-go/") | |
flag.BoolVar(&musage, "h", musage, "Usage") | |
flag.StringVar(&filename, "f", filename, "XML file or URL to read in") | |
} | |
var out int = -1 | |
var counters map[string]*int | |
func main() { | |
runtime.GOMAXPROCS(runtime.NumCPU()) | |
flag.Parse() | |
if musage { | |
flag.Usage() | |
return | |
} | |
numSetBools, outFlag := numberOfBoolsSet(uniqueFlags) | |
if numSetBools == 0 { | |
flag.Usage() | |
return | |
} | |
if numSetBools != 1 { | |
flag.Usage() | |
log.Fatal("Only one of ", uniqueFlags, " can be set at once") | |
} | |
reader, xmlFile, err := genericReader(filename) | |
if err != nil { | |
log.Fatal(err) | |
return | |
} | |
if true { | |
xmlBytes, err := ioutil.ReadAll(reader) | |
rss := Rss{} | |
err = xml.Unmarshal(xmlBytes, &rss) | |
if err != nil { | |
fmt.Println("Can't Unmarshal", err) | |
} | |
// | |
for _, i := range rss.Channel.Item { | |
fmt.Println(i.Category) | |
i.Category.Text = "FunNews" | |
} | |
//out, err := json.MarshalIndent(rss, " ", " ") | |
out, err := xml.Marshal(rss) | |
fmt.Println(string(out)) | |
//fmt.Printf("%s", rss.Channel.Item) | |
return | |
} | |
decoder := xml.NewDecoder(reader) | |
counters = make(map[string]*int) | |
for { | |
token, _ := decoder.Token() | |
if token == nil { | |
break | |
} | |
switch se := token.(type) { | |
case xml.StartElement: | |
handleFeed(se, decoder, outFlag) | |
} | |
} | |
if xmlFile != nil { | |
defer xmlFile.Close() | |
} | |
if countAll { | |
for k, v := range counters { | |
fmt.Println(*v, k) | |
} | |
} | |
} | |
func handleFeed(se xml.StartElement, decoder *xml.Decoder, outFlag *bool) { | |
if outFlag == &countAll { | |
incrementCounter(se.Name.Space, se.Name.Local) | |
} else { | |
if !oneLevelDown { | |
if se.Name.Local == "rss" && se.Name.Space == "" { | |
var item Rss | |
decoder.DecodeElement(&item, &se) | |
switch outFlag { | |
case &toJson: | |
writeJson(item) | |
case &toXml: | |
writeXml(item) | |
} | |
} | |
} else { | |
if se.Name.Local == "channel" && se.Name.Space == "" { | |
var item Channel | |
decoder.DecodeElement(&item, &se) | |
switch outFlag { | |
case &toJson: | |
writeJson(item) | |
case &toXml: | |
writeXml(item) | |
} | |
} | |
} | |
} | |
} | |
func makeKey(space string, local string) string { | |
if space == "" { | |
space = "_" | |
} | |
return space + ":" + local | |
} | |
func incrementCounter(space string, local string) { | |
key := makeKey(space, local) | |
counter, ok := counters[key] | |
if !ok { | |
n := 1 | |
counters[key] = &n | |
} else { | |
newv := *counter + 1 | |
counters[key] = &newv | |
} | |
} | |
func writeJson(item interface{}) { | |
b, err := json.MarshalIndent(item, "", " ") | |
if err != nil { | |
log.Fatal(err) | |
} | |
fmt.Println(string(b)) | |
} | |
func writeXml(item interface{}) { | |
output, err := xml.MarshalIndent(item, " ", " ") | |
if err != nil { | |
fmt.Printf("error: %v\n", err) | |
} | |
os.Stdout.Write(output) | |
} | |
func genericReader(filename string) (io.Reader, *os.File, error) { | |
if filename == "" { | |
return bufio.NewReader(os.Stdin), nil, nil | |
} | |
file, err := os.Open(filename) | |
if err != nil { | |
return nil, nil, err | |
} | |
if strings.HasSuffix(filename, "bz2") { | |
return bufio.NewReader(bzip2.NewReader(bufio.NewReader(file))), file, err | |
} | |
if strings.HasSuffix(filename, "gz") { | |
reader, err := gzip.NewReader(bufio.NewReader(file)) | |
if err != nil { | |
return nil, nil, err | |
} | |
return bufio.NewReader(reader), file, err | |
} | |
return bufio.NewReader(file), file, err | |
} | |
func numberOfBoolsSet(a []*bool) (int, *bool) { | |
var setBool *bool | |
counter := 0 | |
for i := 0; i < len(a); i++ { | |
if *a[i] { | |
counter += 1 | |
setBool = a[i] | |
} | |
} | |
return counter, setBool | |
} | |
/////////////////////////// | |
/// structs | |
/////////////////////////// | |
type Category struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Channel struct { | |
//Atom10_link []*Atom10_link `xml:"http://www.w3.org/2005/Atom link,omitempty" json:"link,omitempty"` | |
Copyright *Copyright `xml:" copyright,omitempty" json:"copyright,omitempty"` | |
Description *Description `xml:" description,omitempty" json:"description,omitempty"` | |
Feedburner_feedFlare []*Feedburner_feedFlare `xml:"http://rssnamespace.org/feedburner/ext/1.0 feedFlare,omitempty" json:"feedFlare,omitempty"` | |
Feedburner_info *Feedburner_info `xml:"http://rssnamespace.org/feedburner/ext/1.0 info,omitempty" json:"info,omitempty"` | |
Image *Image `xml:" image,omitempty" json:"image,omitempty"` | |
Item []*Item `xml:" item,omitempty" json:"item,omitempty"` | |
Language *Language `xml:" language,omitempty" json:"language,omitempty"` | |
LastBuildDate *LastBuildDate `xml:" lastBuildDate,omitempty" json:"lastBuildDate,omitempty"` | |
Link *Link `xml:" link,omitempty" json:"link,omitempty"` | |
Title *Title `xml:" title,omitempty" json:"title,omitempty"` | |
} | |
type Copyright struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Description struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Guid struct { | |
Attr_isPermaLink string `xml:" isPermaLink,attr" json:",omitempty"` | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Height struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Image struct { | |
Height *Height `xml:" height,omitempty" json:"height,omitempty"` | |
Link *Link `xml:" link,omitempty" json:"link,omitempty"` | |
Title *Title `xml:" title,omitempty" json:"title,omitempty"` | |
Url *Url `xml:" url,omitempty" json:"url,omitempty"` | |
Width *Width `xml:" width,omitempty" json:"width,omitempty"` | |
} | |
type Item struct { | |
Category *Category `xml:" category,omitempty" json:"category,omitempty"` | |
Description *Description `xml:" description,omitempty" json:"description,omitempty"` | |
Feedburner_origLink *Feedburner_origLink `xml:"http://rssnamespace.org/feedburner/ext/1.0 origLink,omitempty" json:"origLink,omitempty"` | |
Guid *Guid `xml:" guid,omitempty" json:"guid,omitempty"` | |
Link *Link `xml:" link,omitempty" json:"link,omitempty"` | |
PubDate *PubDate `xml:" pubDate,omitempty" json:"pubDate,omitempty"` | |
Title *Title `xml:" title,omitempty" json:"title,omitempty"` | |
} | |
type Language struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type LastBuildDate struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Link struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type PubDate struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Root struct { | |
Rss *Rss `xml:" rss,omitempty" json:"rss,omitempty"` | |
} | |
type Rss struct { | |
Attr_feedburner string `xml:"xmlns feedburner,attr" json:",omitempty"` | |
Attr_version string `xml:" version,attr" json:",omitempty"` | |
Channel *Channel `xml:" channel,omitempty" json:"channel,omitempty"` | |
} | |
type Title struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Url struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Width struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
} | |
type Feedburner_feedFlare struct { | |
Attr_href string `xml:" href,attr" json:",omitempty"` | |
Attr_src string `xml:" src,attr" json:",omitempty"` | |
Text string `xml:",chardata" json:",omitempty"` | |
XMLName xml.Name `xml:"http://rssnamespace.org/feedburner/ext/1.0 feedFlare,omitempty" json:"feedFlare,omitempty"` | |
} | |
type Feedburner_info struct { | |
Attr_uri string `xml:" uri,attr" json:",omitempty"` | |
XMLName xml.Name `xml:"http://rssnamespace.org/feedburner/ext/1.0 info,omitempty" json:"info,omitempty"` | |
} | |
type Feedburner_origLink struct { | |
Text string `xml:",chardata" json:",omitempty"` | |
XMLName xml.Name `xml:"http://rssnamespace.org/feedburner/ext/1.0 origLink,omitempty" json:"origLink,omitempty"` | |
} | |
/* | |
type Atom10_link struct { | |
Attr_atom10 string `xml:"xmlns atom10,attr" json:",omitempty"` | |
Attr_href string `xml:" href,attr" json:",omitempty"` | |
Attr_rel string `xml:" rel,attr" json:",omitempty"` | |
Attr_type string `xml:" type,attr" json:",omitempty"` | |
XMLName xml.Name `xml:"http://www.w3.org/2005/Atom link,omitempty" json:"link,omitempty"` | |
} | |
*/ | |
/////////////////////////// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment