This page is no longer maintained — Please continue to the home page at www.scala-lang.org

How to perform modification/insertions to an existing XML sub-tree?

9 replies
tolsen77
Joined: 2008-10-08,
User offline. Last seen 1 year 38 weeks ago.
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?
David Pollak
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: How to perform modification/insertions to an existing XML s


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp
tolsen77
Joined: 2008-10-08,
User offline. Last seen 1 year 38 weeks ago.
Re: How to perform modification/insertions to an existing XML s
Figured what I actually need is an XML DOM so I'm currently just changing it to use Java instead.

Doesn't "DOM" manipulation of Scala's XML become very verbose when xml sub-trees get passed into other functions and you need to track changes for the root node?

On Thu, Jan 8, 2009 at 3:58 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

David Pollak
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: How to perform modification/insertions to an existing XML s


On Thu, Jan 8, 2009 at 6:57 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Figured what I actually need is an XML DOM so I'm currently just changing it to use Java instead.

Doesn't "DOM" manipulation of Scala's XML become very verbose when xml sub-trees get passed into other functions and you need to track changes for the root node?

No.  There's a package that allows you to transform Scala XML documents.  It's rather concise, especially with pattern matching.  You don't do any of the work, the work is done for you.  You just identify the nodes to be changes (old -> new) and everything else is done for you.
Thanks,
David 


On Thu, Jan 8, 2009 at 3:58 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp




--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp
tolsen77
Joined: 2008-10-08,
User offline. Last seen 1 year 38 weeks ago.
Re: How to perform modification/insertions to an existing XML s
Are there any good tutorials available for this kind of XML manipulation?


A quick example of what I was thinking about:

import scala.xml

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
       
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
            book(xmlBook)
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction") match
    {
        case "add" => {
            // Update status attribute for this xml entry.
            // Add another xml entry.
        }
        case "remove" => {
            // Remove this xml entry.
        }
    }
}

For me to make changes in book(), wouldn't that require addional changes to books() and test()?


On Fri, Jan 9, 2009 at 4:41 AM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Thu, Jan 8, 2009 at 6:57 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Figured what I actually need is an XML DOM so I'm currently just changing it to use Java instead.

Doesn't "DOM" manipulation of Scala's XML become very verbose when xml sub-trees get passed into other functions and you need to track changes for the root node?

No.  There's a package that allows you to transform Scala XML documents.  It's rather concise, especially with pattern matching.  You don't do any of the work, the work is done for you.  You just identify the nodes to be changes (old -> new) and everything else is done for you.
Thanks,
David 


On Thu, Jan 8, 2009 at 3:58 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp




--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

tolsen77
Joined: 2008-10-08,
User offline. Last seen 1 year 38 weeks ago.
Re: How to perform modification/insertions to an existing XML s
A bit too quick.. updated code:

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
      
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
        {
            (xmlBook \ "@instruction").text match
            {
                case "remove" => // Remove this xml entry
                case _ => book(xmlBook)
            }
        }
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction").text match
    {
        case "add" => {
            // Update status attribute for this xml entry.
        }
    }
}


On Fri, Jan 9, 2009 at 5:23 AM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Are there any good tutorials available for this kind of XML manipulation?


A quick example of what I was thinking about:

import scala.xml

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
       
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
            book(xmlBook)
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction") match
    {
        case "add" => {
            // Update status attribute for this xml entry.
            // Add another xml entry.
        }
        case "remove" => {
            // Remove this xml entry.
        }
    }
}

For me to make changes in book(), wouldn't that require addional changes to books() and test()?


On Fri, Jan 9, 2009 at 4:41 AM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Thu, Jan 8, 2009 at 6:57 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Figured what I actually need is an XML DOM so I'm currently just changing it to use Java instead.

Doesn't "DOM" manipulation of Scala's XML become very verbose when xml sub-trees get passed into other functions and you need to track changes for the root node?

No.  There's a package that allows you to transform Scala XML documents.  It's rather concise, especially with pattern matching.  You don't do any of the work, the work is done for you.  You just identify the nodes to be changes (old -> new) and everything else is done for you.
Thanks,
David 


