superfell
superfell

Reputation: 19040

Compile error with nested xml comprehensions

I'm trying to generate some XML from some nested scala types, e.g.

class Inner(val n:String)

class Outer(val n:String, val i:Seq[Inner])

given Outer(1,[2,3]), i want to generate <root><item>1</item><item>2</item><item>3</item></root> (note that Inners values are not nested inside Outers element in the xml). I have this code

object Xmlizer {

    def main(args: Array[String]) {
        val outers = (1 to 2).map(o => new Outer("outer" + o, List(new Inner("i"))))

        val root = <root>
                    { outers.map(o => <item>{o.n}</item> { o.i.map (i => <item>{i.n}</item>) } ) }
                </root>

        println(root)
    }
}

This generates a compiler error

 error: overloaded method value apply with alternatives:
  (f: scala.xml.Node => Boolean)scala.xml.NodeSeq <and>
  (i: Int)scala.xml.Node
 cannot be applied to (Seq[scala.xml.Elem])
                    { outers.map(o => <item>{o.n}</item> { o.i.map (i => <item>{i.n}</item>) } ) }

I have nested comprehensions working where the nested loop is within a pair of elements, and if i simplify to one comprehension that works, e.g.

val root = <root>
            { outers.map(o => <item>{o.n}</item><item>{o.i.head.n}</item> ) }
        </root>

so its not like the { } needs to return a single container element, but when i expand Inner to be another comprehension it gives the compiler error. Is there some trick to getting this working, or do i need to somehow flatten the scala data into a single list first?

Upvotes: 1

Views: 109

Answers (1)

senia
senia

Reputation: 38045

You should create a flat collection of items:

<root>
  { outers.flatMap(o => <item>{o.n}</item> +: o.i.map{ i => <item>{i.n}</item> } ) }
</root>
// <root><item>outer1</item><item>i</item><item>outer2</item><item>i</item></root>

With <item>{o.n}</item><item>{o.i.head.n}</item> you are creating a combination of 2 objects of the same type, compiler is smart enough to create it.

But this code:

<item>{o.n}</item> { o.i.map (i => <item>{i.n}</item>) }

actually looks like this:

<item>{o.n}</item>{Seq(<item>{o.i.head.n}</item>)}

You are trying to combine 2 object of completely different types. You should tell to compiler how to combine Node with Seq[Node]:

<item>{o.n}</item> +: o.i.map (i => <item>{i.n}</item>)

Upvotes: 1

Related Questions