├── .gitignore
├── LICENSE
├── README.md
├── chidley.go
├── codegenTemplates.go
├── data
├── test.xml
└── typeCollapsing.xml
├── decl.go
├── encoding_test.go
├── extractor.go
├── fieldTemplate.go
├── fqn.go
├── genericReader.go
├── go.mod
├── go.sum
├── javaTypes.go
├── jaxbTemplate.go
├── makereadme
├── chidley.md
├── main.go
├── readme.sh.old
├── template.go
└── util.go
├── mvnTemplate.go
├── node.go
├── nodeTypeInfo.go
├── printGoStructVisitor.go
├── printJavaJaxbVisitor.go
├── source.go
├── stdoutWriter.go
├── test_xml.sh
├── tests_util.go
├── util.go
├── util_test.go
├── xml
├── ActorPreludeSample.xml
├── BrookeWestSample.xml
├── Fantasia_con_imitazione_BWV563.xml
├── MODIS-Imagery-OilSpill.kml
├── MODIS-Imagery-OilSpill.kml.gz
├── amazon_api.xml
├── arxiv_search_query.xml.gz
├── pubmed_xml_12750255.xml.bz2
├── test1.xml
├── test2.xml
├── test2a.xml
├── test2b.xml
├── test2c.xml
├── test3a.xml
├── test3b.xml
├── test3c.xml
├── test4.xml
├── testSpacePreserve.xml
└── testType.xml
├── xml_source_test.go
└── xml_test.go
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
2 | *.o
3 | *.a
4 | *.so
5 |
6 | # Folders
7 | _obj
8 | _test
9 |
10 | # Architecture specific extensions/prefixes
11 | *.[568vq]
12 | [568vq].out
13 |
14 | *.cgo1.go
15 | *.cgo2.c
16 | _cgo_defun.c
17 | _cgo_gotypes.go
18 | _cgo_export.*
19 |
20 | _testmain.go
21 |
22 | *.exe
23 | *.test
24 |
25 | *~
26 | codegen/
27 | TAGS
28 | #*#
29 |
30 | chidley
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2014 Glen Newton
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/chidley.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | // Copyright 2014,2015,2016 Glen Newton
4 | // glen.newton@gmail.com
5 |
6 | import (
7 | "bufio"
8 | "bytes"
9 | "errors"
10 | "flag"
11 | "fmt"
12 | "io"
13 | "log"
14 | "os"
15 | "path/filepath"
16 | "sort"
17 |
18 | "text/template"
19 | "time"
20 | )
21 |
22 | func init() {
23 |
24 | flag.BoolVar(&DEBUG, "d", DEBUG, "Debug; prints out much information")
25 | flag.BoolVar(&addDbMetadata, "B", addDbMetadata, "Add database metadata to created Go structs")
26 | flag.BoolVar(&classicStructNamesWithUnderscores, "C", classicStructNamesWithUnderscores, "Structs have underscores instead of CamelCase; how chidley used to produce output; includes name spaces (see -n)")
27 | flag.BoolVar(&codeGenConvert, "W", codeGenConvert, "Generate Go code to convert XML to JSON or XML (latter useful for validation) and write it to stdout")
28 | flag.BoolVar(&flattenStrings, "F", flattenStrings, "Assume complete representative XML and collapse tags with only a single string and no attributes")
29 | flag.BoolVar(&ignoreXmlDecodingErrors, "I", ignoreXmlDecodingErrors, "If XML decoding error encountered, continue")
30 | flag.BoolVar(&nameSpaceInJsonName, "n", nameSpaceInJsonName, "Use the XML namespace prefix as prefix to JSON name")
31 | flag.BoolVar(&prettyPrint, "p", prettyPrint, "Pretty-print json in generated code (if applicable)")
32 | flag.BoolVar(&progress, "r", progress, "Progress: every 50000 input tags (elements)")
33 | flag.BoolVar(&readFromStandardIn, "c", readFromStandardIn, "Read XML from standard input")
34 | flag.BoolVar(&sortByXmlOrder, "X", sortByXmlOrder, "Sort output of structs in Go code by order encounered in source XML (default is alphabetical order)")
35 | flag.BoolVar(&structsToStdout, "G", structsToStdout, "Only write generated Go structs to stdout")
36 | flag.BoolVar(&url, "u", url, "Filename interpreted as an URL")
37 | flag.BoolVar(&useType, "t", useType, "Use type info obtained from XML (int, bool, etc); default is to assume everything is a string; better chance at working if XMl sample is not complete")
38 | flag.BoolVar(&writeJava, "J", writeJava, "Generated Java code for Java/JAXB")
39 | flag.BoolVar(&xmlName, "x", xmlName, "Add XMLName (Space, Local) for each XML element, to JSON")
40 | flag.BoolVar(&keepXmlFirstLetterCase, "K", keepXmlFirstLetterCase, "Do not change the case of the first letter of the XML tag names")
41 | flag.BoolVar(&validateFieldTemplate, "m", validateFieldTemplate, "Validate the field template. Useful to make sure the template defined with -T is valid")
42 |
43 | flag.BoolVar(&ignoreLowerCaseXmlTags, "L", ignoreLowerCaseXmlTags, "Ignore lower case XML tags")
44 |
45 | flag.StringVar(&attributePrefix, "a", attributePrefix, "Prefix to attribute names")
46 | flag.StringVar(&baseJavaDir, "D", baseJavaDir, "Base directory for generated Java code (root of maven project)")
47 | flag.StringVar(&cdataStringName, "M", cdataStringName, "Set name of CDATA string field")
48 | flag.StringVar(&fieldTemplateString, "T", fieldTemplateString, "Field template for the struct field definition. Can include annotations. Default is for XML and JSON")
49 | flag.StringVar(&javaAppName, "k", javaAppName, "App name for Java code (appended to ca.gnewton.chidley Java package name))")
50 | flag.StringVar(&lengthTagAttribute, "A", lengthTagAttribute, "The tag name attribute to use for the max length Go annotations")
51 | flag.StringVar(&lengthTagName, "N", lengthTagName, "The tag name to use for the max length Go annotations")
52 | flag.StringVar(&lengthTagSeparator, "S", lengthTagSeparator, "The tag name separator to use for the max length Go annotations")
53 | flag.StringVar(&namePrefix, "e", namePrefix, "Prefix to struct (element) names; must start with a capital")
54 | flag.StringVar(&userJavaPackageName, "P", userJavaPackageName, "Java package name (rightmost in full package name")
55 |
56 | flag.StringVar(&ignoredXmlTags, "h", ignoredXmlTags, "List of XML tags to ignore; comma separated")
57 |
58 | flag.Int64Var(&lengthTagPadding, "Z", lengthTagPadding, "The padding on the max length tag attribute")
59 |
60 | }
61 |
62 | func handleParameters() error {
63 | flag.Parse()
64 |
65 | if codeGenConvert || writeJava {
66 | structsToStdout = false
67 | }
68 |
69 | numBoolsSet := countNumberOfBoolsSet(outputs)
70 | if numBoolsSet > 1 {
71 | log.Print(" ERROR: Only one of -W -J -X -V -c can be set")
72 | } else if numBoolsSet == 0 {
73 | log.Print(" ERROR: At least one of -W -J -X -V -c must be set")
74 | }
75 | if sortByXmlOrder {
76 | structSort = printStructsByXml
77 | }
78 |
79 | var err error
80 | ignoredXmlTagsMap, err = extractExcludedTags(ignoredXmlTags)
81 | if err != nil {
82 | return err
83 | }
84 |
85 | if lengthTagName == "" && lengthTagAttribute == "" || lengthTagName != "" && lengthTagAttribute != "" {
86 | return nil
87 | }
88 |
89 | return errors.New("Both lengthTagName and lengthTagAttribute must be set")
90 | }
91 |
92 | func main() {
93 | //log.Println(fieldTemplateString)
94 |
95 | //EXP()
96 | log.SetFlags(log.LstdFlags | log.Lshortfile)
97 |
98 | err := handleParameters()
99 |
100 | if err != nil {
101 | log.Println(err)
102 | flag.Usage()
103 | return
104 | }
105 |
106 | err = runValidateFieldTemplate(validateFieldTemplate)
107 | if err != nil {
108 |
109 | return
110 | }
111 | if validateFieldTemplate {
112 | return
113 | }
114 |
115 | if len(flag.Args()) == 0 && !readFromStandardIn {
116 | fmt.Println("chidley xmlFileName|url")
117 | fmt.Println("xmlFileName can be .gz or .bz2: uncompressed transparently")
118 | flag.Usage()
119 | return
120 | }
121 |
122 | var sourceNames []string
123 |
124 | if !readFromStandardIn {
125 | sourceNames = flag.Args()
126 | }
127 | if !url && !readFromStandardIn {
128 | for i, _ := range sourceNames {
129 | sourceNames[i], err = filepath.Abs(sourceNames[i])
130 | if err != nil {
131 | log.Fatal("FATAL ERROR: " + err.Error())
132 | }
133 | }
134 | }
135 |
136 | sources, err := makeSourceReaders(sourceNames, url, readFromStandardIn)
137 | if err != nil {
138 | log.Fatal("FATAL ERROR: " + err.Error())
139 | }
140 |
141 | ex := Extractor{
142 | namePrefix: namePrefix,
143 | nameSuffix: nameSuffix,
144 | useType: useType,
145 | progress: progress,
146 | ignoreXmlDecodingErrors: ignoreXmlDecodingErrors,
147 | initted: false,
148 | }
149 |
150 | if DEBUG {
151 | log.Print("extracting")
152 | }
153 |
154 | m := &ex
155 | m.init()
156 |
157 | for source := range sources {
158 | if DEBUG {
159 | log.Println("READER", source)
160 | }
161 | err = m.extract(source.getReader())
162 |
163 | if err != nil {
164 | log.Println("ERROR: " + err.Error())
165 | if !ignoreXmlDecodingErrors {
166 | log.Fatal("FATAL ERROR: " + err.Error())
167 | }
168 | }
169 | if DEBUG {
170 | log.Println("DONE READER", source)
171 | }
172 | }
173 |
174 | ex.done()
175 |
176 | switch {
177 | case codeGenConvert:
178 | generateGoCode(os.Stdout, sourceNames, &ex)
179 |
180 | case structsToStdout:
181 | generateGoStructs(os.Stdout, sourceNames[0], &ex)
182 |
183 | case writeJava:
184 | if len(userJavaPackageName) > 0 {
185 | javaAppName = userJavaPackageName
186 | }
187 | javaPackage := javaBasePackage + "." + javaAppName
188 | javaDir := baseJavaDir + "/" + mavenJavaBase + "/" + javaBasePackagePath + "/" + javaAppName
189 |
190 | os.RemoveAll(baseJavaDir)
191 | os.MkdirAll(javaDir+"/xml", 0755)
192 | date := time.Now()
193 | printJavaJaxbVisitor := PrintJavaJaxbVisitor{
194 | alreadyVisited: make(map[string]bool),
195 | globalTagAttributes: ex.globalTagAttributes,
196 | nameSpaceTagMap: ex.nameSpaceTagMap,
197 | useType: useType,
198 | javaDir: javaDir,
199 | javaPackage: javaPackage,
200 | namePrefix: namePrefix,
201 | Date: date,
202 | }
203 |
204 | var onlyChild *Node
205 | for _, child := range ex.root.children {
206 | printJavaJaxbVisitor.Visit(child)
207 | // Bad: assume only one base element
208 | onlyChild = child
209 | }
210 | fullPath, err := getFullPath(sourceNames[0])
211 | if err != nil {
212 | log.Fatal(err)
213 | }
214 | printJavaJaxbMain(onlyChild.makeJavaType(namePrefix, ""), javaDir, javaPackage, fullPath, date)
215 | printPackageInfo(onlyChild, javaDir, javaPackage, ex.globalTagAttributes, ex.nameSpaceTagMap)
216 |
217 | printMavenPom(baseJavaDir+"/pom.xml", javaAppName)
218 | }
219 |
220 | }
221 |
222 | func printPackageInfo(node *Node, javaDir string, javaPackage string, globalTagAttributes map[string][]*FQN, nameSpaceTagMap map[string]string) {
223 |
224 | //log.Printf("%+v\n", node)
225 |
226 | if node.space != "" {
227 | _ = findNameSpaces(globalTagAttributes[nk(node)])
228 | //attributes := findNameSpaces(globalTagAttributes[nk(node)])
229 |
230 | t := template.Must(template.New("package-info").Parse(jaxbPackageInfoTemplage))
231 | packageInfoPath := javaDir + "/xml/package-info.java"
232 | fi, err := os.Create(packageInfoPath)
233 | if err != nil {
234 | log.Print("Problem creating file: " + packageInfoPath)
235 | panic(err)
236 | }
237 | defer fi.Close()
238 |
239 | writer := bufio.NewWriter(fi)
240 | packageInfo := JaxbPackageInfo{
241 | BaseNameSpace: node.space,
242 | //AdditionalNameSpace []*FQN
243 | PackageName: javaPackage + ".xml",
244 | }
245 | err = t.Execute(writer, packageInfo)
246 | if err != nil {
247 | log.Println("executing template:", err)
248 | }
249 | bufio.NewWriter(writer).Flush()
250 | }
251 |
252 | }
253 |
254 | const XMLNS = "xmlns"
255 |
256 | func findNameSpaces(attributes []*FQN) []*FQN {
257 | if attributes == nil || len(attributes) == 0 {
258 | return nil
259 | }
260 | xmlns := make([]*FQN, 0)
261 | return xmlns
262 | }
263 |
264 | func printMavenPom(pomPath string, javaAppName string) {
265 | t := template.Must(template.New("mavenPom").Parse(mavenPomTemplate))
266 | fi, err := os.Create(pomPath)
267 | if err != nil {
268 | log.Print("Problem creating file: " + pomPath)
269 | panic(err)
270 | }
271 | defer fi.Close()
272 |
273 | writer := bufio.NewWriter(fi)
274 | maven := JaxbMavenPomInfo{
275 | AppName: javaAppName,
276 | }
277 | err = t.Execute(writer, maven)
278 | if err != nil {
279 | log.Println("executing template:", err)
280 | }
281 | bufio.NewWriter(writer).Flush()
282 | }
283 |
284 | func printJavaJaxbMain(rootElementName string, javaDir string, javaPackage string, sourceXMLFilename string, date time.Time) {
285 | t := template.Must(template.New("chidleyJaxbGenClass").Parse(jaxbMainTemplate))
286 | writer, f, err := javaClassWriter(javaDir, javaPackage, "Main")
287 | defer f.Close()
288 |
289 | classInfo := JaxbMainClassInfo{
290 | PackageName: javaPackage,
291 | BaseXMLClassName: rootElementName,
292 | SourceXMLFilename: sourceXMLFilename,
293 | Date: date,
294 | }
295 | err = t.Execute(writer, classInfo)
296 | if err != nil {
297 | log.Println("executing template:", err)
298 | }
299 | bufio.NewWriter(writer).Flush()
300 |
301 | }
302 |
303 | //func makeSourceReaders(sourceNames []string, url bool, standardIn bool) ([]Source, error) {
304 | func makeSourceReaders(sourceNames []string, url bool, standardIn bool) (chan Source, error) {
305 | var err error
306 | //sources := make([]Source, len(sourceNames))
307 | sources := make(chan Source, 1)
308 |
309 | go func() {
310 | var newSource Source
311 | for i, _ := range sourceNames {
312 | if url {
313 | newSource = new(UrlSource)
314 | if DEBUG {
315 | log.Print("Making UrlSource")
316 | }
317 | } else {
318 | if standardIn {
319 | newSource = new(StdinSource)
320 | if DEBUG {
321 | log.Print("Making StdinSource")
322 | }
323 | } else {
324 | newSource = new(FileSource)
325 | if DEBUG {
326 | //log.Print("Making FileSource")
327 | }
328 | }
329 | }
330 |
331 | err = newSource.newSource(sourceNames[i])
332 | if err != nil {
333 | log.Fatal(err)
334 | }
335 | sources <- newSource
336 | if DEBUG {
337 | log.Print("Making Source:[" + sourceNames[i] + "]")
338 | }
339 | }
340 | close(sources)
341 | }()
342 | return sources, err
343 | }
344 |
345 | func attributes(atts map[string]bool) string {
346 | ret := ": "
347 | for k, _ := range atts {
348 | ret = ret + k + ", "
349 | }
350 | return ret
351 | }
352 |
353 | func indent(d int) string {
354 | indent := ""
355 | for i := 0; i < d; i++ {
356 | indent = indent + "\t"
357 | }
358 | return indent
359 | }
360 |
361 | func countNumberOfBoolsSet(a []*bool) int {
362 | counter := 0
363 | for i := 0; i < len(a); i++ {
364 | if *a[i] {
365 | counter += 1
366 | }
367 | }
368 | return counter
369 | }
370 |
371 | func makeOneLevelDown(node *Node, globalTagAttributes map[string]([]*FQN)) []*XMLType {
372 | var children []*XMLType
373 |
374 | for _, np := range node.children {
375 | if np == nil {
376 | continue
377 | }
378 | for _, n := range np.children {
379 | if n == nil {
380 | continue
381 | }
382 | if flattenStrings && isStringOnlyField(n, len(globalTagAttributes[nk(n)])) {
383 | continue
384 | }
385 | x := XMLType{NameType: n.makeType(namePrefix, nameSuffix),
386 | XMLName: n.name,
387 | XMLNameUpper: capitalizeFirstLetter(n.name),
388 | XMLSpace: n.space}
389 | children = append(children, &x)
390 | }
391 | }
392 | return children
393 | }
394 | func printChildrenChildren(node *Node) {
395 | for k, v := range node.children {
396 | log.Print(k)
397 | log.Printf("children: %+v\n", v.children)
398 | }
399 | }
400 |
401 | // Order Xml is encountered
402 | func printStructsByXml(v *PrintGoStructVisitor) error {
403 | orderNodes := make(map[int]*Node)
404 | var order []int
405 |
406 | for k := range v.alreadyVisitedNodes {
407 | nodeOrder := v.alreadyVisitedNodes[k].discoveredOrder
408 | orderNodes[nodeOrder] = v.alreadyVisitedNodes[k]
409 | order = append(order, nodeOrder)
410 | }
411 | sort.Ints(order)
412 |
413 | for o := range order {
414 | err := print(v, orderNodes[o])
415 | if err != nil {
416 | return err
417 | }
418 | }
419 | return nil
420 | }
421 |
422 | // Alphabetical order
423 | func printStructsAlphabetical(v *PrintGoStructVisitor) error {
424 | var keys []string
425 | for k := range v.alreadyVisitedNodes {
426 | keys = append(keys, k)
427 | }
428 | sort.Strings(keys)
429 |
430 | for _, k := range keys {
431 | err := print(v, v.alreadyVisitedNodes[k])
432 | if err != nil {
433 | return err
434 | }
435 | }
436 | return nil
437 |
438 | }
439 |
440 | func generateGoStructs(out io.Writer, sourceName string, ex *Extractor) {
441 | printGoStructVisitor := new(PrintGoStructVisitor)
442 |
443 | printGoStructVisitor.init(os.Stdout, 999, ex.globalTagAttributes, ex.nameSpaceTagMap, useType, nameSpaceInJsonName)
444 | printGoStructVisitor.Visit(ex.root)
445 | structSort(printGoStructVisitor)
446 | }
447 |
448 | //Writes structs to a string then uses this in a template to generate Go code
449 | func generateGoCode(out io.Writer, sourceNames []string, ex *Extractor) error {
450 | buf := bytes.NewBufferString("")
451 | printGoStructVisitor := new(PrintGoStructVisitor)
452 | printGoStructVisitor.init(buf, 9999, ex.globalTagAttributes, ex.nameSpaceTagMap, useType, nameSpaceInJsonName)
453 | printGoStructVisitor.Visit(ex.root)
454 |
455 | structSort(printGoStructVisitor)
456 |
457 | xt := XMLType{NameType: ex.firstNode.makeType(namePrefix, nameSuffix),
458 | XMLName: ex.firstNode.name,
459 | XMLNameUpper: capitalizeFirstLetter(ex.firstNode.name),
460 | XMLSpace: ex.firstNode.space,
461 | }
462 |
463 | fullPath, err := getFullPath(sourceNames[0])
464 | if err != nil {
465 | return err
466 | }
467 |
468 | fullPaths, err := getFullPaths(sourceNames)
469 | if err != nil {
470 | return err
471 | }
472 | x := XmlInfo{
473 | BaseXML: &xt,
474 | OneLevelDownXML: makeOneLevelDown(ex.root, ex.globalTagAttributes),
475 | Filenames: fullPaths,
476 | Filename: fullPath,
477 | Structs: buf.String(),
478 | }
479 | x.init()
480 | t := template.Must(template.New("chidleyGen").Parse(codeTemplate))
481 |
482 | err = t.Execute(out, x)
483 | if err != nil {
484 | log.Println("executing template:", err)
485 | return err
486 | }
487 | return err
488 | }
489 |
--------------------------------------------------------------------------------
/codegenTemplates.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "strconv"
5 | )
6 |
7 | type XmlInfo struct {
8 | BaseXML *XMLType
9 | OneLevelDownXML []*XMLType
10 | Structs string
11 | Filenames []string
12 | Filename string
13 | }
14 |
15 | type XMLType struct {
16 | NameType, XMLName, XMLNameUpper, XMLSpace string
17 | }
18 |
19 | // b := [5]int{1, 2, 3, 4, 5}
20 | func (xi *XmlInfo) init() {
21 | xi.Filename = "[" + strconv.Itoa(len(xi.Filenames)) + "]string{"
22 | for i, _ := range xi.Filenames {
23 | if i != 0 {
24 | xi.Filename = xi.Filename + ","
25 | }
26 | xi.Filename = xi.Filename + "\"" + xi.Filenames[i] + "\""
27 | }
28 | xi.Filename = xi.Filename + "}"
29 | }
30 |
31 | const codeTemplate = `
32 |
33 | package main
34 |
35 | /////////////////////////////////////////////////////////////////
36 | //Code generated by chidley https://github.com/gnewton/chidley //
37 | /////////////////////////////////////////////////////////////////
38 |
39 | import (
40 | "bufio"
41 | "compress/bzip2"
42 | "compress/gzip"
43 | "encoding/json"
44 | "encoding/xml"
45 | "flag"
46 | "fmt"
47 | "io"
48 | "log"
49 | "os"
50 | "math"
51 | "strings"
52 | )
53 |
54 | const (
55 | JsonOut = iota
56 | XmlOut
57 | CountAll
58 | )
59 |
60 | var toJson bool = false
61 | var toXml bool = false
62 | var oneLevelDown bool = false
63 | var countAll bool = false
64 | var musage bool = false
65 |
66 | var uniqueFlags = []*bool{
67 | &toJson,
68 | &toXml,
69 | &countAll}
70 |
71 | var filenames = {{.Filename}}
72 |
73 |
74 |
75 | func init() {
76 |
77 | flag.BoolVar(&toJson, "j", toJson, "Convert to JSON")
78 | flag.BoolVar(&toXml, "x", toXml, "Convert to XML")
79 | flag.BoolVar(&countAll, "c", countAll, "Count each instance of XML tags")
80 | 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/")
81 | flag.BoolVar(&musage, "h", musage, "Usage")
82 | //flag.StringVar(&filename, "f", filename, "XML file or URL to read in")
83 |
84 | flag.Int64Var(&recordLimit, "n", recordLimit, "Limit # records output")
85 | }
86 |
87 | var out int = -1
88 |
89 | var counters map[string]*int
90 |
91 | var recordLimit int64 = int64(math.MaxInt64)
92 | var recordCounter = int64(0)
93 |
94 | func main() {
95 | flag.Parse()
96 |
97 | if musage {
98 | flag.Usage()
99 | return
100 | }
101 |
102 | numSetBools, outFlag := numberOfBoolsSet(uniqueFlags)
103 | if numSetBools == 0 {
104 | flag.Usage()
105 | return
106 | }
107 |
108 | if numSetBools != 1 {
109 | flag.Usage()
110 | log.Fatal("Only one of ", uniqueFlags, " can be set at once")
111 | }
112 |
113 | counter := 0
114 | stop := false
115 | counters = make(map[string]*int)
116 | for i, _ := range filenames {
117 | filename := filenames[i]
118 | reader, xmlFile, err := genericReader(filename)
119 | if err != nil {
120 | log.Fatal(err)
121 | return
122 | }
123 |
124 | decoder := xml.NewDecoder(reader)
125 |
126 | for {
127 | if stop {
128 | break
129 | }
130 | token, _ := decoder.Token()
131 | if token == nil {
132 | break
133 | }
134 | switch se := token.(type) {
135 | case xml.StartElement:
136 | counter++
137 | handleFeed(se, decoder, outFlag)
138 | if recordCounter == recordLimit {
139 | stop = true
140 | }
141 | }
142 |
143 | }
144 | if stop {
145 | break
146 | }
147 | if xmlFile != nil {
148 | defer xmlFile.Close()
149 | }
150 | }
151 | if countAll {
152 | for k, v := range counters {
153 | fmt.Println(*v, k)
154 | }
155 | }
156 | }
157 |
158 | func handleFeed(se xml.StartElement, decoder *xml.Decoder, outFlag *bool) {
159 | if outFlag == &countAll {
160 | incrementCounter(se.Name.Space, se.Name.Local)
161 | } else {
162 | if !oneLevelDown{
163 | if se.Name.Local == "{{.BaseXML.XMLName}}" && se.Name.Space == "{{.BaseXML.XMLSpace}}" {
164 | var item {{.BaseXML.NameType}}
165 | decoder.DecodeElement(&item, &se)
166 | switch outFlag {
167 | case &toJson:
168 | writeJson(item)
169 | case &toXml:
170 | writeXml(item)
171 | }
172 | }
173 | }else{
174 | {{ range .OneLevelDownXML }}
175 | if se.Name.Local == "{{.XMLName}}" && se.Name.Space == "{{.XMLSpace}}" {
176 | recordCounter++
177 | var item {{.NameType}}
178 | decoder.DecodeElement(&item, &se)
179 | switch outFlag {
180 | case &toJson:
181 | writeJson(item)
182 | case &toXml:
183 | writeXml(item)
184 | }
185 | }
186 | {{ end }}
187 | }
188 | }
189 | }
190 |
191 | func makeKey(space string, local string) string {
192 | if space == "" {
193 | space = "_"
194 | }
195 | return space + ":" + local
196 | }
197 |
198 | func incrementCounter(space string, local string) {
199 | key := makeKey(space, local)
200 |
201 | counter, ok := counters[key]
202 | if !ok {
203 | n := 1
204 | counters[key] = &n
205 | } else {
206 | newv := *counter + 1
207 | counters[key] = &newv
208 | }
209 | }
210 |
211 | func writeJson(item interface{}) {
212 | b, err := json.MarshalIndent(item, "", " ")
213 | if err != nil {
214 | log.Fatal(err)
215 | }
216 | fmt.Println(string(b))
217 | }
218 |
219 | func writeXml(item interface{}) {
220 | output, err := xml.MarshalIndent(item, " ", " ")
221 | if err != nil {
222 | fmt.Printf("error: %v\n", err)
223 | }
224 | os.Stdout.Write(output)
225 | }
226 |
227 | func genericReader(filename string) (io.Reader, *os.File, error) {
228 | if filename == "" {
229 | return bufio.NewReader(os.Stdin), nil, nil
230 | }
231 | file, err := os.Open(filename)
232 | if err != nil {
233 | return nil, nil, err
234 | }
235 | if strings.HasSuffix(filename, "bz2") {
236 | return bufio.NewReader(bzip2.NewReader(bufio.NewReader(file))), file, err
237 | }
238 |
239 | if strings.HasSuffix(filename, "gz") {
240 | reader, err := gzip.NewReader(bufio.NewReader(file))
241 | if err != nil {
242 | return nil, nil, err
243 | }
244 | return bufio.NewReader(reader), file, err
245 | }
246 | return bufio.NewReader(file), file, err
247 | }
248 |
249 | func numberOfBoolsSet(a []*bool) (int, *bool) {
250 | var setBool *bool
251 | counter := 0
252 | for i := 0; i < len(a); i++ {
253 | if *a[i] {
254 | counter += 1
255 | setBool = a[i]
256 | }
257 | }
258 | return counter, setBool
259 | }
260 |
261 |
262 | ///////////////////////////
263 | /// structs
264 | ///////////////////////////
265 |
266 | {{.Structs}}
267 | ///////////////////////////
268 |
269 | `
270 |
--------------------------------------------------------------------------------
/data/test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dune
4 | 1966
5 |
6 |
7 | Frank
8 | Herbert
9 |
10 |
11 |
12 | 678
13 |
14 |
15 |
16 |
17 |
18 | Larry
19 | Niven
20 |
21 |
22 | Jerry
23 | Pournelle
24 |
25 |
26 | Footfall
27 | 1972
28 |
29 | 451
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/data/typeCollapsing.xml:
--------------------------------------------------------------------------------
1 |
2 | Bill Smith
3 | 42
4 | true
5 | 55.7
6 |
7 |
--------------------------------------------------------------------------------
/decl.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | var DEBUG = false
8 | var attributePrefix = "Attr"
9 | var codeGenConvert = false
10 | var classicStructNamesWithUnderscores = false
11 | var nameSpaceInJsonName = false
12 | var prettyPrint = false
13 | var progress = false
14 | var readFromStandardIn = false
15 | var sortByXmlOrder = false
16 | var structsToStdout = true
17 | var validateFieldTemplate = false
18 |
19 | var ignoreLowerCaseXmlTags = false
20 | var ignoredXmlTags = ""
21 | var ignoredXmlTagsMap *map[string]struct{}
22 |
23 | var ignoreXmlDecodingErrors = false
24 |
25 | var codeGenDir = "codegen"
26 | var codeGenFilename = "CodeGenStructs.go"
27 |
28 | // Java out
29 | const javaBasePackage = "ca.gnewton.chidley"
30 | const mavenJavaBase = "src/main/java"
31 |
32 | var javaBasePackagePath = strings.Replace(javaBasePackage, ".", "/", -1)
33 | var javaAppName = "jaxb"
34 | var writeJava = false
35 | var baseJavaDir = "java"
36 | var userJavaPackageName = ""
37 |
38 | var namePrefix = "C"
39 | var nameSuffix = ""
40 | var xmlName = false
41 | var url = false
42 | var useType = false
43 | var addDbMetadata = false
44 | var flattenStrings = false
45 |
46 | //FIXXX: should not be global
47 | var keepXmlFirstLetterCase = true
48 |
49 | var lengthTagName = ""
50 | var lengthTagPadding int64 = 0
51 | var lengthTagAttribute = ""
52 | var lengthTagSeparator = ":"
53 |
54 | var cdataStringName = "Text"
55 | var cdataNumberName = "Number"
56 | var cdataBooleanName = "Flag"
57 |
58 | type structSortFunc func(v *PrintGoStructVisitor)
59 |
60 | var structSort = printStructsAlphabetical
61 |
62 | var outputs = []*bool{
63 | &codeGenConvert,
64 | &structsToStdout,
65 | &writeJava,
66 | }
67 |
--------------------------------------------------------------------------------
/encoding_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | const XML = `
8 |
9 |
10 | 43
11 |
12 | `
13 |
14 | func TestHasNonDefaultEncoding(t *testing.T) {
15 |
16 | }
17 |
18 | const XMLHasTagCalledRoot = `
19 |
20 |
21 |
22 |
23 | `
24 |
25 | func TestHasTagCalledRoot(t *testing.T) {
26 |
27 | }
28 |
29 | const XMLHasCapitalizationTagCollisions = `
30 |
31 |
32 | 123
33 |
34 |
35 | add
36 |
37 |
38 | `
39 |
40 | func TestHasCapitalizationTagCollisions(t *testing.T) {
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/extractor.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/xml"
5 | "errors"
6 | "io"
7 | "log"
8 | "strconv"
9 | "strings"
10 | )
11 |
12 | const XML_NAMESPACE_ACRONYM = "xmlns"
13 |
14 | var nameMapper = map[string]string{
15 | "-": "Hyphen",
16 | ".": "Dot",
17 | }
18 |
19 | var DiscoveredOrder = 0
20 |
21 | type Extractor struct {
22 | globalTagAttributes map[string]([]*FQN)
23 | globalTagAttributesMap map[string]bool
24 | globalNodeMap map[string]*Node
25 | namePrefix string
26 | nameSpaceTagMap map[string]string
27 | nameSuffix string
28 | root *Node
29 | firstNode *Node
30 | hasStartElements bool
31 | useType bool
32 | progress bool
33 | ignoreXmlDecodingErrors bool
34 | initted bool
35 | tokenChannel chan xml.Token
36 | handleTokensDoneChannel chan bool
37 | }
38 |
39 | const RootName = "ChidleyRoot314159"
40 |
41 | func (ex *Extractor) init() {
42 | ex.globalTagAttributes = make(map[string]([]*FQN))
43 | ex.globalTagAttributesMap = make(map[string]bool)
44 | ex.nameSpaceTagMap = make(map[string]string)
45 | ex.globalNodeMap = make(map[string]*Node)
46 | ex.root = new(Node)
47 | //ex.root.initialize(RootName, "", "", nil)
48 | ex.root.initialize("", "", "", nil)
49 | ex.hasStartElements = false
50 | ex.initted = true
51 | ex.tokenChannel = make(chan xml.Token, 100)
52 | ex.handleTokensDoneChannel = make(chan bool)
53 | go handleTokens(ex)
54 | }
55 |
56 | func (ex *Extractor) done() {
57 | close(ex.tokenChannel)
58 | _ = <-ex.handleTokensDoneChannel
59 | }
60 |
61 | func (ex *Extractor) extract(reader io.Reader) error {
62 | if ex.initted == false {
63 | return errors.New("extractor not properly initted: must run extractor.init() first")
64 | }
65 | decoder := xml.NewDecoder(reader)
66 |
67 | for {
68 | token, err := decoder.Token()
69 | if err != nil {
70 | if err.Error() == "EOF" {
71 | // OK
72 | break
73 | }
74 | log.Println(err)
75 | if !ex.ignoreXmlDecodingErrors {
76 | return err
77 | }
78 | }
79 | if token == nil {
80 | log.Println("Empty token")
81 | break
82 | }
83 | ex.tokenChannel <- xml.CopyToken(token)
84 | }
85 | return nil
86 | }
87 |
88 | func handleTokens(ex *Extractor) {
89 | tChannel := ex.tokenChannel
90 | handleTokensDoneChannel := ex.handleTokensDoneChannel
91 | depth := 0
92 | thisNode := ex.root
93 | first := true
94 | var progressCounter int64 = 0
95 |
96 | for token := range tChannel {
97 | //log.Println(token)
98 | switch element := token.(type) {
99 |
100 | case xml.Comment:
101 | if DEBUG {
102 | //log.Print(thisNode.name)
103 | //log.Printf("Comment: %+v\n", string(element))
104 | }
105 |
106 | case xml.ProcInst:
107 | if DEBUG {
108 | //log.Println("ProcInst: Target=" + element.Target + " Inst=[" + string(element.Inst) + "]")
109 | }
110 |
111 | case xml.Directive:
112 | if DEBUG {
113 | //log.Printf("Directive: %+v\n", string(element))
114 | }
115 |
116 | case xml.StartElement:
117 | progressCounter += 1
118 | if DEBUG {
119 | //log.Printf("StartElement: %+v\n", element)
120 | }
121 | ex.hasStartElements = true
122 |
123 | if element.Name.Local == "" {
124 | continue
125 | }
126 | thisNode = ex.handleStartElement(element, thisNode)
127 | thisNode.tempCharData = ""
128 | thisNode.ignoredTag = isIgnoredTag(element.Name.Local)
129 |
130 | if first {
131 | first = false
132 | ex.firstNode = thisNode
133 | }
134 | depth += 1
135 | if progress {
136 | if progressCounter%50000 == 0 {
137 | log.Print(progressCounter)
138 | }
139 | }
140 |
141 | case xml.CharData:
142 | if DEBUG {
143 | //log.Print(thisNode.name)
144 | //log.Printf("CharData: [%+v]\n", string(element))
145 | }
146 |
147 | //if !thisNode.hasCharData {
148 | charData := string(element)
149 | thisNode.tempCharData += charData //strings.TrimSpace(charData)
150 | thisNode.charDataCount += int64(len(charData))
151 | //}
152 |
153 | case xml.EndElement:
154 | //if ignoredTag(element.Name.Local) {
155 | //continue
156 | //}
157 |
158 | thisNode.nodeTypeInfo.checkFieldType(thisNode.tempCharData)
159 | thisNode.nodeTypeInfo.addFieldLength(thisNode.charDataCount)
160 | thisNode.charDataCount = 0
161 |
162 | if DEBUG {
163 | //log.Printf("EndElement: %+v\n", element)
164 | //log.Printf("[[" + thisNode.tempCharData + "]]")
165 | //log.Println("Char is empty: ", isJustSpacesAndLinefeeds(thisNode.tempCharData))
166 | }
167 | if !thisNode.hasCharData && !isJustSpacesAndLinefeeds(thisNode.tempCharData) {
168 | thisNode.hasCharData = true
169 |
170 | } else {
171 |
172 | }
173 | thisNode.tempCharData = ""
174 | depth -= 1
175 |
176 | for key, c := range thisNode.childCount {
177 | if c > 1 {
178 | thisNode.children[key].repeats = true
179 | }
180 | thisNode.childCount[key] = 0
181 | }
182 | if thisNode.peekParent() != nil {
183 | thisNode = thisNode.popParent()
184 | }
185 | }
186 | }
187 | handleTokensDoneChannel <- true
188 | close(handleTokensDoneChannel)
189 | }
190 |
191 | func space(n int) string {
192 | s := strconv.Itoa(n) + "Space"
193 | for i := 0; i < n; i++ {
194 | s += " "
195 | }
196 | return s
197 | }
198 |
199 | func (ex *Extractor) findNewNameSpaces(attrs []xml.Attr) {
200 | for _, attr := range attrs {
201 | if strings.HasPrefix(attr.Name.Space, XML_NAMESPACE_ACRONYM) {
202 | //log.Println("mmmmmmmmmmmmmmmmmmmmmmm", attr)
203 | //log.Println("+++++++++++++++++++++++++++", attr.Value, "|", attr.Name.Local, "|", attr.Name.Space)
204 | ex.nameSpaceTagMap[attr.Value] = attr.Name.Local
205 | }
206 | }
207 | }
208 |
209 | var full struct{}
210 |
211 | func (ex *Extractor) handleStartElement(startElement xml.StartElement, thisNode *Node) *Node {
212 | name := startElement.Name.Local
213 | space := startElement.Name.Space
214 |
215 | ex.findNewNameSpaces(startElement.Attr)
216 |
217 | var child *Node
218 | var attributes []*FQN
219 | key := nks(space, name)
220 |
221 | child, ok := thisNode.children[key]
222 | // Does thisNode node already exist as child
223 | //fmt.Println(space, name)
224 | if ok {
225 | thisNode.childCount[key] += 1
226 | attributes, ok = ex.globalTagAttributes[key]
227 | } else {
228 | // if thisNode node does not already exist as child, it may still exist as child on other node:
229 | child, ok = ex.globalNodeMap[key]
230 | if !ok {
231 | child = new(Node)
232 | DiscoveredOrder += 1
233 | child.discoveredOrder = DiscoveredOrder
234 | ex.globalNodeMap[key] = child
235 | spaceTag, _ := ex.nameSpaceTagMap[space]
236 | child.initialize(name, space, spaceTag, thisNode)
237 | thisNode.childCount[key] = 1
238 |
239 | attributes = make([]*FQN, 0, 2)
240 | ex.globalTagAttributes[key] = attributes
241 | } else {
242 | attributes = ex.globalTagAttributes[key]
243 | }
244 | thisNode.children[key] = child
245 | }
246 | child.pushParent(thisNode)
247 |
248 | // Extract attributes
249 | for _, attr := range startElement.Attr {
250 | bigKey := key + "_" + attr.Name.Space + "_" + attr.Name.Local
251 | _, ok := ex.globalTagAttributesMap[bigKey]
252 | if ok {
253 | fqn := findThisAttribute(attr.Name.Local, attr.Name.Space, ex.globalTagAttributes[key])
254 | if fqn == nil {
255 | log.Println("This should not be happening: fqn is nil")
256 | continue
257 | }
258 | lenValue := len(attr.Value)
259 | if lenValue > fqn.maxLength {
260 | fqn.maxLength = lenValue
261 | }
262 | } else {
263 | fqn := new(FQN)
264 | fqn.name = attr.Name.Local
265 | fqn.space = attr.Name.Space
266 | fqn.maxLength = len(attr.Value)
267 | //log.Println(name, "|", fqn.name, "||", fqn.space)
268 | attributes = append(attributes, fqn)
269 | ex.globalTagAttributesMap[bigKey] = true
270 | }
271 | }
272 | ex.globalTagAttributes[key] = attributes
273 | return child
274 | }
275 |
276 | func isJustSpacesAndLinefeeds(s string) bool {
277 | s = strings.Replace(s, "\\n", "", -1)
278 | s = strings.Replace(s, "\n", "", -1)
279 | return len(strings.TrimSpace(s)) == 0
280 | }
281 |
--------------------------------------------------------------------------------
/fieldTemplate.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | //"fmt"
6 | "log"
7 | //"strconv"
8 | "text/template"
9 | )
10 |
11 | type FieldDef struct {
12 | XMLName string
13 | XMLNameSpace string
14 | GoName string
15 | GoType string
16 | GoTypeArrayOrPointer string
17 | Length int64
18 | //Foo bool
19 | }
20 |
21 | var fieldTemplate *template.Template
22 |
23 | var fieldTemplateString = `{{.GoName}} {{.GoTypeArrayOrPointer}}{{.GoType}} ` + "`" + `xml:"{{if notEmpty .XMLNameSpace}}{{.XMLNameSpace}} {{end}}{{.XMLName}},omitempty" json:"{{.XMLName}},omitempty"` + "`" + ``
24 |
25 | func render(otd FieldDef) (string, error) {
26 | var err error
27 | // fieldTemplate = template.Must(template.New("fieldTemplate").Funcs(template.FuncMap{
28 | fieldTemplate, err = template.New("fieldTemplate").Funcs(template.FuncMap{
29 | "notEmpty": func(feature string) bool {
30 | return len(feature) > 0
31 | },
32 | }).Parse(fieldTemplateString)
33 |
34 | if err != nil {
35 | return "", err
36 | }
37 |
38 | var buf bytes.Buffer
39 |
40 | //err := t.Execute(os.Stdout, ot)
41 | err = fieldTemplate.Execute(&buf, otd)
42 | if err != nil {
43 | return "", err
44 | }
45 | //fmt.Println(buf.String())
46 | //return "\t" + buf.String() + " // ZZmaxLength=" + strconv.FormatInt(otd.Length, 10), nil
47 | return "\t" + buf.String(), nil
48 | }
49 |
50 | func runValidateFieldTemplate(printToLog bool) error {
51 | fieldDef := FieldDef{
52 | XMLName: "xmlName",
53 | XMLNameSpace: "xmlNameSpace",
54 | GoName: "Foobar",
55 | GoType: "string",
56 | GoTypeArrayOrPointer: "[]",
57 | Length: 32,
58 | }
59 |
60 | string, err := render(fieldDef)
61 | if printToLog {
62 | log.Println("validateFieldTemplate")
63 | log.Println("Using template:", fieldTemplateString)
64 | log.Println(string)
65 |
66 | }
67 | if err != nil {
68 | log.Println("Error with field template:", err)
69 | }
70 | return err
71 | }
72 |
--------------------------------------------------------------------------------
/fqn.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | type FQN struct {
4 | space string
5 | name string
6 | maxLength int
7 | }
8 |
9 | type FQNAbbr struct {
10 | FQN
11 | abbr string
12 | }
13 |
--------------------------------------------------------------------------------
/genericReader.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "compress/bzip2"
6 | "compress/gzip"
7 | "io"
8 | "log"
9 | "net/http"
10 | "os"
11 | "strings"
12 | )
13 |
14 | type GenericReader struct {
15 | io.Reader
16 | reader io.Reader
17 | }
18 |
19 | func (ge *GenericReader) Read(p []byte) (n int, err error) {
20 | return ge.reader.Read(p)
21 | }
22 |
23 | func (ge *GenericReader) Open(name string) error {
24 | if name == "" {
25 | return nil
26 | }
27 | if strings.HasPrefix(name, "http://") || strings.HasPrefix(name, "https://") {
28 | return ge.openUrl(name)
29 | } else {
30 | return ge.openLocalFile(name)
31 | }
32 | }
33 |
34 | func (ge *GenericReader) Close() error {
35 | return nil
36 | }
37 |
38 | func (ge *GenericReader) openLocalFile(filename string) error {
39 | file, err := openIfExistsIsFileIsReadable(filename)
40 | if err != nil {
41 | return err
42 | }
43 |
44 | if strings.HasSuffix(filename, "bz2") {
45 | ge.reader = bufio.NewReader(bzip2.NewReader(bufio.NewReader(file)))
46 | } else {
47 | if strings.HasSuffix(filename, "gz") {
48 | reader, err := gzip.NewReader(bufio.NewReader(file))
49 | if err != nil {
50 | return err
51 | }
52 | ge.reader = bufio.NewReader(reader)
53 | } else {
54 | ge.reader = bufio.NewReader(file)
55 | }
56 | }
57 | return nil
58 | }
59 |
60 | func (gr *GenericReader) openUrl(url string) error {
61 | res, err := http.Get(url)
62 | if err != nil {
63 | return err
64 | }
65 |
66 | if res.StatusCode != 200 {
67 | log.Fatal("ERROR: bad http status code != 200: ", res.StatusCode, " ", url)
68 | return nil
69 |
70 | }
71 | gr.reader = res.Body
72 | return nil
73 | }
74 |
75 | func openIfExistsIsFileIsReadable(fileName string) (*os.File, error) {
76 | file, err := os.Open(fileName) // For read access.
77 | log.Print(fileName)
78 | if err != nil {
79 | log.Print("Problem opening file: [" + fileName + "]")
80 | log.Print(err)
81 | return nil, err
82 | }
83 | if _, err := os.Stat(fileName); os.IsNotExist(err) {
84 | log.Print("Problem stat'ing file: [" + fileName + "]")
85 | return nil, err
86 | }
87 |
88 | fi, err := file.Stat()
89 | if err != nil {
90 | log.Print("Problem stat'ing file: [" + fileName + "]")
91 | return nil, err
92 | }
93 |
94 | fm := fi.Mode()
95 | if !fm.IsRegular() {
96 | error := new(InternalError)
97 | error.ErrorString = "Is directory, needs to be file: " + fileName
98 | log.Print(error.ErrorString)
99 | return nil, error
100 | }
101 |
102 | log.Print(fm.Perm().String())
103 | if fm.Perm().String()[7] != 'r' {
104 | error := new(InternalError)
105 | error.ErrorString = "Exists but unable to read: " + fileName
106 | log.Print(error.ErrorString)
107 | return nil, error
108 | }
109 | return file, nil
110 | }
111 |
112 | type InternalError struct {
113 | ErrorString string
114 | }
115 |
116 | func (ie *InternalError) Error() string {
117 | return "Error: " + ie.ErrorString
118 | }
119 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/gnewton/chidley
2 |
3 | go 1.17
4 |
5 | require github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8
6 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
2 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
3 |
--------------------------------------------------------------------------------
/javaTypes.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | const JavaString = "String"
4 | const JavaBoolean = "boolean"
5 | const JavaShort = "short"
6 | const JavaFloat = "float"
7 | const JavaDouble = "double"
8 | const JavaInt = "int"
9 | const JavaLong = "long"
10 |
11 | const GoBool = "bool"
12 |
13 | const GoInt8 = "int8"
14 | const GoUint8 = "uint8"
15 | const GoInt16 = "int16"
16 |
17 | const GoUint16 = "uint16"
18 | const GoInt32 = "int32"
19 |
20 | const GoUint32 = "uint32"
21 | const GoInt64 = "int64"
22 |
23 | const GoFloat32 = "float32"
24 |
25 | const GoFloat64 = "float64"
26 |
27 | func findJavaType(nti *NodeTypeInfo, useType bool) string {
28 | if !useType {
29 | return JavaString
30 | }
31 | goType := findType(nti, true)
32 |
33 | switch goType {
34 | case GoBool:
35 | return JavaBoolean
36 | case GoInt8, GoUint8, GoInt16:
37 | return JavaShort
38 | case GoUint16, GoInt32:
39 | return JavaInt
40 | case GoUint32, GoInt64:
41 | return JavaLong
42 | case GoFloat32:
43 | return JavaFloat
44 | case GoFloat64:
45 | return JavaDouble
46 | }
47 | return JavaString
48 | }
49 |
--------------------------------------------------------------------------------
/jaxbTemplate.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type JaxbPackageInfo struct {
8 | BaseNameSpace string
9 | AdditionalNameSpace []*FQNAbbr
10 | PackageName string
11 | }
12 |
13 | type JaxbMainClassInfo struct {
14 | PackageName string
15 | BaseXMLClassName string
16 | SourceXMLFilename string
17 | Date time.Time
18 | }
19 |
20 | type JaxbClassInfo struct {
21 | Name string
22 | Root bool
23 | PackageName, ClassName string
24 | Attributes []*JaxbAttribute
25 | Fields []*JaxbField
26 | HasValue bool
27 | ValueType string
28 | Date time.Time
29 | }
30 |
31 | type JaxbAttribute struct {
32 | Name string
33 | NameUpper string
34 | NameLower string
35 | NameSpace string
36 | }
37 | type JaxbField struct {
38 | TypeName string
39 | Name string
40 | NameUpper string
41 | NameLower string
42 | NameSpace string
43 | Repeats bool
44 | }
45 |
46 | func (jb *JaxbClassInfo) init() {
47 | jb.Attributes = make([]*JaxbAttribute, 0)
48 | jb.Fields = make([]*JaxbField, 0)
49 | }
50 |
51 | const jaxbClassTemplate = `
52 | // Generated by chidley https://github.com/gnewton/chidley
53 | // Date: {{.Date}}
54 | //
55 | package {{.PackageName}}.xml;
56 |
57 | import java.util.ArrayList;
58 | import javax.xml.bind.annotation.*;
59 | import com.google.gson.annotations.SerializedName;
60 |
61 | @XmlAccessorType(XmlAccessType.FIELD)
62 | @XmlRootElement(name="{{.Name}}")
63 | public class {{.ClassName}} {
64 | {{if .Attributes}}
65 | // Attributes{{end}}
66 | {{range .Attributes}}
67 | {{if .NameSpace}}
68 | @XmlAttribute(namespace = "{{.NameSpace}}"){{else}} @XmlAttribute(name="{{.Name}}"){{end}}
69 | @SerializedName("{{.Name}}")
70 | public String {{.NameLower}};{{end}}
71 | {{if .Fields}}
72 | // Fields{{end}}{{range .Fields}}
73 | @XmlElement(name="{{.Name}}")
74 | @SerializedName("{{.Name}}")
75 | {{if .Repeats}}public ArrayList<{{.TypeName}}> {{.NameLower}}{{else}}public {{.TypeName}} {{.NameLower}}{{end}};
76 | {{end}}
77 | {{if .HasValue}}
78 | // Value
79 | @XmlValue
80 | public {{.ValueType}} tagValue;{{end}}
81 | }
82 | `
83 |
84 | const jaxbMainTemplate = `
85 | // Generated by chidley https://github.com/gnewton/chidley
86 | // Date: {{.Date}}
87 | //
88 |
89 | package {{.PackageName}};
90 |
91 | import java.io.File;
92 | import javax.xml.bind.JAXBContext;
93 | import javax.xml.bind.JAXBException;
94 | import javax.xml.bind.Unmarshaller;
95 | import {{.PackageName}}.xml.{{.BaseXMLClassName}};
96 | import com.google.gson.Gson;
97 | import com.google.gson.GsonBuilder;
98 | import java.net.URL;
99 | import java.net.URLClassLoader;
100 |
101 |
102 |
103 | public class Main {
104 | public static void main(String[] args) {
105 | try {
106 | //https://jaxp.java.net/1.5/JAXP1.5Guide.html
107 | // To fix error: Caused by:
108 | //org.xml.sax.SAXParseException; systemId: file:/home/gnewton/gocode/src/github.com/gnewton/chidley/xml/MozartTrio.xml; lineNumber: 2; columnNumber: 123; External DTD: Failed to read external DTD 'partwise.dtd', because 'http' access is not allowed due to restriction set by the accessExternalDTD property.
109 | System.setProperty("javax.xml.accessExternalSchema", "all");
110 | System.setProperty("javax.xml.accessExternalDTD", "all");
111 | System.setProperty("javax.xml.XMLConstants.ACCESS_EXTERNAL_STYLESHEET", "all");
112 |
113 | // System.setProperty("http.agent", "Mozilla/4.76");
114 | System.setProperty("http.agent", "Mozilla/5.0 (X11; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0");
115 |
116 | File file = new File("{{.SourceXMLFilename}}");
117 | JAXBContext jaxbContext = JAXBContext.newInstance({{.BaseXMLClassName}}.class);
118 |
119 | Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
120 | {{.BaseXMLClassName}} root = ({{.BaseXMLClassName}}) jaxbUnmarshaller.unmarshal(file);
121 |
122 | Gson gson = new GsonBuilder().setPrettyPrinting().create();
123 | System.out.println(gson.toJson(root));
124 |
125 | } catch (Throwable e) {
126 | e.printStackTrace();
127 | // Print classpath
128 | System.err.println("CLASSPATH START");
129 | ClassLoader cl = ClassLoader.getSystemClassLoader();
130 | URL[] urls = ((URLClassLoader)cl).getURLs();
131 | for(URL url: urls){
132 | System.err.println("\n" + url.getFile());
133 | }
134 | System.err.println("CLASSPATH END");
135 | }
136 | }
137 | }
138 | `
139 |
140 | const jaxbPackageInfoTemplage = `
141 | @XmlSchema(
142 | namespace="{{.BaseNameSpace}}",
143 | elementFormDefault = XmlNsForm.QUALIFIED{{if .AdditionalNameSpace}},
144 | xmlns={
145 | {{range .AdditionalNameSpace}}
146 | @XmlNs(prefix="{{.abbr}}", namespaceURI="{{.space}}"),
147 | {{end}}
148 | }
149 | {{end}}
150 | )
151 | package {{.PackageName}};
152 |
153 | import javax.xml.bind.annotation.*;
154 | `
155 |
--------------------------------------------------------------------------------
/makereadme/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | // Copyright 2014,2015,2016 Glen Newton
4 | // glen.newton@gmail.com
5 |
6 | import (
7 | "io/ioutil"
8 | "log"
9 | "os"
10 | "text/template"
11 | )
12 |
13 | type ReadmeInfo struct {
14 | ChidleyUsage string
15 | GeneratedUsage string
16 | GeneratedXMLToJson string
17 | GeneratedXMLToXML string
18 | GeneratedCountElements string
19 | ChidleyOnlyStructOutput string
20 | SimpleExampleXMLFile string
21 | SimpleExampleXMLChidleyGoStructs string
22 | SimpleExampleXMLChidleyGoStructsCollapsed string
23 | SimpleExampleXMLChidleyGoStructsWithTypes string
24 | PubmedXMLFileName string
25 |
26 | PubmedExampleXMLChidleyGoStructsWithTypes string
27 | PubmedExampleXMLChidleyGoStructsWithTypeTiming string
28 | GeneratedPubmedCount string
29 | GeneratedPubmedNoStreaming string
30 | GeneratedPubmedStreaming string
31 | GeneratedPubmedXMLToJson string
32 | GeneratedPubmedXMLToXML string
33 | ChidleyGenerateJava string
34 | ChidleyGenerateJavaChangePackageName string
35 | ChidleyGenerateJavaMavenBuild string
36 | ChidleyGenerateJavaRun string
37 | }
38 |
39 | const empty = `
40 | ***********EMPTY`
41 |
42 | func main() {
43 | log.SetFlags(log.LstdFlags | log.Lshortfile)
44 | var err error
45 | var tmp []byte
46 |
47 | ri := ReadmeInfo{
48 | ChidleyUsage: empty,
49 | GeneratedUsage: empty,
50 | GeneratedXMLToJson: empty,
51 | GeneratedXMLToXML: empty,
52 | GeneratedCountElements: empty,
53 | ChidleyOnlyStructOutput: empty,
54 | SimpleExampleXMLFile: empty,
55 | SimpleExampleXMLChidleyGoStructs: empty,
56 | SimpleExampleXMLChidleyGoStructsCollapsed: empty,
57 | SimpleExampleXMLChidleyGoStructsWithTypes: empty,
58 |
59 | PubmedXMLFileName: empty,
60 | PubmedExampleXMLChidleyGoStructsWithTypes: empty,
61 | PubmedExampleXMLChidleyGoStructsWithTypeTiming: empty,
62 | GeneratedPubmedCount: empty,
63 | GeneratedPubmedNoStreaming: empty,
64 | GeneratedPubmedStreaming: empty,
65 | GeneratedPubmedXMLToJson: empty,
66 | GeneratedPubmedXMLToXML: empty,
67 | ChidleyGenerateJava: empty,
68 | ChidleyGenerateJavaChangePackageName: empty,
69 | ChidleyGenerateJavaMavenBuild: empty,
70 | ChidleyGenerateJavaRun: empty,
71 | }
72 |
73 | ri.ChidleyUsage, err = runCaptureStdout("..", "./chidley", "-n")
74 |
75 | if err != nil {
76 | log.Fatal(err)
77 | }
78 |
79 | tmp, err = ioutil.ReadFile("../data/test.xml")
80 | if err != nil {
81 | log.Fatal(err)
82 | }
83 | ri.SimpleExampleXMLFile = string(tmp)
84 |
85 | ri.SimpleExampleXMLChidleyGoStructs, err = runCaptureStdout("..", "./chidley", "-G", "data/test.xml")
86 |
87 | if err != nil {
88 | log.Fatal(err)
89 | }
90 |
91 | ri.SimpleExampleXMLChidleyGoStructsCollapsed = string(tmp)
92 |
93 | ri.SimpleExampleXMLChidleyGoStructsCollapsed, err = runCaptureStdout("..", "./chidley", "-G", "-F", "data/test.xml")
94 | if err != nil {
95 | log.Fatal(err)
96 | }
97 |
98 | ri.SimpleExampleXMLChidleyGoStructsWithTypes, err = runCaptureStdout("..", "./chidley", "-G", "-t", "data/test.xml")
99 | if err != nil {
100 | log.Fatal(err)
101 | }
102 |
103 | ri.PubmedXMLFileName = "xml/pubmed_xml_12750255.xml.bz2"
104 | ri.PubmedExampleXMLChidleyGoStructsWithTypes, err = runCaptureStdout("..", "./chidley", "-G", "-t", ri.PubmedXMLFileName)
105 | if err != nil {
106 | log.Fatal(err)
107 | }
108 |
109 | ri.PubmedExampleXMLChidleyGoStructsWithTypeTiming, err = runCaptureStderr("..", "/usr/bin/time", "-f", "\"Seconds: %E Resident size: %M\"", "./chidley", "-G", ri.PubmedXMLFileName)
110 | if err != nil {
111 | log.Fatal(err)
112 | }
113 |
114 | dirName := "example1"
115 | err = os.MkdirAll(dirName, 0700)
116 | if err != nil {
117 | log.Fatal(err)
118 | }
119 | var str string
120 |
121 | str, err = runCaptureStdout("..", "./chidley", "-W", ri.PubmedXMLFileName)
122 | if err != nil {
123 | log.Fatal(err)
124 | }
125 |
126 | err = ioutil.WriteFile(dirName+"/main.go", []byte(str), 0644)
127 | if err != nil {
128 | log.Fatal(err)
129 | }
130 |
131 | str, err = runCaptureStdout(dirName, "bash", "-c", "go build")
132 | if err != nil {
133 | log.Fatal(err)
134 | }
135 |
136 | ri.GeneratedPubmedCount, err = runCaptureStdout(dirName, "bash", "-c", "./"+dirName+" -c | sort -n")
137 | if err != nil {
138 | log.Fatal(err)
139 | }
140 |
141 | err = generateSimpleGoCode()
142 |
143 | if err != nil {
144 | log.Fatal(err)
145 | }
146 |
147 | // Build generated code
148 | var output string
149 | output, err = runCaptureStdout("gencode", "go", "build")
150 | if err != nil {
151 | log.Println(output)
152 | log.Fatal(err)
153 | }
154 |
155 | // Run generated code, usage
156 | ri.GeneratedUsage, err = runCaptureStdout("gencode", "./gencode", "-h")
157 | if err != nil {
158 | log.Fatal(err)
159 | }
160 |
161 | // Run generated code, convert XML to JSON
162 | ri.GeneratedXMLToJson, err = runCaptureStdout("gencode", "./gencode", "-j")
163 | if err != nil {
164 | log.Fatal(err)
165 | }
166 |
167 | // Run generated code, convert XML to XML
168 | ri.GeneratedXMLToXML, err = runCaptureStdout("gencode", "./gencode", "-x")
169 | if err != nil {
170 | log.Fatal(err)
171 | }
172 |
173 | // Run generated code, count XML tags
174 | ri.GeneratedCountElements, err = runCaptureStdout("gencode", "./gencode", "-c")
175 | if err != nil {
176 | log.Fatal(err)
177 | }
178 |
179 | //log.Println(out)
180 |
181 | if true {
182 | t := template.Must(template.New("readmeTemplate").Parse(readmeTemplate))
183 |
184 | err = t.Execute(os.Stdout, ri)
185 |
186 | if err != nil {
187 | log.Println("executing template:", err)
188 | }
189 | }
190 | //os.Setenv("PATH", "/home/newtong/go/src/github.com/gnewton/chidley")
191 |
192 | }
193 |
194 | func generateSimpleGoCode() error {
195 | //tmp, err := runCaptureStdout(".", "mkdir", "gencode")
196 | _, _ = runCaptureStdout(".", "mkdir", "gencode")
197 | tmp, err := runCaptureStdout(".", "../chidley", "-W", "../data/test.xml") //> gencode/main.go)
198 |
199 | if err != nil {
200 | log.Println(err)
201 | return err
202 | }
203 |
204 | //file, err := os.Create("gencode/main.go")
205 | file, _ := os.Create("gencode/main.go")
206 | file.WriteString(tmp)
207 | file.Sync()
208 | file.Close()
209 |
210 | //_, _ = runCaptureStdout(".", "rmdir", "gencode")
211 | return err
212 | }
213 |
--------------------------------------------------------------------------------
/makereadme/readme.sh.old:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | pubmed_filename="pubmedsample18n0001.xml.gz"
4 | pubmed_filename="pubmed18n0001.xml.gz"
5 | pubmed_url="ftp://ftp.ncbi.nlm.nih.gov/pubmed/baseline/"
6 | #pubmed_url="ftp://ftp.ncbi.nlm.nih.gov/pubmed/baseline-2018-sample/"
7 | pubmed_url+=$pubmed_filename
8 |
9 | test_filename="../data/test.xml"
10 |
11 | #echo "" > foo
12 |
13 | if [ ! -e "$pubmed_filename" ]
14 | then
15 | wget $pubmed_url
16 | fi
17 |
18 | function out(){
19 | echo "$1"
20 | }
21 |
22 | function exe(){
23 | out "\`\`\`"
24 | out "$($1 2>&1)"
25 | out "\`\`\`"
26 | }
27 |
28 |
29 | ############start
30 | out "# \`chidley\` converts *any* XML to Go structs (and therefor to JSON)"
31 | out "* By *any*, any XML that can be read by the Go [xml package](http://golang.org/pkg/encoding/xml/) decoder. "
32 | out "* Where *convert* means, generates Go code that when compiled, will convert the XML to JSON"
33 | out "* or will just generate the Go structs that represent the input XML"
34 | out "* or converts XML to XML (useful for validation) "
35 | out ""
36 | out "Author: Glen Newton"
37 | out "Language: Go"
38 | out ""
39 | out "## How does it work (with such a small memory footprint)"
40 | out "\`chidley\` uses the input XML to build a model of each XML element (aka tag)."
41 | out "It examines each instance of a tag, and builds a (single) prototypical representation; that is, the union of all the attributes and all of the child elements of all instances of the tag."
42 | out "So even if there are million instances of a specific tag, there is only one model tag representation."
43 | out "Note that a tag is unique by its namespace+tagname combination (in the Go xml package parlance, [\`space + local\`](http://golang.org/pkg/encoding/xml/#Name)."
44 | out "### Types"
45 | out "\`chidley\` by default makes all values (attributes, tag content) in the generated Go structs a string (which is always valid for XML attributes and content), but it has a flag (\`-t\`) where it will detect and use the most appropriate type. "
46 | out "\`chidley\` tries to fit the **smallest** Go type. "
47 | out "For example, if all instances of a tag contain a number, and all instances are -128 to 127, then it will use an \`int8\` in the Go struct."
48 |
49 | out ""
50 | out "## Usage"
51 | exe "../chidley -h"
52 |
53 | out ""
54 | out "### Specific Usages:"
55 | out "* \`chidley -W ...\`: writes Go code to standard out, so this output should be directed to a filename and subsequently be compiled. When compiled, the resulting binary will:"
56 | out " * convert the XML file to JSON"
57 | out " * or convert the XML file to XML (useful for validation)"
58 | out " * or count the # of elements (space, local) in the XML file"
59 | out "* \`chidley -G ...\`: writes just the Go structs that represent the input XML. For incorporation into the user's code base."
60 |
61 | out "### Example:"
62 | out "Using filename \`test.xml\`"
63 | exe "cat ../test.xml"
64 | cmd="../chidley ./${test_filename}"
65 |
66 | out $cmd
67 | out "### Generated Go structs"
68 | exe "$cmd"
69 |
70 | if [ ! -e "test1" ]
71 | then
72 | mkdir test1
73 | fi
74 |
75 |
76 |
77 | eval "../chidley -W ./${test_filename} > test1/t.go"
78 |
79 | cd test1
80 | go build
81 |
82 |
83 | out "### Usage -W"
84 | exe "./test1 -h"
85 |
86 | out "##### Generated code:: xml -> json"
87 | exe "./test1 -j -s"
88 |
89 | out "##### Generated code: xml -> xml"
90 | exe "./test1 -x -s"
91 |
92 | out "##### Generated code: Count elements -c"
93 | exe "./test1 -c"
94 |
95 | cd ..
96 | rm test1/*
97 |
98 |
99 |
100 |
101 | out "### Example chidley -G:"
102 | out "#### Default"
103 |
104 | out "#### Types turned on -t"
105 | exe "../chidley -t ./${test_filename}"
106 |
107 | out "Note the \`Number int16\` in \`Chiyear\`"
108 |
109 | out "## Larger more complex example"
110 |
111 |
112 | out "Using the large pubmed XML file, $pubmed_url "
113 | cmd="../chidley -t -F ./${pubmed_filename}"
114 | out "\`\$ ${cmd}"
115 | exe "$cmd"
116 |
117 |
118 | out "Timings"
119 | out "### Generate Go program: -W"
120 | out "#### Generated program: count tags"
121 |
122 | out "#### Generated program: convert XML to JSON"
123 | out "##### No streaming"
124 | out "##### With streaming -s"
125 | out "##### Sample of generated JSON"
126 |
127 | out "##### Sample of generated XML to XML"
128 |
129 | out "## Java/JAXB"
130 | out "### Usage"
131 |
132 |
133 | out "### New"
134 |
135 | out "#### Build Java package"
136 | out "#### Running"
137 |
138 |
139 | out "### Limitations"
140 |
141 |
142 |
--------------------------------------------------------------------------------
/makereadme/template.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | const endInline = `
4 |
5 | ` + "`" + `` + "`" + `` + "`"
6 |
7 | const beginInline = `
8 |
9 | ` + endInline
10 |
11 | const readmeTemplate = `
12 | # ` + "`" + `chidley` + "`" + `
13 |
14 | # NOTE: The below documentation is out of date with the most recent release. I will work to update these docs in the next week. 2018/10/17
15 |
16 | ###############################################################################################################################################
17 |
18 | ## ` + "`" + `chidley` + "`" + ` converts *any* XML to Go structs (and therefor to JSON)
19 | * By *any*, any XML that can be read by the Go [xml package](http://golang.org/pkg/encoding/xml/) decoder.
20 | * Where *convert* means, generates Go code that when compiled, will convert the XML to JSON
21 | * or will just generate the Go structs that represent the input XML
22 | * or converts XML to XML (useful for validation)
23 |
24 | Author: Glen Newton
25 | Language: Go
26 |
27 | ## New
28 |
29 | # 2016.08.14
30 | Added ability to sort structs into the same order the XML is encountered in the file. Useful for human readers comparing the Go structs to the original XML.
31 | Use flag ` + "`" + `-X` + "`" + ` to invoke. Overrides default of sorting by alphabetical sorting.
32 |
33 | # 2015.07.24
34 | ` + "`" + `chidley` + "`" + ` now supports the user naming of the resulting JAXB Java class package.
35 | Previously the package name could only be ` + "`" + `ca/gnewton/chidley/jaxb` + "`" + `.
36 | Now, using the ` + "`" + `-P name` + "`" + `, the ` + "`" + `jaxb` + "`" + ` default can be altered.
37 |
38 | So ` + "`" + `chidley -J -P "foobar" sample.xml` + "`" + ` will result in Java classes with package name: ` + "`" + `ca/gnewton/chidley/foobar` + "`" + `.
39 |
40 |
41 | ### Previous
42 |
43 | ` + "`" + `chidley` + "`" + ` now has support for Java/JAXB. It generates appropriate Java/JAXB classes and associated maven pom.
44 |
45 | See [Java/JAXB section below](#user-content-java) for usage.
46 |
47 |
48 | ## How does it work (with such a small memory footprint)
49 | ` + "`" + `chidley` + "`" + ` uses the input XML to build a model of each XML element (aka tag).
50 | It examines each instance of a tag, and builds a (single) prototypical representation; that is, the union of all the attributes and all of the child elements of all instances of the tag.
51 | So even if there are million instances of a specific tag, there is only one model tag representation.
52 | Note that a tag is unique by its namespace+tagname combination (in the Go xml package parlance, [` + "`" + `space + local` + "`" + `](http://golang.org/pkg/encoding/xml/#Name).
53 | ### Types
54 | ` + "`" + `chidley` + "`" + ` by default makes all values (attributes, tag content) in the generated Go structs a string (which is always valid for XML attributes and content), but it has a flag (` + "`" + `-t` + "`" + `) where it will detect and use the most appropriate type.
55 | ` + "`" + `chidley` + "`" + ` tries to fit the **smallest** Go type.
56 | For example, if all instances of a tag contain a number, and all instances are -128 to 127, then it will use an ` + "`" + `int8` + "`" + ` in the Go struct.
57 |
58 | ## ` + "`" + `chidley` + "`" + ` binary
59 | Compiled for 64bit Linux Fedora18, go version go1.3 linux/amd64
60 |
61 | ## Usage` + beginInline + `
62 | $ chidley -h
63 | {{.ChidleyUsage}}
64 | $` + endInline + `
65 |
66 | ### Specific Usages:
67 | * ` + "`" + `chidley -W ` + "`" + `: writes Go code to standard out, so this output should be directed to a filename and subsequently be compiled. When compiled, the resulting binary will:
68 | * convert the XML file to JSON
69 | * or convert the XML file to XML (useful for validation)
70 | * or count the # of elements (space, local) in the XML file
71 | * ` + "`" + `chidley -G ...` + "`" + `: writes just the Go structs that represent the input XML. For incorporation into the user's code base.
72 |
73 |
74 | ### Example
75 | #### ` + "`" + `data/test.xml` + "`" + `:` + beginInline + `
76 | {{.SimpleExampleXMLFile}}` + endInline + `
77 |
78 | #### Generated Go structs:
79 | ` + beginInline + `
80 | {{.SimpleExampleXMLChidleyGoStructs}}` + endInline + `
81 |
82 | Note that ` + "`" + `chidley` + "`" + `prepends a ` + "`" + `C` + "`" + `in front of every Go struct that corresponds to an XML tag in the original XML. It also does not alter the tag part of the Go struct name (except where noted below in "Name Changes").
83 | The reason this is done is 1) The Go XML and JSON libraries only operate on public fields (name must start with a capital); and 2) To avoid name collisions.
84 | Here is a simple and contrived example of name collisions in XMK:
85 | ` + beginInline + `
86 |
87 | Fred
88 | Gone with the Wind
89 |
90 | ` + endInline + `
91 | In order to work` + "`" + `` + "`" + ` would have to be capitalized, causing a collision with ` + "`" + `` + "`" + `
92 | Prefixing both with a capital c avoid this.
93 |
94 | This prefix can be changed with the ` + "`" + `-e` + "`" + ` flag
95 |
96 |
97 |
98 | Note that all XMl tags are converted to Go structs.
99 | However, for those that always correspond to a single element (no sub-tags & no XML attributes), like title:` + "`" + `Footfall` + "`" + ` this is a bit of a waste.
100 | It is possible to have ` + "`" + `chidley` + "`" + `collapse these into inline strings with the ` + "`" + `-F` + "`" + `flag. However, if your example XML is not canonical (i.e. it does not exhibit all uses of all XML tags), it may result in Go structs that do not capture everything that is needed.
101 |
102 | ## Name changes: XML vs. Go structs
103 | XML names can contain dots ` + "`" + `.` + "`" + ` and hyphens or dashes ` + "`" + `-` + "`" + `. These are not valid identifiers for Go structs or variables. These are mapped as:
104 | * ` + "`" + `"-": "_"` + "`" + `
105 | * ` + "`" + `".": "_dot_"` + "`" + `
106 |
107 |
108 | Example:
109 | ` + beginInline + `
110 | ` + "`$" + `chidley -F data/test.xml` + "`" + `:
111 | {{.SimpleExampleXMLChidleyGoStructsCollapsed}}` + endInline + `
112 |
113 | #### Generating code to read XML` + `
114 | ` + "`chidley`" + ` can generate Go code that will read in the XML and output a number of things, including the equivalent JSON, XML (XML to XML useful for validation), and a count total for each XML tag in the source file
115 |
116 | Generating code:
117 | ` + beginInline + `
118 | $ mkdir gencode
119 | $ chidley -W data/test.xml> gencode/main.go
120 | ` + endInline + `
121 |
122 | #### Usage of generated code
123 | ` + beginInline + `
124 | $ cd gencode
125 | $ go build
126 | $ ./gencode
127 | {{.GeneratedUsage}}
128 | ` + endInline + `
129 |
130 | ##### Generated code: Convert XML to JSON ` + "`" + `-j` + "`" + beginInline + `
131 | $ ./test1 -j -f ../../xml/test1.xml
132 | {{.GeneratedXMLToJson}}` + endInline + `
133 |
134 | ##### Generated code: Convert XML to XML ` + "`" + `-x` + "`" + `
135 | ` + beginInline + `$ ./test1 -x -f ../../xml/test1.xml
136 | {{.GeneratedXMLToXML}}` + endInline + `
137 |
138 | ##### Generated code: Count elements ` + "`" + `-c` + "`" + `
139 | XML elements (or tags) are counted in the source file (space,local) and are printed-out, unsorted
140 | ` + beginInline + `$ gencode -c
141 | {{.GeneratedCountElements}}` + endInline + `
142 |
143 | **Note**: the underscore before the colon indicates there is no (or the default) namespace for the element.
144 |
145 | ## Type example
146 | ` + "`" + `` + "`" + `` + "`" + `
147 | {{.SimpleExampleXMLFile}}
148 |
149 | ` + "`" + `` + "`" + `` + "`" + `
150 |
151 | #### Default
152 | ` + "`" + `` + "`" + `` + "`" + `
153 | $ ./chidley -G xml/testType.xml
154 | {{.SimpleExampleXMLChidleyGoStructs}}
155 |
156 | ` + "`" + `` + "`" + `` + "`" + `
157 |
158 | #### Types turned on ` + "`" + `-t` + "`" + `
159 | ` + "`" + `` + "`" + `` + "`" + `
160 | $ ./chidley -G -t data/xml.test
161 | {{.SimpleExampleXMLChidleyGoStructsWithTypes}}
162 |
163 | ` + "`" + `` + "`" + `` + "`" + `
164 |
165 | Notice:
166 | * ` + "`" + `Text int8` + "`" + ` in ` + "`" + `Chi_age` + "`" + `
167 | * ` + "`" + `Text bool` + "`" + ` in ` + "`" + `Chi_married` + "`" + `
168 |
169 | ## Go struct name prefix
170 | ` + "`" + `chidley` + "`" + ` by default prepends a prefix to Go struct type identifiers. The default is ` + "`" + `Chi` + "`" + ` but this can be changed with the ` + "`" + `-e` + "`" + ` flag. If changed from the default, the new prefix must start with a capital letter (for the XML annotation and decoder to work: the struct fields must be public).
171 |
172 | ## Warning
173 | If you are going to use the ` + "`" + `chidley` + "`" + ` generated Go structs on XML other than the input XML, you need to make sure the input XML has examples of all tags, and tag attribute and tag child tag combinations.
174 |
175 | If the input does not have all of these, and you use new XML that has tags not found in the input XML, attributes not seen in tags in the input XML, or child tags not encountered in the input XML, these will not be *seen* by the xml decoder, as they will not be in the Go structs used by the xml decoder.
176 |
177 | ## Limitations
178 | ` + "`" + `chidley` + "`" + ` is constrained by the underlying Go [xml package](http://golang.org/pkg/encoding/xml/)
179 | Some of these limitations include:
180 | * The default encoding supported by ` + "`" + `encoder/xml` + "`" + ` is UTF-8. Right now ` + "`" + `chidley` + "`" + ` does not support additional charsets.
181 | An xml decoder that handles charsets other than UTF-8 is possible (see example https://stackoverflow.com/questions/6002619/unmarshal-an-iso-8859-1-xml-input-in-go).
182 | It is possible that this method might be used in the future to extend ` + "`" + `chidley` + "`" + ` to include a small set of popular charsets.
183 | * For vanilla XML with no namespaces, there should be no problem using ` + "`" + `chidley` + "`" + `
184 |
185 | ### Go ` + "`" + `xml` + "`" + ` package Namespace issues
186 | * There are a number of bugs open for the Go xml package that relate to XML namespaces: https://code.google.com/p/go/issues/list?can=2&q=xml+namespace If the XML you are using uses namespaces in certain ways, these bugs will impact whether ` + "`" + `chidley` + "`" + ` can create correct structs for your XML
187 | * For _most_ XML with namespaces, the JSON will be OK but if you convert XML to XML using the generated Go code, there will be a chance one of the above mentioned bugs may impact results. Here is an example I encountered: https://groups.google.com/d/msg/golang-nuts/drWStJSt0Pg/Z47JHeij7ToJ
188 |
189 | ## Name
190 | ` + "`" + `chidley` + "`" + ` is named after [Cape Chidley](https://en.wikipedia.org/wiki/Cape_Chidley), Canada
191 |
192 | ## Larger & more complex example
193 | Using the file ` + "`" + `{{.PubmedXMLFileName}}` + "`" + `. Generated from a query to pubmed (similar but much larger than [http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=20598978,444444,455555&retmode=xml](http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=20598978,444444,455555&retmode=xml)), returning a document in the [MEDLINE/Pubmed XML format](http://www.nlm.nih.gov/bsd/licensee/data_elements_doc.html).
194 | * Compressed size: 27M
195 | * Uncompressed size: 337M
196 |
197 | ### Generate Go structs from {{.PubmedXMLFileName}}: ` + "`" + `-G` + "`" + `
198 |
199 | ` + "`" + `` + "`" + `` + "`" + `
200 |
201 | {{.PubmedExampleXMLChidleyGoStructsWithTypes}}
202 |
203 | ` + "`" + `` + "`" + `` + "`" + `
204 | ####Run times
205 | $ /usr/bin/time -f "%E %M" ./chidley -G xml/pubmed_xml_12750255.xml.bz2
206 | {{.PubmedExampleXMLChidleyGoStructsWithTypeTiming}}
207 |
208 | *Note:* All timings from Dell laptop 16GB, regular disk, 8 core i7-3720QM CPU @ 2.60GHz)
209 | ` + "`" + `Linux 3.11.10-100.fc18.x86_64 #1 SMP Mon Dec 2 20:28:38 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux` + "`" + `
210 |
211 |
212 |
213 | ### Generate Go program: ` + "`" + `-W` + "`" + `
214 |
215 | ` + "`" + `` + "`" + `` + "`" + `
216 | $ ./chidley -W xml/pubmed_xml_12750255.xml.bz2 > examples/pubmed/ChiPubmed.go
217 | $ cd examples/pubmed/
218 | $ go build
219 | $
220 | ` + "`" + `` + "`" + `` + "`" + `
221 |
222 | #### Generated program: count tags
223 | ` + "`" + `` + "`" + `` + "`" + `
224 | $ /usr/bin/time -f "%E %M" ./pubmed -c | sort -n
225 | 0:36.58 10460
226 | {{.GeneratedPubmedCount}}
227 |
228 | 12121212
229 |
230 | $
231 | ` + "`" + `` + "`" + `` + "`" + `
232 |
233 | *Note:* The underscore before the colon indicates there is no (or the default) namespace for the element.
234 |
235 | 36 seconds for 337MB XML; resident size: 10.5MB
236 |
237 | #### Generated program: convert XML to JSON
238 |
239 | ##### No streaming
240 | ` + "`" + `` + "`" + `` + "`" + `
241 | $ /usr/bin/time -f "%E %M" ./pubmed -j > /dev/null
242 | {{.GeneratedPubmedNoStreaming}}
243 | 0:57.26 2866408
244 | $
245 | ` + "`" + `` + "`" + `` + "`" + `
246 | 57 seconds for 337MB XML; resident size: 2.9GB
247 |
248 | ##### With streaming ` + "`" + `-s` + "`" + `
249 | Streaming decodes using the XML elements that are one level down from the top level container element.
250 | ` + "`" + `` + "`" + `` + "`" + `
251 | {{.GeneratedPubmedStreaming}}
252 | $ /usr/bin/time -f "%E %M" ./pubmed -j -s > /dev/null
253 | 0:58.72 15944
254 | ` + "`" + `` + "`" + `` + "`" + `
255 | 59 seconds for 337MB XML; resident size: 16MB
256 |
257 | ##### Sample of generated JSON
258 | ` + "`" + `` + "`" + `` + "`" + `
259 | $ /usr/bin/time -f "%E %M" ./pubmed -j -s |head -310
260 | {{.GeneratedPubmedXMLToJson}}
261 | {
262 | "MedlineCitation": {
263 | "Attr_Owner": "NLM",
264 | "Attr_Status": "MEDLINE",
265 | "Article": {
266 | "Attr_PubModel": "Print",
267 | "Abstract": {
268 | "AbstractText": [
269 | {
270 | "Text": "A review on the operative methods for prophylaxis of urological complications (fistulas and strictures) due to radical hysterectomy with systemic dissection of lymph nodes is described. The authors recommend the method of T. H. Green as the most effective method. A new method for protection of the ureter with flaps, formed as a \"leg\" from omentum majus, is proposed. The modification has been used in 20 patients without postoperative complications. The method is recommended in cases, when postoperative stenosis or strictures of the ureters are expected as well as when postoperative irradiation is forthcoming."
271 | }
272 | ]
273 | },
274 | "ArticleTitle": {
275 | "Text": "[A method for preventing the urologic complications connected with the surgical treatment of cancer of the cervix uteri]."
276 | },
277 | "AuthorList": [
278 | {
279 | "Attr_CompleteYN": "Y",
280 | "Author": [
281 | {
282 | "Attr_ValidYN": "Y",
283 | "ForeName": {
284 | "Text": "T"
285 | },
286 | "Initials": {
287 | "Text": "T"
288 | },
289 | "LastName": {
290 | "Text": "Kŭrlov"
291 | }
292 | },
293 | {
294 | "Attr_ValidYN": "Y",
295 | "ForeName": {
296 | "Text": "N"
297 | },
298 | "Initials": {
299 | "Text": "N"
300 | },
301 | "LastName": {
302 | "Text": "Vasilev"
303 | }
304 | }
305 | ]
306 | }
307 | ],
308 | "Journal": {
309 | "ISOAbbreviation": {
310 | "Text": "Akush Ginekol (Sofiia)"
311 | },
312 | "ISSN": {
313 | "Attr_IssnType": "Print",
314 | "Text": "0324-0959"
315 | },
316 | "JournalIssue": {
317 | "Attr_CitedMedium": "Print",
318 | "Issue": {
319 | "Text": "1"
320 | },
321 | "PubDate": {
322 | "Year": {
323 | "Text": "1990"
324 | }
325 | },
326 | "Volume": {
327 | "Text": "29"
328 | }
329 | },
330 | "Title": {
331 | "Text": "Akusherstvo i ginekologii͡a"
332 | }
333 | },
334 | "Language": [
335 | {
336 | "Text": "bul"
337 | }
338 | ],
339 | "Pagination": {
340 | "MedlinePgn": {
341 | "Text": "55-7"
342 | }
343 | },
344 | "PublicationTypeList": {
345 | "PublicationType": [
346 | {
347 | "Text": "English Abstract"
348 | },
349 | {
350 | "Text": "Journal Article"
351 | }
352 | ]
353 | },
354 | "VernacularTitle": {
355 | "Text": "Metod za profilaktika na urologichnite uslozhneniia, svŭrzani s operativnoto lechenie na raka na matochnata shiĭka."
356 | }
357 | },
358 | "CitationSubset": [
359 | {
360 | "Text": "IM"
361 | }
362 | ],
363 | "DateCompleted": {
364 | "Day": {
365 | "Text": "22"
366 | },
367 | "Month": {
368 | "Text": "08"
369 | },
370 | "Year": {
371 | "Text": "1990"
372 | }
373 | },
374 | "DateCreated": {
375 | "Day": {
376 | "Text": "22"
377 | },
378 | "Month": {
379 | "Text": "08"
380 | },
381 | "Year": {
382 | "Text": "1990"
383 | }
384 | },
385 | "DateRevised": {
386 | "Day": {
387 | "Text": "15"
388 | },
389 | "Month": {
390 | "Text": "11"
391 | },
392 | "Year": {
393 | "Text": "2006"
394 | }
395 | },
396 | "MedlineJournalInfo": {
397 | "Country": {
398 | "Text": "BULGARIA"
399 | },
400 | "ISSNLinking": {
401 | "Text": "0324-0959"
402 | },
403 | "MedlineTA": {
404 | "Text": "Akush Ginekol (Sofiia)"
405 | },
406 | "NlmUniqueID": {
407 | "Text": "0370455"
408 | }
409 | },
410 | "MeshHeadingList": {
411 | "MeshHeading": [
412 | {
413 | "DescriptorName": {
414 | "Attr_MajorTopicYN": "N",
415 | "Text": "Female"
416 | }
417 | },
418 | {
419 | "DescriptorName": {
420 | "Attr_MajorTopicYN": "N",
421 | "Text": "Humans"
422 | }
423 | },
424 | {
425 | "DescriptorName": {
426 | "Attr_MajorTopicYN": "N",
427 | "Text": "Hysterectomy"
428 | },
429 | "QualifierName": [
430 | {
431 | "Attr_MajorTopicYN": "N",
432 | "Text": "methods"
433 | }
434 | ]
435 | },
436 | {
437 | "DescriptorName": {
438 | "Attr_MajorTopicYN": "N",
439 | "Text": "Lymph Node Excision"
440 | },
441 | "QualifierName": [
442 | {
443 | "Attr_MajorTopicYN": "N",
444 | "Text": "methods"
445 | }
446 | ]
447 | },
448 | {
449 | "DescriptorName": {
450 | "Attr_MajorTopicYN": "N",
451 | "Text": "Postoperative Complications"
452 | },
453 | "QualifierName": [
454 | {
455 | "Attr_MajorTopicYN": "N",
456 | "Text": "etiology"
457 | },
458 | {
459 | "Attr_MajorTopicYN": "Y",
460 | "Text": "prevention \u0026 control"
461 | }
462 | ]
463 | },
464 | {
465 | "DescriptorName": {
466 | "Attr_MajorTopicYN": "N",
467 | "Text": "Urologic Diseases"
468 | },
469 | "QualifierName": [
470 | {
471 | "Attr_MajorTopicYN": "N",
472 | "Text": "etiology"
473 | },
474 | {
475 | "Attr_MajorTopicYN": "Y",
476 | "Text": "prevention \u0026 control"
477 | }
478 | ]
479 | },
480 | {
481 | "DescriptorName": {
482 | "Attr_MajorTopicYN": "N",
483 | "Text": "Uterine Cervical Neoplasms"
484 | },
485 | "QualifierName": [
486 | {
487 | "Attr_MajorTopicYN": "N",
488 | "Text": "complications"
489 | },
490 | {
491 | "Attr_MajorTopicYN": "Y",
492 | "Text": "surgery"
493 | }
494 | ]
495 | }
496 | ]
497 | },
498 | "PMID": {
499 | "Attr_Version": "1",
500 | "Text": "2372101"
501 | }
502 | },
503 | "PubmedData": {
504 | "ArticleIdList": {
505 | "ArticleId": [
506 | {
507 | "Attr_IdType": "pubmed",
508 | "Text": "2372101"
509 | }
510 | ]
511 | },
512 | "History": {
513 | "PubMedPubDate": [
514 | {
515 | "Attr_PubStatus": "pubmed",
516 | "Day": {
517 | "Text": "1"
518 | },
519 | "Month": {
520 | "Text": "1"
521 | },
522 | "Year": {
523 | "Text": "1990"
524 | }
525 | },
526 | {
527 | "Attr_PubStatus": "medline",
528 | "Day": {
529 | "Text": "1"
530 | },
531 | "Hour": {
532 | "Text": "0"
533 | },
534 | "Minute": {
535 | "Text": "1"
536 | },
537 | "Month": {
538 | "Text": "1"
539 | },
540 | "Year": {
541 | "Text": "1990"
542 | }
543 | },
544 | {
545 | "Attr_PubStatus": "entrez",
546 | "Day": {
547 | "Text": "1"
548 | },
549 | "Hour": {
550 | "Text": "0"
551 | },
552 | "Minute": {
553 | "Text": "0"
554 | },
555 | "Month": {
556 | "Text": "1"
557 | },
558 | "Year": {
559 | "Text": "1990"
560 | }
561 | }
562 | ]
563 | },
564 | "PublicationStatus": {
565 | "Text": "ppublish"
566 | }
567 | }
568 | }
569 | {
570 | "MedlineCitation": {
571 | ` + "`" + `` + "`" + `` + "`" + `
572 |
573 | ##### Sample of generated XML to XML
574 | ` + "`" + `` + "`" + `` + "`" + `
575 | $ ./pubmed -x -s |head -100
576 | {{.GeneratedPubmedXMLToXML}}
577 |
578 |
579 |
580 |
581 | A review on the operative methods for prophylaxis of urological complications (fistulas and strictures) due to radical hysterectomy with systemic dissection of lymph nodes is described. The authors recommend the method of T. H. Green as the most effective method. A new method for protection of the ureter with flaps, formed as a "leg" from omentum majus, is proposed. The modification has been used in 20 patients without postoperative complications. The method is recommended in cases, when postoperative stenosis or strictures of the ureters are expected as well as when postoperative irradiation is forthcoming.
582 |
583 | [A method for preventing the urologic complications connected with the surgical treatment of cancer of the cervix uteri].
584 |
585 |
586 | T
587 | T
588 | Kŭrlov
589 |
590 |
591 | N
592 | N
593 | Vasilev
594 |
595 |
596 |
597 | Akush Ginekol (Sofiia)
598 | 0324-0959
599 |
600 | 1
601 |
602 | 1990
603 |
604 | 29
605 |
606 | Akusherstvo i ginekologii͡a
607 |
608 | bul
609 |
610 | 55-7
611 |
612 |
613 | English Abstract
614 | Journal Article
615 |
616 | Metod za profilaktika na urologichnite uslozhneniia, svŭrzani s operativnoto lechenie na raka na matochnata shiĭka.
617 |
618 | IM
619 |
620 | 22
621 | 08
622 | 1990
623 |
624 |
625 | 22
626 | 08
627 | 1990
628 |
629 |
630 | 15
631 | 11
632 | 2006
633 |
634 |
635 | BULGARIA
636 | 0324-0959
637 | Akush Ginekol (Sofiia)
638 | 0370455
639 |
640 |
641 |
642 | Female
643 |
644 |
645 | Humans
646 |
647 |
648 | Hysterectomy
649 | methods
650 |
651 |
652 | Lymph Node Excision
653 | methods
654 |
655 |
656 | Postoperative Complications
657 | etiology
658 | prevention & control
659 |
660 |
661 | Urologic Diseases
662 | etiology
663 | prevention & control
664 |
665 |
666 | Uterine Cervical Neoplasms
667 | complications
668 | surgery
669 |
670 |
671 | 2372101
672 |
673 |
674 |
675 | 2372101
676 |
677 | ` + "`" + `` + "`" + `` + "`" + `
678 |
679 | ## Java/JAXB
680 | ` + "`" + `chidley` + "`" + ` now supports the production of Java/JAXB code. It generates a class-per-element, with classes mapping to the Go structs generated by the XML extraction.
681 | Its only dependency is Google [Gson](https://code.google.com/p/google-gson/), for JSON generation.
682 |
683 |
684 | ### Usage
685 | ` + "`" + `chidley` + "`" + ` creates a maven project in ` + "`" + `./java` + "`" + ` (settable using the ` + "`" + `-D` + "`" + ` flag) and creates Java JAXB files in ` + "`" + `src/main/java/ca/gnewton/chidley/jaxb/xml` + "`" + `.
686 | It creates a ` + "`" + `Main.java` + "`" + ` in ` + "`" + `src/main/java/ca/gnewton/chidley/jaxb` + "`" + `
687 | ` + "`" + `` + "`" + `` + "`" + `
688 | $ chidley -J xml/test1.xml
689 | {{.ChidleyGenerateJava}}
690 | 2014/09/02 10:22:27 printJavaJaxbVisitor.go:100: Writing java Class file: java/src/main/java/ca/gnewton/chidley/jaxb/xml/ChiDocs.java
691 | 2014/09/02 10:22:27 printJavaJaxbVisitor.go:100: Writing java Class file: java/src/main/java/ca/gnewton/chidley/jaxb/xml/ChiDoc.java
692 | 2014/09/02 10:22:27 printJavaJaxbVisitor.go:100: Writing java Class file: java/src/main/java/ca/gnewton/chidley/jaxb/xml/ChiTitle.java
693 | 2014/09/02 10:22:27 printJavaJaxbVisitor.go:100: Writing java Class file: java/src/main/java/ca/gnewton/chidley/jaxb/xml/ChiAuthor.java
694 | 2014/09/02 10:22:27 printJavaJaxbVisitor.go:100: Writing java Class file: java/src/main/java/ca/gnewton/chidley/jaxb/xml/ChiLast_name.java
695 | 2014/09/02 10:22:28 printJavaJaxbVisitor.go:100: Writing java Class file: java/src/main/java/ca/gnewton/chidley/jaxb/xml/ChiFirstName.java
696 | 2014/09/02 10:22:28 printJavaJaxbVisitor.go:100: Writing java Class file: java/src/main/java/ca/gnewton/chidley/jaxb/Main.java
697 | ` + "`" + `` + "`" + `` + "`" + `
698 |
699 | ### New
700 | Changing the package with "-P":
701 | ` + "`" + `` + "`" + `` + "`" + `
702 | $ chidley -J -P testFoo xml/test1.xml
703 | {{.ChidleyGenerateJavaChangePackageName}}
704 | 2015/07/24 15:56:52 printJavaJaxbVisitor.go:103: Writing java Class file: java/src/main/java/ca/gnewton/chidley/testFoo/xml/ChiDocs.java
705 | 2015/07/24 15:56:52 printJavaJaxbVisitor.go:103: Writing java Class file: java/src/main/java/ca/gnewton/chidley/testFoo/xml/ChiDoc.java
706 | 2015/07/24 15:56:52 printJavaJaxbVisitor.go:103: Writing java Class file: java/src/main/java/ca/gnewton/chidley/testFoo/xml/ChiTitle.java
707 | 2015/07/24 15:56:52 printJavaJaxbVisitor.go:103: Writing java Class file: java/src/main/java/ca/gnewton/chidley/testFoo/xml/ChiAuthor.java
708 | 2015/07/24 15:56:52 printJavaJaxbVisitor.go:103: Writing java Class file: java/src/main/java/ca/gnewton/chidley/testFoo/xml/ChiLast_name.java
709 | 2015/07/24 15:56:52 printJavaJaxbVisitor.go:103: Writing java Class file: java/src/main/java/ca/gnewton/chidley/testFoo/xml/ChiFirstName.java
710 | 2015/07/24 15:56:52 printJavaJaxbVisitor.go:103: Writing java Class file: java/src/main/java/ca/gnewton/chidley/testFoo/Main.java
711 | $
712 | ` + "`" + `` + "`" + `` + "`" + `
713 |
714 | #### Build Java package
715 | ` + "`" + `` + "`" + `` + "`" + `
716 | $ cd java
717 | $ ls
718 | pom.xml src
719 | $ $ mvn package
720 | {{.ChidleyGenerateJavaMavenBuild}}
721 | [INFO] Scanning for projects...
722 | [INFO]
723 | [INFO] ------------------------------------------------------------------------
724 | [INFO] Building chidley-jaxb 1.0-SNAPSHOT
725 | [INFO] ------------------------------------------------------------------------
726 | [INFO]
727 | [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ chidley-jaxb ---
728 | [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
729 | [INFO] skip non existing resourceDirectory /home/newtong/work/chidley/java/src/main/resources
730 | [INFO]
731 | [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ chidley-jaxb ---
732 | [WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
733 | [INFO] Compiling 7 source files to /home/newtong/work/chidley/java/target/classes
734 | [INFO]
735 | [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ chidley-jaxb ---
736 | [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
737 | [INFO] skip non existing resourceDirectory /home/newtong/work/chidley/java/src/test/resources
738 | [INFO]
739 | [INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ chidley-jaxb ---
740 | [INFO] No sources to compile
741 | [INFO]
742 | [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ chidley-jaxb ---
743 | [INFO] No tests to run.
744 | [INFO]
745 | [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ chidley-jaxb ---
746 | [INFO] Building jar: /home/newtong/work/chidley/java/target/chidley-jaxb-1.0-SNAPSHOT.jar
747 | [INFO] ------------------------------------------------------------------------
748 | [INFO] BUILD SUCCESS
749 | [INFO] ------------------------------------------------------------------------
750 | [INFO] Total time: 3.514s
751 | [INFO] Finished at: Tue Sep 02 10:29:18 EDT 2014
752 | [INFO] Final Memory: 11M/240M
753 | [INFO] ------------------------------------------------------------------------
754 | $
755 | ` + "`" + `` + "`" + `` + "`" + `
756 |
757 | #### Running
758 | ` + "`" + `` + "`" + `` + "`" + `
759 | $ export CLASSPATH=./target/chidley-jaxb-1.0-SNAPSHOT.jar:/home/myhome/.m2/repository/com/google/code/gson/gson/2.3/gson-2.3.jar:$CLASSPATH
760 | $ java ca.gnewton.chidley.jaxb.Main
761 | zzzzzz {{.ChidleyGenerateJavaRun}} mmmmm
762 | {
763 | "language": "eng",
764 | "doc": [
765 | {
766 | "type": "book",
767 | "title": {
768 | "tagValue": "Dune"
769 | },
770 | "author": {
771 | "last-name": {
772 | "tagValue": "Herbert"
773 | },
774 | "firstName": {
775 | "tagValue": "Frank"
776 | }
777 | }
778 | },
779 | {
780 | "type": "article",
781 | "title": {
782 | "tagValue": "Brave New Wold"
783 | },
784 | "author": {
785 | "last-name": {
786 | "tagValue": "Huxley"
787 | },
788 | "firstName": {
789 | "tagValue": "Aldous"
790 | }
791 | }
792 | }
793 | ]
794 | }
795 | $
796 | ` + "`" + `` + "`" + `` + "`" + `
797 |
798 | ### Limitations
799 | - Can handle vanilla XML (no namespaces) OK
800 | - Can handle top level namespaces OK
801 | ` + "`" + `` + "`" + `` + "`" + `
802 |
803 |
807 |
808 | A book entry
809 |
810 |
811 | A article entry
812 |
813 | n
814 | ` + "`" + `` + "`" + `` + "`" + `
815 | - *Cannot* handle element- or attribute-level namespaces (*soon*), like:
816 | ` + "`" + `` + "`" + `` + "`" + `
817 |
818 |
819 | number one
820 | number two
821 |
822 | ` + "`" + `` + "`" + `` + "`" + `
823 | - *Cannot* read ` + "`" + `gz` + "`" + ` or ` + "`" + `bz2` + "`" + ` compressed XML (soon)
824 | - *Cannot* do [XML streaming](https://stackoverflow.com/questions/1134189/can-jaxb-parse-large-xml-files-in-chunks) (thus limited to smaller XML files) (perhaps soon?)
825 |
826 |
827 | Copyright 2014,2015,2016 Glen Newton
828 | `
829 |
--------------------------------------------------------------------------------
/makereadme/util.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "os/exec"
6 | )
7 |
8 | func runDiscardOutput(dir string, name string, arg ...string) error {
9 |
10 | //err, stderr, stdout := run(cmd, false, false, false)
11 | _, _, err := run(false, false, false, dir, name, arg...)
12 | return err
13 | }
14 |
15 | func run(stderr, stdout, seperate bool, dir, name string, arg ...string) (string, string, error) {
16 | //cmd, err := exec.Command(name, arg...).Output()
17 | //if dir != "" {
18 | //cmd.Dir = dir
19 | //}
20 | //err := cmd.Run()
21 | //log.Println("--------------", cmd.ProcessState)
22 |
23 | //str, _ := cmd.Output()
24 |
25 | //return string(cmd), "", err
26 |
27 | //cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
28 |
29 | cmd := exec.Command(name, arg...)
30 | if dir != "" {
31 | cmd.Dir = dir
32 | }
33 | stdoutStderr, err := cmd.CombinedOutput()
34 | if err != nil {
35 | log.Println("Error running:", name, arg)
36 | log.Println(err)
37 | return "", "", err
38 | }
39 | return string(stdoutStderr), "", err
40 | }
41 |
42 | func runCaptureStdout(dir string, name string, arg ...string) (string, error) {
43 | stdout, _, err := run(true, false, false, dir, name, arg...)
44 | return stdout, err
45 | }
46 |
47 | func runCaptureStderr(dir string, name string, arg ...string) (string, error) {
48 | _, stderr, err := run(false, true, false, dir, name, arg...)
49 | return stderr, err
50 | }
51 |
52 | // cmd := exec.Command("myCommand", "arg1", "arg2")
53 | // cmd.Dir = "/path/to/work/dir"
54 | // cmd.Run()
55 |
56 | func runCaptureAll(dir string, name string, arg ...string) (string, string, error) {
57 | stdout, stderr, err := run(true, true, false, dir, name, arg...)
58 | return stdout, stderr, err
59 | }
60 |
--------------------------------------------------------------------------------
/mvnTemplate.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | type JaxbMavenPomInfo struct {
4 | AppName string
5 | }
6 |
7 | const mavenPomTemplate = `
8 |
10 | 4.0.0
11 | ca.gnewton.chidley.{{.AppName}}
12 | {{.AppName}}
13 | jar
14 | 1.0-SNAPSHOT
15 | {{.AppName}}
16 | http://maven.apache.org
17 |
18 |
19 | junit
20 | junit
21 | 3.8.1
22 | test
23 |
24 |
25 | com.google.code.gson
26 | gson
27 | 2.3
28 | compile
29 |
30 |
31 |
32 | `
33 |
--------------------------------------------------------------------------------
/node.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "strings"
5 | //"log"
6 | )
7 |
8 | type Node struct {
9 | name string
10 | space string
11 | spaceTag string
12 | parent *Node
13 | parents []*Node
14 | children map[string]*Node
15 | childCount map[string]int
16 | repeats bool
17 | nodeTypeInfo *NodeTypeInfo
18 | hasCharData bool
19 | tempCharData string
20 | charDataCount int64
21 | discoveredOrder int
22 | ignoredTag bool
23 | }
24 |
25 | type NodeVisitor interface {
26 | Visit(n *Node) bool
27 | AlreadyVisited(n *Node) bool
28 | SetAlreadyVisited(n *Node)
29 | }
30 |
31 | func (n *Node) initialize(name string, space string, spaceTag string, parent *Node) {
32 | n.parent = parent
33 | n.parents = make([]*Node, 0, 0)
34 | n.pushParent(parent)
35 | n.name = name
36 | n.space = space
37 | n.spaceTag = spaceTag
38 | n.children = make(map[string]*Node)
39 | n.childCount = make(map[string]int)
40 | n.nodeTypeInfo = new(NodeTypeInfo)
41 | n.nodeTypeInfo.initialize()
42 | n.hasCharData = false
43 | n.ignoredTag = false
44 | }
45 |
46 | func (n *Node) makeName() string {
47 | spaceTag := ""
48 | if n.spaceTag != "" {
49 | spaceTag = "_" + n.spaceTag
50 | }
51 | //return capitalizeFirstLetter(cleanName(n.name)) + spaceTag
52 | return cleanName(n.name) + spaceTag
53 | }
54 |
55 | func (n *Node) makeType(prefix string, suffix string) string {
56 | return goVariableNameSanitize(capitalizeFirstLetter(makeTypeGeneric(n.name, n.spaceTag, prefix, suffix, !keepXmlFirstLetterCase)) + n.renderSpaceTag())
57 | }
58 |
59 | func (n *Node) renderSpaceTag() string {
60 | if len(strings.TrimSpace(n.spaceTag)) == 0 {
61 | return ""
62 | } else {
63 | return "__" + n.spaceTag
64 | }
65 | }
66 |
67 | func (n *Node) makeJavaType(prefix string, suffix string) string {
68 | return capitalizeFirstLetter(makeTypeGeneric(n.name, n.spaceTag, prefix, suffix, !keepXmlFirstLetterCase))
69 | }
70 |
71 | func (n *Node) peekParent() *Node {
72 | if len(n.parents) == 0 {
73 | return nil
74 | }
75 | a := n.parents
76 | return a[len(a)-1]
77 | }
78 |
79 | func (n *Node) pushParent(parent *Node) {
80 | n.parents = append(n.parents, parent)
81 | }
82 |
83 | func (n *Node) popParent() *Node {
84 | if len(n.parents) == 0 {
85 | return nil
86 | }
87 | var poppedNode *Node
88 | a := n.parents
89 | poppedNode, n.parents = a[len(a)-1], a[:len(a)-1]
90 | return poppedNode
91 | }
92 |
93 | func makeTypeGeneric(name string, space string, prefix string, suffix string, capitalizeName bool) string {
94 | spaceTag := ""
95 |
96 | if capitalizeName {
97 | name = capitalizeFirstLetter(name)
98 | }
99 |
100 | return prefix + spaceTag + cleanName(name) + suffix
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/nodeTypeInfo.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 | )
7 |
8 | type NodeTypeInfo struct {
9 | alwaysBool bool
10 | alwaysFloat32 bool
11 | alwaysFloat64 bool
12 |
13 | alwaysInt0 bool
14 | alwaysInt08 bool
15 | alwaysInt16 bool
16 | alwaysInt32 bool
17 | alwaysInt64 bool
18 |
19 | alwaysUint08 bool
20 | alwaysUint16 bool
21 | alwaysUint32 bool
22 | alwaysUint64 bool
23 | maxLength int64
24 | }
25 |
26 | func (nti *NodeTypeInfo) initialize() {
27 | nti.alwaysBool = true
28 | nti.alwaysFloat32 = true
29 | nti.alwaysFloat64 = true
30 |
31 | nti.alwaysInt0 = true
32 | nti.alwaysInt08 = true
33 | nti.alwaysInt16 = true
34 | nti.alwaysInt32 = true
35 | nti.alwaysInt64 = true
36 |
37 | nti.alwaysUint08 = true
38 | nti.alwaysUint16 = true
39 | nti.alwaysUint32 = true
40 | nti.alwaysUint64 = true
41 | nti.maxLength = 0
42 | }
43 |
44 | func (n *NodeTypeInfo) addFieldLength(l int64) {
45 | if n.maxLength < l {
46 | n.maxLength = l
47 | }
48 | }
49 |
50 | func (n *NodeTypeInfo) checkFieldType(v string) {
51 | v = strings.TrimSpace(v)
52 |
53 | if _, err := strconv.ParseBool(v); err != nil {
54 | n.alwaysBool = false
55 | }
56 |
57 | if _, err := strconv.ParseFloat(v, 32); err != nil {
58 | n.alwaysFloat32 = false
59 | }
60 |
61 | if _, err := strconv.ParseFloat(v, 64); err != nil {
62 | n.alwaysFloat64 = false
63 | }
64 |
65 | if _, err := strconv.ParseInt(v, 10, 0); err != nil {
66 | n.alwaysInt0 = false
67 | }
68 |
69 | if _, err := strconv.ParseInt(v, 10, 8); err != nil {
70 | n.alwaysInt08 = false
71 | }
72 |
73 | if _, err := strconv.ParseInt(v, 10, 16); err != nil {
74 | n.alwaysInt16 = false
75 | }
76 |
77 | if _, err := strconv.ParseInt(v, 10, 32); err != nil {
78 | n.alwaysInt32 = false
79 | }
80 |
81 | if _, err := strconv.ParseInt(v, 10, 64); err != nil {
82 | n.alwaysInt64 = false
83 | }
84 |
85 | if _, err := strconv.ParseUint(v, 10, 8); err != nil {
86 | n.alwaysUint08 = false
87 | }
88 |
89 | if _, err := strconv.ParseUint(v, 10, 16); err != nil {
90 | n.alwaysUint16 = false
91 | }
92 |
93 | if _, err := strconv.ParseUint(v, 10, 32); err != nil {
94 | n.alwaysUint32 = false
95 | }
96 |
97 | if _, err := strconv.ParseUint(v, 10, 64); err != nil {
98 | n.alwaysUint64 = false
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/printGoStructVisitor.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "sort"
7 | //"strconv"
8 | )
9 |
10 | type PrintGoStructVisitor struct {
11 | alreadyVisited map[string]bool
12 | alreadyVisitedNodes map[string]*Node
13 | globalTagAttributes map[string]([]*FQN)
14 |
15 | maxDepth int
16 | depth int
17 | nameSpaceTagMap map[string]string
18 | useType bool
19 | nameSpaceInJsonName bool
20 | writer io.Writer
21 | }
22 |
23 | func (v *PrintGoStructVisitor) init(writer io.Writer, maxDepth int, globalTagAttributes map[string]([]*FQN), nameSpaceTagMap map[string]string, useType bool, nameSpaceInJsonName bool) {
24 | v.alreadyVisited = make(map[string]bool)
25 | v.alreadyVisitedNodes = make(map[string]*Node)
26 | v.globalTagAttributes = make(map[string]([]*FQN))
27 | v.globalTagAttributes = globalTagAttributes
28 | v.writer = writer
29 | v.maxDepth = maxDepth
30 | v.depth = 0
31 | v.nameSpaceTagMap = nameSpaceTagMap
32 | v.useType = useType
33 | v.nameSpaceInJsonName = nameSpaceInJsonName
34 | }
35 |
36 | func (v *PrintGoStructVisitor) Visit(node *Node) bool {
37 |
38 | v.depth += 1
39 |
40 | if v.AlreadyVisited(node) || node.ignoredTag {
41 | v.depth += 1
42 | return false
43 | }
44 | v.SetAlreadyVisited(node)
45 |
46 | for _, child := range node.children {
47 | v.Visit(child)
48 | }
49 | v.depth += 1
50 | return true
51 | }
52 |
53 | func print(v *PrintGoStructVisitor, node *Node) error {
54 | if node.ignoredTag || node.name == "" {
55 | return nil
56 | }
57 | if flattenStrings && isStringOnlyField(node, len(v.globalTagAttributes[nk(node)])) {
58 | //v.lineChannel <- "//type " + node.makeType(namePrefix, nameSuffix)
59 | return nil
60 | }
61 |
62 | attributes := v.globalTagAttributes[nk(node)]
63 | //v.lineChannel <- "type " + node.makeType(namePrefix, nameSuffix) + " struct {"
64 | fmt.Fprintln(v.writer, "type "+node.makeType(namePrefix, nameSuffix)+" struct {")
65 |
66 | // fmt.Fprintln(v.writer, "\tXMLName xml.Name`"+makeXmlAnnotation(node.space, false, node.name)+" "+makeJsonAnnotation(node.spaceTag, false, node.name)+"`")
67 |
68 | fmt.Fprintln(v.writer, "\tXMLName xml.Name `"+makeAnnotation("xml", node.space, false, false, node.name)+" "+makeJsonAnnotation(node.spaceTag, false, node.name)+"`")
69 |
70 | //return makeAnnotation("xml", spaceTag, true, false, name)
71 |
72 | makeAttributes(v.writer, attributes, v.nameSpaceTagMap)
73 |
74 | err := v.printInternalFields(len(attributes), node)
75 | if err != nil {
76 | return err
77 | }
78 |
79 | //v.lineChannel <- "}\n"
80 | fmt.Fprintln(v.writer, "}")
81 | fmt.Fprintln(v.writer, "")
82 |
83 | return nil
84 | }
85 |
86 | func (v *PrintGoStructVisitor) AlreadyVisited(n *Node) bool {
87 | _, ok := v.alreadyVisited[nk(n)]
88 | return ok
89 | }
90 |
91 | func (v *PrintGoStructVisitor) SetAlreadyVisited(n *Node) {
92 | v.alreadyVisited[nk(n)] = true
93 | v.alreadyVisitedNodes[nk(n)] = n
94 | }
95 |
96 | func (v *PrintGoStructVisitor) printInternalFields(nattributes int, n *Node) error {
97 | var fields []string
98 |
99 | // Fields in this struct
100 | for i, _ := range n.children {
101 | child := n.children[i]
102 | if child.ignoredTag {
103 | continue
104 | }
105 | var def FieldDef
106 | if flattenStrings && isStringOnlyField(child, len(v.globalTagAttributes[nk(child)])) {
107 | //field = "\t" + child.spaceTag + child.makeType(namePrefix, nameSuffix) + " string `" + makeXmlAnnotation(child.space, false, child.name) + "`" //+ " // ********* " + lengthTagName + ":\"" + lengthTagAttribute + lengthTagSeparator + strconv.FormatInt(child.nodeTypeInfo.maxLength+lengthTagPadding, 10) + "\""
108 | def.GoName = child.makeType(namePrefix, nameSuffix)
109 | //def.GoType = "string"
110 | def.GoType = findType(child.nodeTypeInfo, useType)
111 | def.XMLName = child.name
112 | def.XMLNameSpace = child.space
113 | } else {
114 |
115 | // Field name and type are the same: i.e. Person *Person or Persons []Persons
116 | nameAndType := child.makeType(namePrefix, nameSuffix)
117 |
118 | def.GoName = nameAndType
119 | def.GoType = nameAndType
120 | def.XMLName = child.name
121 | def.XMLNameSpace = child.space
122 |
123 | if child.repeats {
124 | def.GoTypeArrayOrPointer = "[]*"
125 | } else {
126 | def.GoTypeArrayOrPointer = "*"
127 | }
128 | }
129 | if flattenStrings {
130 | def.Length = child.nodeTypeInfo.maxLength
131 | }
132 | fieldDefString, err := render(def)
133 | if err != nil {
134 | return err
135 | }
136 | fields = append(fields, fieldDefString)
137 | }
138 |
139 | // Is this chardata Field (string)
140 | if n.hasCharData {
141 | xmlString := " `xml:\",chardata\" " + makeJsonAnnotation("", false, "") + "`"
142 | thisType := findType(n.nodeTypeInfo, useType)
143 | thisVariableName := findFieldNameFromTypeInfo(thisType)
144 |
145 | charField := "\t" + thisVariableName + " " + thisType + xmlString
146 |
147 | if flattenStrings {
148 | //charField += "// maxLength=" + strconv.FormatInt(n.nodeTypeInfo.maxLength, 10)
149 | if len(n.children) == 0 && nattributes == 0 {
150 | charField += "// *******************"
151 | }
152 | }
153 | //GOOD
154 | //charField += " // maxLength=" + strconv.FormatInt(n.nodeTypeInfo.maxLength, 10)
155 |
156 | fields = append(fields, charField)
157 | }
158 |
159 | sort.Strings(fields)
160 | for i := 0; i < len(fields); i++ {
161 | //v.lineChannel <- fields[i]
162 | fmt.Fprintln(v.writer, fields[i])
163 | }
164 | return nil
165 | }
166 |
167 | func makeJsonAnnotation(spaceTag string, useSpaceTagInName bool, name string) string {
168 | return makeAnnotation("json", spaceTag, false, useSpaceTagInName, name)
169 | }
170 |
171 | func makeXmlAnnotation(spaceTag string, useSpaceTag bool, name string) string {
172 | return makeAnnotation("xml", spaceTag, true, false, name)
173 | }
174 |
175 | func makeDbAnnotation(spaceTag string, useSpaceTag bool, name string) string {
176 | return makeAnnotation("db", spaceTag, true, false, name)
177 | }
178 |
179 | func makeAnnotation(annotationId string, spaceTag string, useSpaceTag bool, useSpaceTagInName bool, name string) (annotation string) {
180 | annotation = annotationId + ":\""
181 |
182 | if useSpaceTag {
183 | annotation = annotation + spaceTag
184 | annotation = annotation + " "
185 | }
186 |
187 | if useSpaceTagInName {
188 | if spaceTag != "" {
189 | annotation = annotation + spaceTag
190 | }
191 | }
192 |
193 | annotation = annotation + name + ",omitempty\""
194 |
195 | return annotation
196 | }
197 |
--------------------------------------------------------------------------------
/printJavaJaxbVisitor.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "io"
6 | "log"
7 | "os"
8 | "text/template"
9 | "time"
10 | )
11 |
12 | type PrintJavaJaxbVisitor struct {
13 | alreadyVisited map[string]bool
14 | globalTagAttributes map[string]([]*FQN)
15 | nameSpaceTagMap map[string]string
16 | useType bool
17 | javaDir string
18 | javaPackage string
19 | namePrefix string
20 | Date time.Time
21 | }
22 |
23 | func (v *PrintJavaJaxbVisitor) Visit(node *Node) bool {
24 | if v.AlreadyVisited(node) {
25 | return false
26 | }
27 | v.SetAlreadyVisited(node)
28 |
29 | attributes := v.globalTagAttributes[nk(node)]
30 |
31 | class := new(JaxbClassInfo)
32 | class.init()
33 | class.Date = v.Date
34 | class.PackageName = v.javaPackage
35 | class.ClassName = v.namePrefix + cleanName(capitalizeFirstLetter(node.name))
36 | class.HasValue = node.hasCharData
37 | class.ValueType = findJavaType(node.nodeTypeInfo, v.useType)
38 | class.Name = node.name
39 |
40 | for _, fqn := range attributes {
41 | jat := new(JaxbAttribute)
42 | cleanName := cleanName(fqn.name)
43 | jat.Name = fqn.name
44 | jat.NameUpper = capitalizeFirstLetter(cleanName)
45 | if v.namePrefix != "" {
46 | jat.NameLower = lowerFirstLetter(v.namePrefix) + capitalizeFirstLetter(cleanName)
47 | } else {
48 | jat.NameLower = lowerFirstLetter(cleanName)
49 | }
50 | jat.NameSpace = fqn.space
51 | class.Attributes = append(class.Attributes, jat)
52 | }
53 |
54 | for _, child := range node.children {
55 | jaf := new(JaxbField)
56 | jaf.Name = child.name
57 | cleanName := cleanName(child.name)
58 | jaf.NameUpper = capitalizeFirstLetter(cleanName)
59 | if v.namePrefix != "" {
60 | jaf.NameLower = lowerFirstLetter(v.namePrefix) + capitalizeFirstLetter(cleanName)
61 | } else {
62 | jaf.NameLower = lowerFirstLetter(cleanName)
63 | }
64 | jaf.NameSpace = child.space
65 | jaf.Repeats = child.repeats
66 | jaf.TypeName = child.makeJavaType(v.namePrefix, "")
67 | class.Fields = append(class.Fields, jaf)
68 |
69 | }
70 |
71 | printJaxbClass(class, v.javaDir+"/xml")
72 |
73 | for _, child := range node.children {
74 | v.Visit(child)
75 | }
76 |
77 | return true
78 | }
79 |
80 | func (v *PrintJavaJaxbVisitor) AlreadyVisited(n *Node) bool {
81 | _, ok := v.alreadyVisited[nk(n)]
82 | return ok
83 | }
84 |
85 | func (v *PrintJavaJaxbVisitor) SetAlreadyVisited(n *Node) {
86 | v.alreadyVisited[nk(n)] = true
87 | }
88 |
89 | func printJaxbClass(class *JaxbClassInfo, dir string) {
90 | t := template.Must(template.New("chidleyJaxbGen").Parse(jaxbClassTemplate))
91 | //err := t.Execute(os.Stdout, jb)
92 | writer, f, err := javaClassWriter(dir, class.PackageName+".xml", class.ClassName)
93 | defer f.Close()
94 | err = t.Execute(writer, class)
95 | if err != nil {
96 | log.Println("executing template:", err)
97 | }
98 | bufio.NewWriter(writer).Flush()
99 | }
100 |
101 | func javaClassWriter(dir string, packageName string, className string) (io.Writer, *os.File, error) {
102 | fullPath := dir + "/" + className + ".java"
103 | log.Print("Writing java Class file: " + fullPath)
104 | fi, err := os.Create(fullPath)
105 | if err != nil {
106 | log.Print("Problem creating file: " + fullPath)
107 | panic(err)
108 | }
109 | return bufio.NewWriter(fi), fi, nil
110 | }
111 |
--------------------------------------------------------------------------------
/source.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "io"
6 | "log"
7 | "net/http"
8 | "os"
9 | )
10 |
11 | type Source interface {
12 | io.Closer
13 | newSource(name string) error
14 | getName() string
15 | getReader() io.Reader
16 | }
17 |
18 | type GenericSource struct {
19 | name string
20 | reader io.Reader
21 | }
22 |
23 | type FileSource struct {
24 | GenericSource
25 | file *os.File
26 | }
27 |
28 | type UrlSource struct {
29 | GenericSource
30 | }
31 |
32 | type StdinSource struct {
33 | GenericSource
34 | }
35 |
36 | //StdInSource impl
37 | func (us *StdinSource) copySource() (Source, error) {
38 | err := new(InternalError)
39 | //error.ErrorString = "copySource not supported"
40 | return nil, err
41 | }
42 |
43 | func (us *StdinSource) getName() string {
44 | return ""
45 | }
46 |
47 | func (us *StdinSource) newSource(name string) error {
48 | us.reader = bufio.NewReader(os.Stdin)
49 | return nil
50 | }
51 |
52 | func (us *StdinSource) Close() error {
53 | return nil
54 | }
55 |
56 | func (us *StdinSource) getReader() io.Reader {
57 | return us.reader
58 | }
59 |
60 | //UrlSource impl
61 | func (us *UrlSource) copySource() (Source, error) {
62 | copy := new(UrlSource)
63 | err := copy.newSource(us.name)
64 | return copy, err
65 | }
66 |
67 | func (us *UrlSource) getName() string {
68 | return us.name
69 | }
70 |
71 | func (us *UrlSource) newSource(name string) error {
72 | us.name = name
73 | var err error
74 |
75 | res, err := http.Get(name)
76 | if err != nil {
77 | log.Fatal(err)
78 | }
79 |
80 | if res.StatusCode != 200 {
81 | log.Fatal("ERROR: bad http status code != 200: ", res.StatusCode, " ", name)
82 | return nil
83 |
84 | }
85 | us.reader = res.Body
86 |
87 | return err
88 | }
89 |
90 | func (us UrlSource) Close() error {
91 | closer, ok := us.reader.(io.Closer)
92 | if ok {
93 | return closer.Close()
94 | }
95 |
96 | return nil
97 | }
98 |
99 | func (us *UrlSource) getReader() io.Reader {
100 | return us.reader
101 | }
102 |
103 | // FileSource impl
104 | func (fs *FileSource) copySource() (Source, error) {
105 | copy := new(FileSource)
106 | err := copy.newSource(fs.name)
107 | return copy, err
108 | }
109 |
110 | func (fs *FileSource) getName() string {
111 | return fs.name
112 | }
113 |
114 | func (fs *FileSource) newSource(name string) error {
115 | fs.name = name
116 | var err error
117 | fs.reader, fs.file, err = genericReader(name)
118 |
119 | return err
120 | }
121 |
122 | func (fs *FileSource) Close() error {
123 | return fs.file.Close()
124 | }
125 |
126 | func (fs FileSource) getReader() io.Reader {
127 | return fs.reader
128 | }
129 |
--------------------------------------------------------------------------------
/stdoutWriter.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | type stdoutWriter struct {
8 | }
9 |
10 | var doneChannel chan bool
11 |
12 | func (w *stdoutWriter) open(s string, lineChannel chan string) error {
13 | doneChannel = make(chan bool)
14 | go w.writer(lineChannel, doneChannel)
15 |
16 | return nil
17 | }
18 |
19 | func (w *stdoutWriter) writer(lineChannel chan string, doneChannel chan bool) {
20 | for line := range lineChannel {
21 | fmt.Println(line)
22 | }
23 | doneChannel <- true
24 | }
25 |
26 | func (w *stdoutWriter) close() {
27 | _ = <-doneChannel
28 | }
29 |
--------------------------------------------------------------------------------
/test_xml.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | #FILES=`ls xml/*.xml xml/*.xml.bz2 xml/*.xml.gz`
5 | FILES=`ls xml/*.xml xml/*.xml.gz`
6 |
7 | for f in $FILES
8 | do
9 | echo ""
10 | echo ""
11 | echo ""
12 | echo "=================================================================="
13 | echo "Processing file $f"
14 | echo ""
15 | echo "Go code generation"
16 | /usr/bin/time -f "%E %M" ./chidley -W $f > test/Test.go
17 | cd test
18 | go build
19 | echo "Generated code: convert to JSON"
20 | /usr/bin/time -f "%E %M" ./test -j > /dev/null
21 | echo "Generated code: convert to JSON, streaming"
22 | /usr/bin/time -f "%E %M" ./test -j -s > /dev/null
23 | echo "Generated code: convert to XML"
24 | /usr/bin/time -f "%E %M" ./test -x > /dev/null
25 | echo "Generated code: convert to XML, streamingb"
26 | /usr/bin/time -f "%E %M" ./test -x -s > /dev/null
27 | cd ..
28 | echo "Java code generation"
29 | /usr/bin/time -f "%E %M" ./chidley -J $f
30 | cd java
31 | mvn package
32 | export CLASSPATH=target/jaxb-1.0-SNAPSHOT.jar:$CLASSPATH:/home/gnewton/.m2/repository
33 | echo "Running Java/JAXB XML -> JSON"
34 | /usr/bin/time -f "%E %M" java ca.gnewton.chidley.jaxb.Main > /dev/null
35 | cd ..
36 | done
37 |
38 |
39 | # From: http://www.ncbi.nlm.nih.gov/books/NBK25500/ and from openstreetmap.org
40 | declare -a URLS=('http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=science[journal]+AND+breast+cancer+AND+2008[pdat]' 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=science[journal]+AND+breast+cancer+AND+2008[pdat]&usehistory=y' 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=protein&id=6678417,9507199,28558982,28558984,28558988,28558990' 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi?dbfrom=protein&db=protein&id=15718680&term=rat[orgn]+AND+srcdb+refseq[prop]&cmd=neighbor_history' 'http://eutils.ncbi.nlm.nih.gov/gquery?term=mouse[orgn]&retmode=xml' 'http://api06.dev.openstreetmap.org/api/capabilities' 'http://api.openstreetmap.org/api/0.6/trackpoints?bbox=0,51.5,0.25,51.75&page=0')
41 |
42 | # for u in "${URLS[@]}"
43 | # do
44 | # echo "#=================================================================="
45 | # echo "# $u "
46 | # ./chidley -V -u -s "" -p "T_" -a "Att_" "$u"
47 | # cd chidleyVerity
48 | # go build
49 | # ./chidleyVerity
50 | # cd ..
51 | # echo "#"
52 | # done
53 |
54 |
55 |
--------------------------------------------------------------------------------
/tests_util.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | // "fmt"
5 | "bytes"
6 | "go/ast"
7 | "go/importer"
8 | "go/parser"
9 | "go/token"
10 | "go/types"
11 | "log"
12 | "strings"
13 | )
14 |
15 | func extractor(xmlStrings []string) error {
16 | log.SetFlags(log.LstdFlags | log.Lshortfile)
17 | ex := Extractor{
18 | namePrefix: namePrefix,
19 | nameSuffix: nameSuffix,
20 | useType: useType,
21 | progress: progress,
22 | ignoreXmlDecodingErrors: ignoreXmlDecodingErrors,
23 | }
24 |
25 | ex.init()
26 |
27 | for i, _ := range xmlStrings {
28 | //log.Println(xmlStrings[i])
29 | err := ex.extract(strings.NewReader(xmlStrings[i]))
30 |
31 | if err != nil {
32 | return err
33 | }
34 | }
35 |
36 | ex.done()
37 |
38 | buf := bytes.NewBufferString("")
39 | fps := make([]string, 1)
40 | //fps[0] = "foo"
41 | generateGoCode(buf, fps, &ex)
42 |
43 | //log.Println(buf.String())
44 |
45 | return parseAndType(buf.String())
46 | }
47 |
48 | // Derived from example at https://github.com/golang/example/tree/master/gotypes#an-example
49 | func parseAndType(s string) error {
50 | fset := token.NewFileSet()
51 | //f, err := parser.ParseFile(fset, "hello.go", hello, 0)
52 | f, err := parser.ParseFile(fset, "hello.go", s, 0)
53 | if err != nil {
54 | //t.Error("Expected 1.5, got ", v)
55 | //log.Fatal(err) // parse error
56 | return err
57 | }
58 |
59 | conf := types.Config{Importer: importer.Default()}
60 |
61 | // Type-check the package containing only file f.
62 | // Check returns a *types.Package.
63 | _, err = conf.Check("cmd/hello", fset, []*ast.File{f}, nil)
64 | if err != nil {
65 | //log.Fatal(err) // type error
66 | return err
67 | }
68 | return nil
69 | }
70 |
--------------------------------------------------------------------------------
/util.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "compress/bzip2"
6 | "compress/gzip"
7 | "errors"
8 | "fmt"
9 | "io"
10 | "log"
11 | "os"
12 | "sort"
13 | //"strconv"
14 | "strings"
15 | "unicode"
16 |
17 | "github.com/xi2/xz"
18 | )
19 |
20 | func genericReader(filename string) (io.Reader, *os.File, error) {
21 | file, err := os.Open(filename)
22 | if err != nil {
23 | return nil, nil, err
24 | }
25 | if strings.HasSuffix(filename, "xz") {
26 | reader, err := xz.NewReader(bufio.NewReader(file), 0)
27 | if err != nil {
28 | return nil, nil, err
29 | }
30 | return bufio.NewReader(reader), file, err
31 | }
32 |
33 | if strings.HasSuffix(filename, "bz2") {
34 | return bufio.NewReader(bzip2.NewReader(bufio.NewReader(file))), file, err
35 | }
36 |
37 | if strings.HasSuffix(filename, "gz") {
38 | reader, err := gzip.NewReader(bufio.NewReader(file))
39 | if err != nil {
40 | return nil, nil, err
41 | }
42 | return bufio.NewReader(reader), file, err
43 | }
44 | return bufio.NewReader(file), file, err
45 | }
46 |
47 | func cleanName(name string) string {
48 | for old, new := range nameMapper {
49 | parts := strings.Split(name, old)
50 | if len(parts) == 1 {
51 | continue
52 | } else {
53 | name := ""
54 | l := len(parts)
55 | for i := 0; i < l; i++ {
56 | if i == 0 {
57 | name += parts[i]
58 | } else {
59 | name += capitalizeFirstLetter(parts[i])
60 | }
61 | if i+1 < l {
62 | name += new
63 | }
64 | }
65 | }
66 | }
67 | //return capitalizeFirstLetter(name)
68 | return name
69 | }
70 |
71 | const BoolType = "bool"
72 | const StringType = "string"
73 | const IntType = "int"
74 | const Int8Type = "int8"
75 | const Int16Type = "int16"
76 | const Int32Type = "int32"
77 | const Int64Type = "int64"
78 | const Float32Type = "float32"
79 | const Float64Type = "float64"
80 |
81 | func findType(nti *NodeTypeInfo, useType bool) string {
82 | if !useType {
83 | return StringType
84 | }
85 |
86 | if nti.alwaysBool {
87 | return BoolType
88 | }
89 |
90 | if nti.alwaysInt08 {
91 | return Int8Type
92 | }
93 | if nti.alwaysInt16 {
94 | return Int16Type
95 | }
96 | if nti.alwaysInt32 {
97 | return Int32Type
98 | }
99 | if nti.alwaysInt64 {
100 | return Int64Type
101 | }
102 |
103 | if nti.alwaysInt0 {
104 | return IntType
105 | }
106 |
107 | if nti.alwaysFloat32 {
108 | return Float32Type
109 | }
110 | if nti.alwaysFloat64 {
111 | return Float64Type
112 | }
113 | return StringType
114 | }
115 |
116 | type fqnSorter []*FQN
117 |
118 | func isStringOnlyField(n *Node, nattributes int) bool {
119 | return (len(n.children) == 0 && nattributes == 0)
120 | }
121 |
122 | func makeAttributes(writer io.Writer, attributes []*FQN, nameSpaceTagMap map[string]string) {
123 | sort.Sort(fqnSorter(attributes))
124 |
125 | for _, fqn := range attributes {
126 |
127 | name := fqn.name
128 | nameSpace := fqn.space
129 |
130 | nameSpaceTag, ok := nameSpaceTagMap[nameSpace]
131 | if ok && nameSpaceTag != "" {
132 | nameSpaceTag = nameSpaceTag + "Space"
133 | } else {
134 | nameSpaceTag = nameSpace
135 | }
136 |
137 | nameSpaceTag = goVariableNameSanitize(nameSpaceTag)
138 | if len(nameSpace) > 0 {
139 | nameSpace = nameSpace + " "
140 | }
141 |
142 | //variableName := attributePrefix + capitalizeFirstLetter(nameSpaceTag) + cleanName(name)
143 | variableName := goVariableNameSanitize(attributePrefix + capitalizeFirstLetter(nameSpaceTag) + cleanName(name))
144 | variableType := "string"
145 |
146 | //lineChannel <- "\t" + variableName + " " + variableType + "`xml:\"" + nameSpace + name + ",attr\" json:\",omitempty\"`" + " // maxLength=" + strconv.Itoa(fqn.maxLength)
147 | //fmt.Fprintln(writer, "\t"+variableName+" "+variableType+"`xml:\""+nameSpace+name+",attr\" json:\",omitempty\"`"+" // maxLength="+strconv.Itoa(fqn.maxLength))
148 | fmt.Fprintln(writer, "\t"+variableName+" "+variableType+"`xml:\""+nameSpace+name+",attr\" json:\",omitempty\"`")
149 | }
150 | }
151 |
152 | func goVariableNameSanitize(s string) string {
153 | s = strings.Replace(s, ":", "_colon_", -1)
154 | s = strings.Replace(s, "/", "_slash_", -1)
155 | s = strings.Replace(s, ".", "_dot_", -1)
156 | s = strings.Replace(s, "-", "_dash_", -1)
157 | s = strings.Replace(s, " ", "_space_", -1)
158 | s = strings.Replace(s, "-", "_dash_", -1)
159 |
160 | return s
161 | }
162 |
163 | // Len is part of sort.Interface.
164 | func (s fqnSorter) Len() int {
165 | return len(s)
166 | }
167 |
168 | // Swap is part of sort.Interface.
169 | func (s fqnSorter) Swap(i, j int) {
170 | s[i], s[j] = s[j], s[i]
171 | }
172 |
173 | // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
174 | func (s fqnSorter) Less(i, j int) bool {
175 | return strings.Compare(cleanName(s[i].name), cleanName(s[j].name)) < 0
176 | }
177 |
178 | // node key
179 | func nk(n *Node) string {
180 | return nks(n.space, n.name)
181 | }
182 |
183 | func nks(space, name string) string {
184 | return space + "NS" + name
185 | }
186 |
187 | func getFullPaths(filenames []string) ([]string, error) {
188 | fps := make([]string, len(filenames))
189 | var err error
190 | for i, _ := range filenames {
191 | fps[i], err = getFullPath(filenames[i])
192 | if err != nil {
193 | return nil, err
194 | }
195 | }
196 |
197 | return fps, nil
198 | }
199 |
200 | func getFullPath(filename string) (string, error) {
201 | if filename == "" {
202 | return "", nil
203 | }
204 | file, err := os.Open(filename) // For read access.
205 | if err != nil {
206 | log.Print("Error opening: " + filename)
207 | return "", err
208 | }
209 | return file.Name(), nil
210 | }
211 |
212 | type alterer func(string) string
213 |
214 | func alterFirstLetter(s string, f alterer) string {
215 | switch len(s) {
216 | case 0:
217 | return s
218 | case 1:
219 | v := f(s[0:1])
220 | return v
221 |
222 | default:
223 | return f(s[0:1]) + s[1:]
224 | }
225 | }
226 |
227 | func capitalizeFirstLetter(s string) string {
228 | return alterFirstLetter(s, strings.ToUpper)
229 | }
230 |
231 | func lowerFirstLetter(s string) string {
232 | return alterFirstLetter(s, strings.ToLower)
233 | }
234 |
235 | func findThisAttribute(local, nameSpace string, attrs []*FQN) *FQN {
236 | for _, attr := range attrs {
237 | if attr.name == local && attr.space == nameSpace {
238 | return attr
239 | }
240 | }
241 | return nil
242 | }
243 |
244 | func makeAttributeName(key, namespace, local string) string {
245 | return key + "_" + local + "_" + namespace
246 |
247 | }
248 |
249 | func containsUnicodeSpace(s string) bool {
250 | if s == "" {
251 | return false
252 | }
253 |
254 | for _, rune := range s {
255 | //log.Printf("*** %#U ****", rune)
256 | if unicode.IsSpace(rune) {
257 | return true
258 | }
259 | }
260 | return false
261 | }
262 |
263 | func isIgnoredTag(tag string) bool {
264 | var ignored bool
265 | if ignoredXmlTagsMap == nil {
266 | return false
267 | }
268 | _, ignored = (*ignoredXmlTagsMap)[tag]
269 |
270 | if ignored || (ignoreLowerCaseXmlTags && tag == strings.ToLower(tag)) {
271 | return true
272 | }
273 |
274 | return false
275 |
276 | }
277 |
278 | func extractExcludedTags(tagsString string) (*map[string]struct{}, error) {
279 | ignoredMap := make(map[string]struct{})
280 | if tagsString == "" {
281 | return &ignoredMap, nil
282 | }
283 |
284 | tags := strings.Split(tagsString, ",")
285 |
286 | for i, _ := range tags {
287 | tag := strings.TrimSpace(tags[i])
288 | if containsUnicodeSpace(tag) {
289 | return nil, errors.New("Excluded tag contains space: [" + tag + "] in list of excluded tags:" + tagsString + "]")
290 | }
291 | ignoredMap[tag] = struct{}{}
292 |
293 | }
294 | return &ignoredMap, nil
295 | }
296 |
297 | func findFieldNameFromTypeInfo(t string) string {
298 | switch t {
299 | case IntType, Int8Type, Int16Type, Int32Type, Int64Type, Float32Type, Float64Type:
300 | return cdataNumberName
301 | case BoolType:
302 | return cdataBooleanName
303 | }
304 | return "string"
305 |
306 | }
307 |
--------------------------------------------------------------------------------
/util_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | //"log"
5 | "testing"
6 | // "unicode"
7 | )
8 |
9 | func TestExtractExcludedTags_EmptyString(t *testing.T) {
10 | s := ""
11 | b := containsUnicodeSpace(s)
12 | if b != false {
13 | t.Error()
14 | }
15 | }
16 |
17 | func TestExtractExcludedTags_CorrectString(t *testing.T) {
18 | s := "a,b,c,d,e"
19 | b := containsUnicodeSpace(s)
20 | if b != false {
21 | t.Error()
22 | }
23 | }
24 |
25 | func TestExtractExcludedTags_StringWithSpaces(t *testing.T) {
26 | s := "a,b,c,d, e"
27 | b := containsUnicodeSpace(s)
28 | if b != true {
29 | t.Error()
30 | }
31 | }
32 |
33 | // Latin-1 spaces taken from https://golang.org/pkg/unicode/#IsSpace
34 | func TestExtractExcludedTags_StringWithAllLatin1Spaces(t *testing.T) {
35 | s := "\t\n\v\f\r U+0085 U+00A0"
36 | b := containsUnicodeSpace(s)
37 | if b != true {
38 | t.Error()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/xml/MODIS-Imagery-OilSpill.kml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MODIS Imagery Overlays
5 | Deepwater Horizon Oil Spill
6 | 1
7 | Google Crisis Response
8 |
9 | This folder contains MODIS imagery of the oil spill in the gulf of Mexico in April 2010, caused by the sinking of the Deepwater Horizon oil rig.
Select dates in the Layers Panel on the left to see imagery from all the available dates.
Data courtesy of NASA
KML layer courtesy of Google Crisis Resposne
]]>
10 |
11 |
12 |
17 |
22 | #style_MainDoc
23 |
24 | -87.95
25 | 28.80
26 | 0
27 | 743000
28 | 0.00
29 | 0.00
30 |
31 |
32 | 2010-06-19 - MODIS
33 | #style_ModisOverlay
34 | 1
35 |
36 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-19/index.kml
37 |
38 |
39 | -88.25
40 | 29.94
41 | 2000000
42 |
43 |
44 |
45 | 2010-06-18 - MODIS
46 | #style_ModisOverlay
47 | 0
48 |
49 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-18/index.kml
50 |
51 |
52 | -88.25
53 | 29.94
54 | 2000000
55 |
56 |
57 |
58 | 2010-06-17 - MODIS
59 | #style_ModisOverlay
60 | 0
61 |
62 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-17/index.kml
63 |
64 |
65 | -88.25
66 | 29.94
67 | 2000000
68 |
69 |
70 |
71 | 2010-06-14 - MODIS
72 | #style_ModisOverlay
73 | 0
74 |
75 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-14/index.kml
76 |
77 |
78 | -88.25
79 | 29.94
80 | 2000000
81 |
82 |
83 |
84 | 2010-06-12 - MODIS
85 | #style_ModisOverlay
86 | 0
87 |
88 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-12/index.kml
89 |
90 |
91 | -88.25
92 | 29.94
93 | 2000000
94 |
95 |
96 |
97 | 2010-06-11 - MODIS
98 | #style_ModisOverlay
99 | 0
100 |
101 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-11/index.kml
102 |
103 |
104 | -88.25
105 | 29.94
106 | 2000000
107 |
108 |
109 |
110 | 2010-06-10 - MODIS
111 | #style_ModisOverlay
112 | 0
113 |
114 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-10/index.kml
115 |
116 |
117 | -88.25
118 | 29.94
119 | 2000000
120 |
121 |
122 |
123 | 2010-06-09 - MODIS
124 | #style_ModisOverlay
125 | 0
126 |
127 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-09/index.kml
128 |
129 |
130 | -88.25
131 | 29.94
132 | 2000000
133 |
134 |
135 |
136 | 2010-06-08 - MODIS
137 | #style_ModisOverlay
138 | 0
139 |
140 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-08/index.kml
141 |
142 |
143 | -88.25
144 | 29.94
145 | 2000000
146 |
147 |
148 |
149 | 2010-06-07 - MODIS
150 | #style_ModisOverlay
151 | 0
152 |
153 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_2010-06-07/index.kml
154 |
155 |
156 | -88.25
157 | 29.94
158 | 2000000
159 |
160 |
161 |
162 | 2010-05-27 - MODIS
163 | #style_ModisOverlay
164 | 0
165 |
166 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/modis_05_27_2010_aqua/doc.kml
167 |
168 |
169 | -88.25
170 | 29.94
171 | 2000000
172 |
173 |
174 |
175 | 2010-05-26 - MODIS
176 | #style_ModisOverlay
177 | 0
178 |
179 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_05-26-2010/doc.kml
180 |
181 |
182 | -88.25
183 | 29.94
184 | 2000000
185 |
186 |
187 |
188 | 2010-05-25 - MODIS
189 | #style_ModisOverlay
190 | 0
191 |
192 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/MODIS_0525_v13/doc.kml
193 |
194 |
195 | -88.25
196 | 29.94
197 | 2000000
198 |
199 |
200 |
201 | 2010-05-23 - MODIS
202 | #style_ModisOverlay
203 | 0
204 |
205 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/Modis_2010-05-23/index.kml
206 |
207 |
208 | -88.25
209 | 29.94
210 | 2000000
211 |
212 |
213 |
214 | 2010-05-22 - MODIS
215 | #style_ModisOverlay
216 | 0
217 |
218 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/Modis_2010-05-22/index.kml
219 |
220 |
221 | -88.25
222 | 29.94
223 | 2000000
224 |
225 |
226 |
227 | 2010-05-20 - MODIS
228 | #style_ModisOverlay
229 | 0
230 |
231 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-05-20/index.kml
232 |
233 |
234 | -88.25
235 | 29.94
236 | 2000000
237 |
238 |
239 |
240 | 2010-05-17 - MODIS
241 | #style_ModisOverlay
242 | 0
243 |
244 | http://mw1.google.com/mw-earth-vectordb/disaster/gulf_oil_spill/Modis_Oil_Spill-2010_05_17/index.kml
245 |
246 |
247 | -88.25
248 | 29.94
249 | 2000000
250 |
251 |
252 |
253 | 2010-05-11 - MODIS
254 | #style_ModisOverlay
255 | 0
256 |
257 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_250m_20100511/index.kml
258 |
259 |
260 | -88.25
261 | 29.94
262 | 2000000
263 |
264 |
265 |
266 | 2010-05-10 - MODIS
267 | #style_ModisOverlay
268 | 0
269 |
270 | http://mw1.google.com/mw-earth-vectordb/disaster/MODIS_2010-05-10_v2/MODIS_2010-05-10_v2.kml
271 |
272 |
273 | -88.25
274 | 29.94
275 | 2000000
276 |
277 |
278 |
279 | 2010-05-09 - MODIS
280 | #style_ModisOverlay
281 | 0
282 |
283 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/Modis_2010-05-09/index.kml
284 |
285 |
286 | -88.25
287 | 29.94
288 | 2000000
289 |
290 |
291 |
292 | 2010-05-08 - MODIS
293 | #style_ModisOverlay
294 | 0
295 |
296 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/Modis_2010-04-08/index.kml
297 |
298 |
299 | -88.25
300 | 29.94
301 | 2000000
302 |
303 |
304 |
305 | 2010-05-07 - MODIS
306 | #style_ModisOverlay
307 | 0
308 |
309 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Oil_Spill_2010/Modis_Oil_Spill-2010_05_07/doc.kml
310 |
311 |
312 | -88.25
313 | 29.94
314 | 2000000
315 |
316 |
317 |
318 | 2010-05-05 - MODIS
319 | #style_ModisOverlay
320 | 0
321 |
322 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_250m_20100505/index.kml
323 |
324 |
325 | -88.25
326 | 29.94
327 | 2000000
328 |
329 |
330 |
331 | 2010-05-04 - MODIS
332 | #style_ModisOverlay
333 | 0
334 |
335 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-05-04/index.kml
336 |
337 |
338 | -88.25
339 | 29.94
340 | 2000000
341 |
342 |
343 |
344 | 2010-04-29 - MODIS
345 | #style_ModisOverlay
346 | 0
347 |
348 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-04-29/index.kml
349 |
350 |
351 | -88.25
352 | 29.94
353 | 2000000
354 |
355 |
356 |
357 | 2010-04-28 - MODIS
358 | #style_ModisOverlay
359 | 0
360 |
361 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-04-28/index.kml
362 |
363 |
364 | -88.25
365 | 29.94
366 | 2000000
367 |
368 |
369 |
370 | 2010-04-27 - MODIS
371 | #style_ModisOverlay
372 | 0
373 |
374 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-04-27/index.kml
375 |
376 |
377 | -88.25
378 | 29.94
379 | 2000000
380 |
381 |
382 |
383 | 2010-04-26 - MODIS
384 | #style_ModisOverlay
385 | 0
386 |
387 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-04-26/index.kml
388 |
389 |
390 | -88.25
391 | 29.94
392 | 2000000
393 |
394 |
395 |
396 | 2010-04-25 - MODIS
397 | #style_ModisOverlay
398 | 0
399 |
400 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-04-25/index.kml
401 |
402 |
403 | -88.25
404 | 29.94
405 | 2000000
406 |
407 |
408 |
409 | 2010-04-22 - MODIS
410 | #style_ModisOverlay
411 | 0
412 |
413 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-04-22/index.kml
414 |
415 |
416 | -88.25
417 | 29.94
418 | 2000000
419 |
420 |
421 |
422 | 2010-04-21 - MODIS
423 | #style_ModisOverlay
424 | 0
425 |
426 | http://mw1.google.com/mw-earth-vectordb/disaster/Gulf_Spill_2010/MODIS_2010-04-21/index.kml
427 |
428 |
429 | -88.25
430 | 29.94
431 | 2000000
432 |
433 |
434 |
435 |
436 |
437 |
--------------------------------------------------------------------------------
/xml/MODIS-Imagery-OilSpill.kml.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnewton/chidley/09b9269092fb8f0bf2548ba78529cfe9c9bd072e/xml/MODIS-Imagery-OilSpill.kml.gz
--------------------------------------------------------------------------------
/xml/amazon_api.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | ID for the distribution
8 | Deployed | InProgress
9 | creation date and time in
10 | ISO 8601 format
11 | number of invalidation batches being
12 | processed for this distribution
13 | CloudFront domain name assigned to the
14 | distribution
15 |
16 | true | false
17 | number of unique trusted signers from
18 | all cache behaviors
19 |
20 |
21 | self | AWS account number
22 |
23 | number of active key pairs for
24 | AwsAccountNumber
25 |
26 | active key pair associated with
27 | AwsAccountNumber
28 |
29 |
30 |
31 |
32 |
33 |
34 | unique description for this
35 | distribution config
36 |
37 | number of CNAME aliases
38 |
39 |
40 | CNAME alias
41 |
42 |
43 | URL for default root object
44 |
45 | number of origins
46 |
47 |
48 | unique identifier for this origin
49 | domain name of origin
50 |
52 |
53 | origin-access-identity/
54 | cloudfront/Id
55 |
56 |
58 |
59 | HTTP port that the custom origin
60 | listens on
61 | HTTPS port that the custom origin
62 | listens on
63 | http-only |
64 | match-viewer
65 |
66 |
67 |
68 |
69 |
70 | ID of the origin that the default cache behavior
71 | applies to
72 |
73 | true | false
74 |
75 | all | whitelist | none
76 |
77 |
78 | number of cookie names to
79 | forward to origin
80 |
81 | name of a cookie to forward to the origin
82 |
83 |
84 |
85 |
86 | number of headers to forward to origin
87 |
88 | header
89 |
90 |
91 |
92 |
93 | true | false
94 | number of trusted signers
95 |
96 |
97 | self | AWS account that can create
98 | signed URLs
99 |
100 |
101 | allow-all |
102 | redirect-to-https | https-only
103 | minimum TTL for objects in seconds
104 |
105 | 2 | 7
106 |
107 |
109 | GET
110 | HEAD
111 |
113 | DELETE
114 | GET
115 | HEAD
116 | OPTIONS
117 | PATCH
118 | POST
119 | PUT
120 |
121 |
122 | true | false
123 |
124 |
125 | number of cache behaviors
126 |
127 |
128 |
129 | pattern that specifies files that this
130 | cache behavior applies to
131 | ID of the origin that this cache behavior
132 | applies to
133 |
134 | true | false
135 |
136 | all | whitelist | none
137 |
139 |
140 | number of cookie names to
141 | forward to origin
142 |
143 | name of a cookie to forward to
144 | the origin
145 |
146 |
147 |
148 |
149 | number of headers to forward to origin
150 |
151 | header
152 |
153 |
154 |
155 |
156 | true | false
157 | number of trusted signers
158 |
159 |
160 | self | AWS account that can create
161 | signed URLs
162 |
163 |
164 | allow-all |
165 | redirect-to-https | https-only
166 | minimum TTL in seconds for files
167 | specified by PathPattern
168 |
169 | 2 | 7
170 |
171 |
174 | GET
175 | HEAD
176 |
178 | DELETE
179 | GET
180 | HEAD
181 | OPTIONS
182 | PATCH
183 | POST
184 | PUT
185 |
186 |
187 | true | false
188 |
189 |
190 |
191 |
192 | number of custom error responses
193 |
194 |
195 | HTTP status code for which you want to
196 | customize the response
197 | path to custom error page
198 | HTTP status code that you want CloudFront
199 | to return along with the custom error page
200 | minimum TTL for this
201 | ErrorCode
202 |
203 |
204 |
205 |
206 |
207 | blacklist | whitelist | none
208 | number of countries
209 | in the blacklist or whitelist
210 |
211 |
212 | two-letter country code in upper case
213 |
214 |
215 |
216 | comment about the distribution
217 |
218 | true | false
219 | true | false
220 | Amazon S3 bucket to save logs in
221 | prefix for log filenames
222 |
223 |
224 | IAM certificate ID
225 | true
226 | vip | sni-only
227 |
228 | maximum price class for the distribution
229 | true | false
230 |
231 |
232 |
--------------------------------------------------------------------------------
/xml/arxiv_search_query.xml.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnewton/chidley/09b9269092fb8f0bf2548ba78529cfe9c9bd072e/xml/arxiv_search_query.xml.gz
--------------------------------------------------------------------------------
/xml/pubmed_xml_12750255.xml.bz2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gnewton/chidley/09b9269092fb8f0bf2548ba78529cfe9c9bd072e/xml/pubmed_xml_12750255.xml.bz2
--------------------------------------------------------------------------------
/xml/test1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Dune
5 |
6 | Herbert
7 | Frank
8 |
9 |
10 |
11 | Brave New Wold
12 |
13 | Huxley
14 | Aldous
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/xml/test2.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | number one
7 | number two
8 |
9 |
--------------------------------------------------------------------------------
/xml/test2a.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | number one
7 | number two
8 |
9 |
--------------------------------------------------------------------------------
/xml/test2b.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | number one
6 | number two
7 |
8 |
--------------------------------------------------------------------------------
/xml/test2c.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | number one
4 | number two
5 |
6 |
--------------------------------------------------------------------------------
/xml/test3a.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | number one
4 |
5 |
--------------------------------------------------------------------------------
/xml/test3b.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | number two
7 |
8 |
9 |
--------------------------------------------------------------------------------
/xml/test3c.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | number one
7 |
8 |
--------------------------------------------------------------------------------
/xml/test4.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 | A book entry
7 |
8 |
9 | A article entry
10 |
11 |
12 |
--------------------------------------------------------------------------------
/xml/testSpacePreserve.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Alix
5 | Krakowski
6 |
7 |
8 | Roses are red,
9 | Violets are blue.
10 | -Alix
11 |
12 |
13 |
--------------------------------------------------------------------------------
/xml/testType.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bill
6 | 37
7 | 9999999999999
8 | true
9 | yes
10 |
11 |
12 |
13 | sarah
14 | 24
15 | 555555555555555
16 | false
17 | no
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/xml_source_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | const sameNameDifferentNameSpaceXML = `
4 |
5 |
6 |
7 | 1
8 | Google Crisis Response
9 | ogle Crisis Responsex
10 |
11 |
12 | `
13 |
14 | //https://github.com/gnewton/chidley/issues/24
15 | const mixedCaseSameNameXML_Issue24 = `
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | `
25 |
26 | const tagsContainHyphens = `
27 |
28 |
29 | Bill
30 | Smith
31 |
32 | `
33 |
34 | //https://github.com/gnewton/chidley/issues/14
35 | const githubIssue14 = `
36 |
37 |
38 | _ActionId-3525062221263473230--64db5972.154ce25275c.-7fc5
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | `
47 |
--------------------------------------------------------------------------------
/xml_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | //"log"
5 | "testing"
6 | )
7 |
8 | func TestTagsContainHyphens(t *testing.T) {
9 | err := extractor([]string{tagsContainHyphens})
10 | if err != nil {
11 | t.Error(err)
12 | }
13 | }
14 |
15 | func TestTagsWithSameNameDifferentNameSpaceXML(t *testing.T) {
16 | err := extractor([]string{sameNameDifferentNameSpaceXML})
17 | if err != nil {
18 | t.Error(err)
19 | }
20 | }
21 |
22 | func TestMixedCaseSameNameTagsXML_Issue24(t *testing.T) {
23 | err := extractor([]string{mixedCaseSameNameXML_Issue24})
24 | if err != nil {
25 | t.Error(err)
26 | }
27 | }
28 |
29 | //https://github.com/gnewton/chidley/issues/14
30 | func TestGithubIssue14(t *testing.T) {
31 | err := extractor([]string{githubIssue14})
32 | if err != nil {
33 | t.Error(err)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------