Skip to content

Commit b402733

Browse files
authored
feat(internal): marshal self-closing tags in XML (#1225)
Currently self-closing tags are marshaled as `<a></a>` which is not the preferred format `<a/>`. With the current implementation of `encoding/xml`, self-closing tags are expanded to `StartElement` and `EndElement` so both elements are written to output. In this PR, a field `Empty` is added to both elements to indicate whether the current element is empty. During encoding: - `/` is written before `>` for an empty `StartElement` - nothing will be written for an empty `EndElement` Considering that we only want tabs not being escaped, this PR modifies `escapeNewline` to `escapeWhitespace` to indicate if we want all whitespace characters escaped.
1 parent 07619c0 commit b402733

File tree

6 files changed

+189
-159
lines changed

6 files changed

+189
-159
lines changed

internal/resolution/manifest/__snapshots__/maven_test.snap

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<groupId>org.example</groupId>
4343
<artifactId>abc</artifactId>
4444
<version>1.0.1</version>
45+
<optional/>
4546
</dependency>
4647
<dependency>
4748
<groupId>org.example</groupId>
@@ -186,6 +187,7 @@
186187
<groupId>org.example</groupId>
187188
<artifactId>abc</artifactId>
188189
<version>1.0.2</version>
190+
<optional/>
189191
</dependency>
190192
<dependency>
191193
<groupId>org.example</groupId>

internal/resolution/manifest/fixtures/maven/my-app/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<groupId>org.example</groupId>
4141
<artifactId>abc</artifactId>
4242
<version>1.0.1</version>
43+
<optional/>
4344
</dependency>
4445
<dependency>
4546
<groupId>org.example</groupId>

internal/thirdparty/xml/marshal.go

+19-11
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,11 @@ func (enc *Encoder) EncodeToken(t Token) error {
216216
return err
217217
}
218218
case EndElement:
219-
if err := p.writeEnd(t.Name); err != nil {
219+
if err := p.writeEnd(t.Name, t.Empty); err != nil {
220220
return err
221221
}
222222
case CharData:
223-
p.Write(t)
223+
escapeText(p, t, false)
224224
case Comment:
225225
if bytes.Contains(t, endComment) {
226226
return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
@@ -495,6 +495,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
495495
if startTemplate != nil {
496496
start.Name = startTemplate.Name
497497
start.Attr = append(start.Attr, startTemplate.Attr...)
498+
start.Empty = startTemplate.Empty
498499
} else if tinfo.xmlname != nil {
499500
xmlname := tinfo.xmlname
500501
if xmlname.name != "" {
@@ -569,7 +570,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
569570
return err
570571
}
571572

572-
if err := p.writeEnd(start.Name); err != nil {
573+
if err := p.writeEnd(start.Name, start.Empty); err != nil {
573574
return err
574575
}
575576

@@ -712,7 +713,7 @@ func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartEl
712713
return err
713714
}
714715
EscapeText(p, text)
715-
return p.writeEnd(start.Name)
716+
return p.writeEnd(start.Name, start.Empty)
716717
}
717718

718719
// writeStart writes the given start element.
@@ -750,11 +751,16 @@ func (p *printer) writeStart(start *StartElement) error {
750751
p.EscapeString(attr.Value)
751752
p.WriteByte('"')
752753
}
754+
755+
if start.Empty {
756+
p.WriteByte('/')
757+
}
758+
753759
p.WriteByte('>')
754760
return nil
755761
}
756762

757-
func (p *printer) writeEnd(name Name) error {
763+
func (p *printer) writeEnd(name Name, empty bool) error {
758764
if name.Local == "" {
759765
return fmt.Errorf("xml: end tag with no name")
760766
}
@@ -769,11 +775,13 @@ func (p *printer) writeEnd(name Name) error {
769775
}
770776
p.tags = p.tags[:len(p.tags)-1]
771777

772-
p.writeIndent(-1)
773-
p.WriteByte('<')
774-
p.WriteByte('/')
775-
p.WriteString(name.Local)
776-
p.WriteByte('>')
778+
if !empty {
779+
p.writeIndent(-1)
780+
p.WriteByte('<')
781+
p.WriteByte('/')
782+
p.WriteString(name.Local)
783+
p.WriteByte('>')
784+
}
777785
p.popPrefix()
778786
return nil
779787
}
@@ -1087,7 +1095,7 @@ func (s *parentStack) trim(parents []string) error {
10871095
}
10881096
}
10891097
for i := len(s.stack) - 1; i >= split; i-- {
1090-
if err := s.p.writeEnd(Name{Local: s.stack[i]}); err != nil {
1098+
if err := s.p.writeEnd(Name{Local: s.stack[i]}, false); err != nil {
10911099
return err
10921100
}
10931101
}

0 commit comments

Comments
 (0)