apple / pkl

A configuration as code language with rich validation and tooling.
https://pkl-lang.org
Apache License 2.0
9.85k stars 258 forks source link

Rendering lists in XML may produce unexpected results #459

Open jsundin opened 2 months ago

jsundin commented 2 months ago

This was discovered during evaluation, and is not a case we actually need supported. It does feel unexpected and just thought it was worth mentioning.

Given the following example.pkl file:

adminIdList = List(1, 2, 3)

We can produce the following json file:

$ pkl eval -f json example.pkl 
{
  "adminIdList": [
    1,
    2,
    3
  ]
}

However, when we try to produce the XML representation of this we get:

$ pkl eval -f xml example.pkl 
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <adminIdList>123</adminIdList>
</root>

This does seem unexpected and prone to mistakes, as it has a completely different meaning. There are tests expecting this behaviour, for example input and output.

The following XML could be the expected behaviour for me in this particular case. But honestly, lists and XML can be tricky. How would you deal with adminIdList = null in this case? And how would that solution compare to that of an empty list?

<root>
  <adminIdList>1</adminIdList>
  <adminIdList>2</adminIdList>
  <adminIdList>3</adminIdList>
</root>

The properties renderer just bails out for this case, which could also be reasonable.

The above has been tested using the following versions:

holzensp commented 2 months ago

The problem here is that the standard representation of a list of things in XML is to write out the elements consecutively. This is actually quite central in the XML spec.

Given

import "pkl:xml"

class Foo {
  bar: Int
}

elements: Listing<Foo> = new {
  new { bar = 1 }
  new { bar = 2 }
}

output {
  renderer = new xml.Renderer {}
}

you get

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <elements>
    <Foo>
      <bar>1</bar>
    </Foo>
    <Foo>
      <bar>2</bar>
    </Foo>
  </elements>
</root>

It would be unexpected, at least, to get

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <elements>
    <Foo>
      <bar>1</bar>
    </Foo>
  </elements>
  <elements>
    <Foo>
      <bar>2</bar>
    </Foo>
  </elements>
</root>

It is admittedly awkward that 1, 2, and 3 come out as 123, which is "just" because Int is a primitive type. That said, if you need repetition of the element tag, or even just line breaks to separate elements of the list, the solution is to use converters.