On Thu, Jan 8, 2009 at 3:58 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp




--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp


Viktor Klang
Joined: 2008-12-17,
User offline. Last seen 1 year 27 weeks ago.
Re: How to perform modification/insertions to an existing XML s
Ever considered the exotic act of "returning" values?

On Fri, Jan 9, 2009 at 5:38 AM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
A bit too quick.. updated code:

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
      
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
        {
            (xmlBook \ "@instruction").text match
            {
                case "remove" => // Remove this xml entry
                case _ => book(xmlBook)
            }
        }
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction").text match
    {
        case "add" => {
            // Update status attribute for this xml entry.
        }
    }
}


On Fri, Jan 9, 2009 at 5:23 AM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Are there any good tutorials available for this kind of XML manipulation?


A quick example of what I was thinking about:

import scala.xml

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
       
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
            book(xmlBook)
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction") match
    {
        case "add" => {
            // Update status attribute for this xml entry.
            // Add another xml entry.
        }
        case "remove" => {
            // Remove this xml entry.
        }
    }
}

For me to make changes in book(), wouldn't that require addional changes to books() and test()?


On Fri, Jan 9, 2009 at 4:41 AM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Thu, Jan 8, 2009 at 6:57 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Figured what I actually need is an XML DOM so I'm currently just changing it to use Java instead.

Doesn't "DOM" manipulation of Scala's XML become very verbose when xml sub-trees get passed into other functions and you need to track changes for the root node?

No.  There's a package that allows you to transform Scala XML documents.  It's rather concise, especially with pattern matching.  You don't do any of the work, the work is done for you.  You just identify the nodes to be changes (old -> new) and everything else is done for you.
Thanks,
David 


On Thu, Jan 8, 2009 at 3:58 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp




--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp





--
Viktor Klang
Senior Systems Analyst
tolsen77
Joined: 2008-10-08,
User offline. Last seen 1 year 38 weeks ago.
Re: How to perform modification/insertions to an existing XML s
Yes, I see now how you return the updated xml to preserve immutability (and I guess error detection with null), but I was hoping for someone to help with code examples for attribute change and updates within a for loop.

On Fri, Jan 9, 2009 at 9:31 AM, Viktor Klang <viktor [dot] klang [at] gmail [dot] com> wrote:
Ever considered the exotic act of "returning" values?

On Fri, Jan 9, 2009 at 5:38 AM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
A bit too quick.. updated code:

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
      
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
        {
            (xmlBook \ "@instruction").text match
            {
                case "remove" => // Remove this xml entry
                case _ => book(xmlBook)
            }
        }
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction").text match
    {
        case "add" => {
            // Update status attribute for this xml entry.
        }
    }
}


On Fri, Jan 9, 2009 at 5:23 AM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Are there any good tutorials available for this kind of XML manipulation?


A quick example of what I was thinking about:

import scala.xml

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
       
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
            book(xmlBook)
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction") match
    {
        case "add" => {
            // Update status attribute for this xml entry.
            // Add another xml entry.
        }
        case "remove" => {
            // Remove this xml entry.
        }
    }
}

For me to make changes in book(), wouldn't that require addional changes to books() and test()?


On Fri, Jan 9, 2009 at 4:41 AM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Thu, Jan 8, 2009 at 6:57 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Figured what I actually need is an XML DOM so I'm currently just changing it to use Java instead.

Doesn't "DOM" manipulation of Scala's XML become very verbose when xml sub-trees get passed into other functions and you need to track changes for the root node?

No.  There's a package that allows you to transform Scala XML documents.  It's rather concise, especially with pattern matching.  You don't do any of the work, the work is done for you.  You just identify the nodes to be changes (old -> new) and everything else is done for you.
Thanks,
David 


On Thu, Jan 8, 2009 at 3:58 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp




--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp





--
Viktor Klang
Senior Systems Analyst

David Pollak
Joined: 2008-12-16,
User offline. Last seen 42 years 45 weeks ago.
Re: How to perform modification/insertions to an existing XML s
Trond,

