Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions element.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,23 @@ func (e *element) writeGoType(w io.Writer, options *generateOptions, indentPrefi
}
fieldNames[exportedChildName] = struct{}{}

// Check for repeated/optional, considering compact types path.
_, repeated := e.repeatedChildren[childElement.name]
_, optional := e.optionalChildren[childElement.name]

// For compact types, also check if any element along the compact path is repeated.
if options.compactTypes && !repeated {
targetChild := firstNotContainerElement(childElement)
if targetChild != childElement {
repeated = isRepeatedInCompactPath(childElement, targetChild)
}
}

fmt.Fprintf(w, "%s\t%s ", indentPrefix, exportedChildName)
if _, repeated := e.repeatedChildren[childElement.name]; repeated {
if repeated {
fmt.Fprintf(w, "[]")
} else if options.usePointersForOptionalFields {
if _, optional := e.optionalChildren[childElement.name]; optional {
if optional {
fmt.Fprintf(w, "*")
}
}
Expand Down Expand Up @@ -257,6 +269,38 @@ func firstNotContainerElement(el *element) *element {
return el
}

// isRepeatedInCompactPath checks if any element along the compact path from start to target is repeated.
func isRepeatedInCompactPath(start, target *element) bool {
current := start
for current != target && current.isContainer() {
for childName, childElement := range current.childElements {
if _, repeated := current.repeatedChildren[childName]; repeated {
return true
}
if childElement == target || isAncestorOf(childElement, target) {
current = childElement
break
}
}
}
return false
}

// isAncestorOf checks if ancestor is an ancestor of descendant in the element tree.
func isAncestorOf(ancestor, descendant *element) bool {
if ancestor == descendant {
return true
}
if ancestor.isContainer() {
for _, child := range ancestor.childElements {
if isAncestorOf(child, descendant) {
return true
}
}
}
return false
}

func exportedName(el *element, options *generateOptions) string {
return exportedNameWithoutSuffix(el, options) + options.elemNameSuffix
}
Expand Down
8 changes: 4 additions & 4 deletions generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,8 +649,8 @@ func TestGenerator(t *testing.T) {
` C struct {`,
"\t\t\tCharData string `xml:\",chardata\"`",
` D struct {`,
"\t\t\t\tE struct{} `xml:\"e\"`",
"\t\t\t\tG struct{} `xml:\"f>g\"`",
"\t\t\t\tE struct{} `xml:\"e\"`",
"\t\t\t\tG []struct{} `xml:\"f>g\"`",
"\t\t\t} `xml:\"d\"`",
"\t\t} `xml:\"c\"`",
"\t} `xml:\"b\"`",
Expand Down Expand Up @@ -702,8 +702,8 @@ func TestGenerator(t *testing.T) {
"}",
"",
"type D struct {",
"\tE struct{} `xml:\"e\"`",
"\tG struct{} `xml:\"f>g\"`",
"\tE struct{} `xml:\"e\"`",
"\tG []struct{} `xml:\"f>g\"`",
"}",
),
},
Expand Down