以XMl格式迭代API响应并收集数据

时间:2017-07-13 13:02:03

标签: groovy

我有一个关于如何遍历XML API响应并收集数据的问题。

假设我收到了XML格式的API回复。回复看起来像这样;

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <SearchRS>
      <SearchStatus>SUCCESS</SearchStatus>
      <Itinerary>
           <DisplayTotal>189.41</DisplayTotal>  
           <FareStarProfileID>11PUB2</FareStarProfileID>
      </Itinerary>
      <Itinerary>
            <DisplayTotal>19.41</DisplayTotal>  
            <FareStarProfileID>11PUB3</FareStarProfileID>
      </Itinerary>
      <Itinerary>
            <DisplayTotal>79.11</DisplayTotal>  
            <FareStarProfileID>11PUB8</FareStarProfileID>
      </Itinerary>
      <Itinerary>
           <DisplayTotal>89.61</DisplayTotal>   
           <FareStarProfileID>11PUB4</FareStarProfileID>
      </Itinerary>
 </SearchRS>

现在我可以遍历这些门票并轻松完成诸如找到最高价,最低价和平均价,获取每个地点的总数等等,方法是:

 def doc = new XmlSlurper().parseText(xmlResponse)
 doc.Ticket.each { Ticket ->
     // for each ticket in the xml response
     Ticket.children().each { tag ->
          // for each tag within each ticket
          switch(tag.name()) {
               case "Price":
                    [compute some stuff here]
               case "Location":
                    [compute some stuff here]
          etc....

如果我想找出每个FareStarProfileId最便宜的DisplayTotal,我的问题是什么?最简单的方法是什么?

1 个答案:

答案 0 :(得分:0)

所以给出了一些像这样的XML:

def xmlResponse = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <SearchRS>
      <SearchStatus>SUCCESS</SearchStatus>
      <Itinerary>
           <DisplayTotal>189.41</DisplayTotal>  
           <FareStarProfileID>11PUB2</FareStarProfileID>
      </Itinerary>
      <Itinerary>
            <DisplayTotal>19.41</DisplayTotal>  
            <FareStarProfileID>11PUB3</FareStarProfileID>
      </Itinerary>
      <Itinerary>
            <DisplayTotal>79.11</DisplayTotal>  
            <FareStarProfileID>11PUB8</FareStarProfileID>
      </Itinerary>
      <Itinerary>
           <DisplayTotal>89.61</DisplayTotal>   
           <FareStarProfileID>11PUB4</FareStarProfileID>
      </Itinerary>
 </SearchRS>'''

您可以使用groupBymin来实现此目标:

def doc = new XmlSlurper().parseText(xmlResponse)

// Group Itinerary by profile text, then for each profile, just keep
// the lowest price one
def minTotals = doc.Itinerary.groupBy { it.FareStarProfileID.text() }
                   .collectEntries { profile, nodes ->
                       [profile, nodes.min { it.DisplayTotal.text() as Double }]
                   }

// minTotals is a map of FareStarProfileID -> xml node representing the itinerary...
// Lets print them out
minTotals.each { profile, minimum ->
    println "For profile $profile, the minimum is ${minimum.DisplayTotal}"
}

对于Groovy 2.0.8

你无法在2.0.8中使用NodeChildren,所以你必须切换到使用inject代替groupBy

def minTotals = doc.Itinerary
        .inject([:].withDefault { [] }) { map, it ->
            map[it.FareStarProfileID.text()] << it
            map
        }
        .collectEntries { profile, nodes ->
           [profile, nodes.min { it.DisplayTotal.text() as Double }]
        }