You cannot change an immutable data structure.  You must return a transformed version of the data structure from a method.  In the event of a potential logical failure (there is none in this case), the return type from your method would be Option[T] (where T is the type of the thing).  If there's a logic failure, you'll return None.  If there's no logical failure, you'll return Some(transformed value).

Also, there's no "for loop" in Scala.  There's a "for comprehension."  While it may seem to be word games, the conceptual difference between Java's flow of control oriented "for loop" and Scala's transformation oriented "for comprehension" is huge.  More on that in another post, although you can get a flavor of what I'm talking about at: http://blog.lostlake.org/index.php?/archives/50-The-Scala-Option-class-and-how-lift-uses-it.html

In terms of your code, here's a working Scala sample.  Note, there are no looping constructs.  You declare rules for transforming nodes into other nodes and those rules are applied to an XML object.

I hope this helps you understand a bit more of the immutable approach.

Thanks,

David

import scala.xml._
import scala.xml.transform._

def test(): NodeSeq = {
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
     
   books(xmlBooks)
}

def books(xmlBooks: Elem): NodeSeq = {
  val removeIt = new RewriteRule {
    override def transform(n: Node): NodeSeq = n match {
      case e: Elem if (e \ "@instruction").text == "remove" =>
    NodeSeq.Empty

      case n => n
    }
  }

  val addIt = new RewriteRule {
    override def transform(n: Node): NodeSeq = n match {
      case e: Elem if (e \ "@instruction").text == "add" =>
    new Elem(e.prefix, e.label,
         e.attributes.remove("instruction"),
         e.scope,
         transform(e.child) ++ <added>I added this</added> :_*)
     
      case n => n
    }
  }

  val transformer = new RuleTransformer(removeIt , addIt)

  transformer.transform(xmlBooks)
}

println(test())


On Thu, Jan 8, 2009 at 8:38 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
A bit too quick.. updated code:

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
      
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
        {
            (xmlBook \ "@instruction").text match
            {
                case "remove" => // Remove this xml entry
                case _ => book(xmlBook)
            }
        }
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction").text match
    {
        case "add" => {
            // Update status attribute for this xml entry.
        }
    }
}


On Fri, Jan 9, 2009 at 5:23 AM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Are there any good tutorials available for this kind of XML manipulation?


A quick example of what I was thinking about:

import scala.xml

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
       
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
            book(xmlBook)
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction") match
    {
        case "add" => {
            // Update status attribute for this xml entry.
            // Add another xml entry.
        }
        case "remove" => {
            // Remove this xml entry.
        }
    }
}

For me to make changes in book(), wouldn't that require addional changes to books() and test()?


On Fri, Jan 9, 2009 at 4:41 AM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Thu, Jan 8, 2009 at 6:57 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Figured what I actually need is an XML DOM so I'm currently just changing it to use Java instead.

Doesn't "DOM" manipulation of Scala's XML become very verbose when xml sub-trees get passed into other functions and you need to track changes for the root node?

No.  There's a package that allows you to transform Scala XML documents.  It's rather concise, especially with pattern matching.  You don't do any of the work, the work is done for you.  You just identify the nodes to be changes (old -> new) and everything else is done for you.
Thanks,
David 


On Thu, Jan 8, 2009 at 3:58 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp




--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp





--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp
tolsen77
Joined: 2008-10-08,
User offline. Last seen 1 year 38 weeks ago.
Re: How to perform modification/insertions to an existing XML s
Thank you this example. What confused me was how to do XML pattern matching and transforming (knowing what to ask for) the XML. I'm still resisting Option, hehe.

On Fri, Jan 9, 2009 at 7:08 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:
Trond,

You cannot change an immutable data structure.  You must return a transformed version of the data structure from a method.  In the event of a potential logical failure (there is none in this case), the return type from your method would be Option[T] (where T is the type of the thing).  If there's a logic failure, you'll return None.  If there's no logical failure, you'll return Some(transformed value).

Also, there's no "for loop" in Scala.  There's a "for comprehension."  While it may seem to be word games, the conceptual difference between Java's flow of control oriented "for loop" and Scala's transformation oriented "for comprehension" is huge.  More on that in another post, although you can get a flavor of what I'm talking about at: http://blog.lostlake.org/index.php?/archives/50-The-Scala-Option-class-and-how-lift-uses-it.html

