Easy way to append one NodeSeq to another

1,443 views
Skip to first unread message

Jack Park

unread,
Dec 24, 2011, 1:30:37 AM12/24/11
to lif...@googlegroups.com
I've been looking around for an easy way to append one NodeSeq to
another. The reason is this:

In the middle of building some HTML like this:

<div>
<h2>Hello World</h2>
{
...create a list of elements, e.g.
<li>something</li>
<li>something else</li>
}

where, in reality, inside the {} blocks is an iterator and a while
loop that calls a routine that returns a NodeSeq, but being inside the
{} block, that NodeSeq is not added as it is in the above sketch. So,
the code is changed to:

var x: Nodeseq =
<div>
<h2>Hello World</h2>
{
do some calculations that set this:

Jack Park

unread,
Dec 24, 2011, 1:39:02 AM12/24/11
to lif...@googlegroups.com
Not too happy with this new gmail interface; it's tricky--let me finish:

> var x: Nodeseq =
> <div>
> <h2>Hello World</h2>
> {
> do some calculations that set this:

var y:NodeSeq = doSomething()
here's where I'd love to do something trivial like:
x.++(y)
but the compiler simply hates that. Didn't like :+ either; -that takes a Node

The question is this: short of a messy foreach loop, is there some
simple way to append y to x?

Many thanks
Jack

Denis Nevmerzhitsky

unread,
Dec 24, 2011, 2:42:42 AM12/24/11
to lif...@googlegroups.com
Hi!

Probably your example code is not full.
It is strange, but x ++ y should work:
scala> val x: NodeSeq = <a><b /></a>
x: scala.xml.NodeSeq = <a><b></b></a>

scala> val y: NodeSeq = <c><d /></c>
y: scala.xml.NodeSeq = <c><d></d></c>

scala> x ++ y
res5: scala.xml.NodeSeq = NodeSeq(<a><b></b></a>, <c><d></d></c>)

Or you want to embed one NodeSeq into another? So you can do this:
scala> def doSomething(): NodeSeq = <c><d /></c>
doSomething: ()scala.xml.NodeSeq

scala> val x: NodeSeq = <a>{doSomething()}</a>
x: scala.xml.NodeSeq = <a><c><d></d></c></a>

If it didn't help you, post full example.
Good luck.

Jack Park

unread,
Dec 24, 2011, 12:54:06 PM12/24/11
to lif...@googlegroups.com
Hi Denis,

Actually, the second instance is close to what I am doing, except that
it's a bit more complex:

<li id={"node_"+loxa}>
<a class="nodehref" href={lox}><img class="nodeimg"
src={"/images"+node.getSmallIcon()}/><span
class="nodetitle">{node.getLabel("en")}</span></a>
{
if (snappers != null) {
itr = snappers.iterator
<ul><div style='height: 100%; overflow: visible;'>
while(itr.hasNext)
createTree(start,count,itr.next(),credentials)
</div></ul>
}
}
</li>


There is an if block and while loop embedded. What that returns is a
nested while(itr.hasNext)
createTree(start,count,itr.next(),credentials)
inside the nested <ui> </ui> block.

That's the reason for my query: the idea is to isolate the while loop
inside {} and use something like ++ except that I want them nested,
not appended where you see the "," as per your example.

The game is to isolate the while loop and still get the NodeSeq output
of createTree()

Thanks
Jack

> --
> Lift, the simply functional web framework: http://liftweb.net
> Code: http://github.com/lift
> Discussion: http://groups.google.com/group/liftweb
> Stuck? Help us help you:
> https://www.assembla.com/wiki/show/liftweb/Posting_example_code

Jack Park

unread,
Dec 24, 2011, 1:53:44 PM12/24/11
to lif...@googlegroups.com
After spending some time reading the NodeSeq docs and playing in the
console, my current belief is that what I seek cannot be done. ++ is
said, according to the docs, to concatinate two sequences. It will
return a,b when what I want is ab. The operator +: does the same
thing. I would suggest that what I really need is a NodeSeq operator
"append" which is how +: is defined, but it treats it more like a
collection than a continuous object. Embedding by directly calling a
single function and not applying an entire embedded algorithm does
work; once you embed an algorithm, you return to needing an append
operator that works as I mentioned.

The option is thus to return to the original code, which built the
structure with a StringBuilder, and then uses XML.loadString. I was
trying to work around that and use the elegant XML tools available; It
appears that, in this case, I cannot do that.

Thanks
Jack

Diego Medina

unread,
Dec 24, 2011, 4:08:16 PM12/24/11
to lif...@googlegroups.com

you may want to ask on the scala mailing list or stackoverflow site under the Scala tag, as it is not limited to lift.
Regards

Diego
Sent from my android cell

Naftoli Gugenheim

unread,
Jan 6, 2012, 12:09:32 AM1/6/12
to lif...@googlegroups.com
While loops return Unit. What type does createTree return? Can't you just flatMap and toSeq the iterator?

Joseph Shraibman

unread,
Jan 6, 2012, 1:11:56 AM1/6/12
to lif...@googlegroups.com
I ran into a problem like this not long ago and it took me a little while to figure it out.

I assumed I could just add NodeSeq's together, but I was getting compiler errors I didn't understand.  When I put in explicit return types for my methods I discovered that sometimes I didn't have a NodeSeq, I had a Seq[Node].  Scala was being helpful and giving me one or the other depending on what I was doing but in the end it didn't all work together.  The solution was to make all my methods return Seq[Node] (so that NodeSeq's were automatically converted) and in one place I used a NodeBuffer to add them together.

It ended up looking like this:

def getTableContents: NodeSeq = {
    val nodeBuf = new scala.xml.NodeBuffer
    nodeBuf ++=     getHeaderRow( ) getHeaderRow returns a Seq[Node]
    nodeBuf ++= data.map( oa =>  getDataRow(oa)) getDataRow returns a Node
    nodeBuf

Jack Park

unread,
Jan 6, 2012, 2:12:06 AM1/6/12
to lif...@googlegroups.com
That, for me, is new information!!!
I plan to try that soon.

Many thanks.
Jack

Reply all
Reply to author
Forward
0 new messages