Search code examples
xmlscalascala-xml

Parsing with scala-xml API with multiple attributes


I have XML that I'm trying to use Scala XML API. I have XPath queries to retrieve the data from the XML tags. I want to retrieve <price> tag value from <market> but using the two attributes _id and type. I want to write a condition with && so that I'll get a unique value for each price tag, e.g. where MARKET _ID = 1 && TYPE = "A".

For reference find XML below:

<publisher>
    <book _id = "0"> 
        <author _id="0">Dev</author>
        <publish_date>24 Feb 1995</publish_date>
        <description>Data Structure - C</description>
        <market _id="0" type="A">
            <price>45.95</price>            
        </market>
        <market _id="0" type="B">
            <price>55.95</price>
        </market>
    </book>
    <book _id="1"> 
        <author _id = "1">Ram</author>
        <publish_date>02 Jul 1999</publish_date>
        <description>Data Structure - Java</description>
        <market _id="1" type="A">
            <price>145.95</price>           
        </market>   
        <market _id="1" type="B">
            <price>155.95</price>           
        </market>
    </book>
</publisher>

The following code is working fine

import scala.xml._

object XMLtoCSV extends App {

  val xmlLoad = XML.loadFile("C:/Users/sharprao/Desktop/FirstTry.xml")  

  val price = (((xmlLoad \ "book" filter { _ \ "@_id" exists (_.text == "0")}) \ "market" filter { _ \ "@_id" exists (_.text == "0")}) \ "price").text  //45.95
  val price1 = (((xmlLoad \ "book" filter { _ \ "@_id" exists (_.text == "1")}) \ "market" filter { _ \ "@_id" exists (_.text == "1")}) \ "price").text  //155.95

  println("price = " + price)
  println("price1 = " + price1)
} 

The output is:

price = 45.9555.95
price1 = 145.95155.95

My above code is giving me both the values as I'm not able to put && conditions.

  1. Please advice other than filter what SCALA function I can use.
  2. Also let me know how to get the all attribute names.
  3. If possible please let me know from where I can read all these APIs.

Thanks in Advance.


Solution

  • You could write a custom predicate to check multiple attributes:

    def checkMarket(marketId: String, marketType: String)(node: Node): Boolean = {
      node.attribute("_id").exists(_.text == marketId) &&
      node.attribute("type").exists(_.text == marketType)
    }
    

    Then use it as a filter:

    val price1 = (((xmlLoad \ "book" filter (_ \ "@_id" exists (_.text == "0"))) \ "market" filter checkMarket("0", "A")) \ "price").text
    // 45.95
    
    val price2 = (((xmlLoad \ "book" filter (_ \ "@_id" exists (_.text == "1"))) \ "market" filter checkMarket("1", "B")) \ "price").text
    // 155.95