Динамическое добавление нескольких элементов/контейнеров XML с помощью XML MarkupBuilder в Groovy

Я пытаюсь сгенерировать XML с помощью Groovy MarkupBuilder.

Необходимый XML имеет следующую форму (упрощенную):

<Order>
  <StoreID />
  <City />
  <Items>
    <Item>
      <ItemCode />
      <UnitPrice />
      <Quantity />
    </Item>
  </Items>
</Order>

Данные хранятся в файле Excel и легко доступны. Мой скрипт Groovy анализирует Excel и генерирует XML.

e.g.

import groovy.xml.*
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)

xml.Order{
  StoreID("Store1")
  City("New York")
  Items(){
    Item(){
      ItemCode("LED_TV")
      UnitPrice("800.00")
      Quantity("2")
    }
  }
}

Внутри «предметов» может быть несколько контейнеров «предмет».

Мой вопрос: скажем, мы хотим сгенерировать заказ XML с 10 элементами. Есть ли способ написать что-то вроде цикла for внутри контейнера "items"? Таким образом, нам не нужно будет писать код MarkupBuilder для 10 разных элементов.

Существует аналогичный вопрос Добавление динамических элементов и атрибутов в groovy MarkupBuilder или StreamingMarkupBuilder. Но это не обсуждает зацикливание.


person CodeVenture    schedule 02.08.2013    source источник


Ответы (2)


Да, есть способ использовать цикл. Расширение вашего примера здесь:

import groovy.xml.*
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)

//List of items represented as a map
def items = [[itemCode: "A", unitPrice: 10, quantity: 2], 
             [itemCode: "B", unitPrice: 20, quantity: 3], 
             [itemCode: "C", unitPrice: 30, quantity: 4], 
             [itemCode: "D", unitPrice: 40, quantity: 6], 
             [itemCode: "E", unitPrice: 50, quantity: 5]]

xml.Order{
  StoreID("Store1")
  City("New York")
  Items{
    //Loop through the list.
    //make sure you are using a variable name instead of using "it"
    items.each{item->
      Item{
        ItemCode(item.itemCode)
        UnitPrice(item.unitPrice)
        Quantity(item.quantity)
      }
    }
  }
}

println writer

Должен дать вам то, что вы ожидаете.

person dmahapatro    schedule 02.08.2013
comment
Понимаю. Таким образом, мы МОЖЕМ написать обычный код цикла Groovy внутри разметки. Я думал, что разметка не должна содержать ничего, кроме кода разметки. Спасибо за подробный ответ. Ценить это! :) - person CodeVenture; 02.08.2013
comment
Спасибо за предложение. это помогает мне много усилий. - person Tung; 19.09.2016
comment
Спасибо за отличный ответ! Будучи новичком в Groovy, я много искал, пока не нашел это! - person eerriicc; 30.11.2016

Этот вклад помог мне решить аналогичную проблему: я хотел вызывать функции в блоках MarkupBuilder, например функцию addElement() в моем примере.

Я хотел разделить код на разные функции.

Пример вызова функций в блоках MarkupBuilder:

static void addElement(Map<String,String> elements, MarkupBuilder mb) {
    mb."${elements.tag}"(elements.content)
}

static void example() {
    def writer = new StringWriter()
    def htmlBuilder = new MarkupBuilder(writer)

    String tag = "a"
    Map<String, String> attributes1 = new HashMap<>()
    attributes1.put("href","http://address")
    String content1 = "this is a link"

    Map<String, String> element1 = new HashMap<>()
    element1.put("tag","b")
    element1.put("content","bold content 1")

    Map<String, String> element2 = new HashMap<>()
    element2.put("tag","b")
    element2.put("content","bold content 2")

    List<Map<String, String>> elements = new ArrayList<>()
    elements.add(element1)
    elements.add(element2)

    htmlBuilder."html" {
        "${tag}"( attributes1, content1 )
        elements.each { contentIterator ->
            addElement(contentIterator, htmlBuilder)
        }
    }

    println writer
 }

и он производит этот вывод:

<html>
  <a href='http://address'>this is a link</a>
  <b>bold content 1</b>
  <b>bold content 2</b>
</html>
person Andre Rolfs    schedule 14.07.2018