In terms of your code, here's a working Scala sample.  Note, there are no looping constructs.  You declare rules for transforming nodes into other nodes and those rules are applied to an XML object.

I hope this helps you understand a bit more of the immutable approach.

Thanks,

David

import scala.xml._
import scala.xml.transform._

def test(): NodeSeq = {
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
     
   books(xmlBooks)
}

def books(xmlBooks: Elem): NodeSeq = {
  val removeIt = new RewriteRule {
    override def transform(n: Node): NodeSeq = n match {
      case e: Elem if (e \ "@instruction").text == "remove" =>
    NodeSeq.Empty

      case n => n
    }
  }

  val addIt = new RewriteRule {
    override def transform(n: Node): NodeSeq = n match {
      case e: Elem if (e \ "@instruction").text == "add" =>
    new Elem(e.prefix, e.label,
         e.attributes.remove("instruction"),
         e.scope,
         transform(e.child) ++ <added>I added this</added> :_*)
     
      case n => n
    }
  }

  val transformer = new RuleTransformer(removeIt , addIt)

  transformer.transform(xmlBooks)
}

println(test())


On Thu, Jan 8, 2009 at 8:38 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
A bit too quick.. updated code:

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
      
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
        {
            (xmlBook \ "@instruction").text match
            {
                case "remove" => // Remove this xml entry
                case _ => book(xmlBook)
            }
        }
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction").text match
    {
        case "add" => {
            // Update status attribute for this xml entry.
        }
    }
}


On Fri, Jan 9, 2009 at 5:23 AM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Are there any good tutorials available for this kind of XML manipulation?


A quick example of what I was thinking about:

import scala.xml

def test()
{
    val xmlBooks =
        <books instruction="update">
        <book instruction="remove" name="book1" status=""/>
        <book instruction="add" name="book2" status=""/>
        </books>
       
   books(xmlBooks)

   // How do I get the updated xml here?
}

def books(xmlBooks: xml.Elem)
{
    if ((xmlBooks \ "@instruction").text == "update")
    {
        for (xmlBook <- xmlBooks if (xmlBook \ "@instruction").isEmpty == false)
            book(xmlBook)
    }
}

def book(xmlBook: xml.Elem)
{
    (xmlBook \ "@instruction") match
    {
        case "add" => {
            // Update status attribute for this xml entry.
            // Add another xml entry.
        }
        case "remove" => {
            // Remove this xml entry.
        }
    }
}

For me to make changes in book(), wouldn't that require addional changes to books() and test()?


On Fri, Jan 9, 2009 at 4:41 AM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Thu, Jan 8, 2009 at 6:57 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
Figured what I actually need is an XML DOM so I'm currently just changing it to use Java instead.

Doesn't "DOM" manipulation of Scala's XML become very verbose when xml sub-trees get passed into other functions and you need to track changes for the root node?

No.  There's a package that allows you to transform Scala XML documents.  It's rather concise, especially with pattern matching.  You don't do any of the work, the work is done for you.  You just identify the nodes to be changes (old -> new) and everything else is done for you.
Thanks,
David 


On Thu, Jan 8, 2009 at 3:58 PM, David Pollak <feeder [dot] of [dot] the [dot] bears [at] gmail [dot] com> wrote:


On Wed, Jan 7, 2009 at 11:17 PM, Trond Olsen <tolsen77 [at] gmail [dot] com> wrote:
My problem: I have to do modifications of sub-trees in my existing XML tree, like adding child nodes or modifying attributes.

In the "Updates and Queries" chapter of http://burak.emir.googlepages.com/scalaxbook.docbk.html is says that XML nodes are immutable. Does that mean that in any existing XML tree, modification of a sub-tree required a full copy of the entire XML tree?

No, it requires a copy from the modified node to the root node.  This is an O(log n) operation.


--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp




--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp





--
Lift, the simply functional web framework http://liftweb.net
Collaborative Task Management http://much4.us
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland