在使用StreamingMarkupBuilder创建xml时,我可以使用闭包吗?

时间:2011-12-12 20:44:21

标签: xml groovy

创建xml时是否可以使用闭包?我想用一个表示站点菜单的groovy对象创建一个xml。我正在使用StreamingMarkupBuilder并且正在努力让它使用闭包(我想要递归调用),但到目前为止还没有成功。

我正在创建这样的XML:

    public menuToXml(Menu menu, def countrySpecificConfiguration) { 
            def builder = new StreamingMarkupBuilder() 
            builder.encoding = 'UTF-8' 
            def outputFile = builder.bind { 
                    mkp.xmlDeclaration() 
                    namespaces << [''] 
                    siteMenu { 
                            menu.menuItems.each menuItemToXml 
                    } 
            } 

    } 

我正在使用的封闭是:

    def menuItemToXml = { menuItem -> 
            item { 
                    logicalName(menuItem.name) 
                    controller(menuItem.controller) 
                    action(menuItem.action) 
                    enabled(menuItem.enabled.toString()) 
                    pageID(menuItem.pageID) 
                    mustBeLoggedIn(menuItem.mustBeLoggedIn.toString()) 
                    authorizedUserRoles { 
                            menuItem.authorizedUserRoles.each { user -> userRole(user) } 
                    } 
                    childItems { menuItem.childItems.each menuItemToXml } 
            } 
    } 

它一直给出以下错误(在“item {”行):

groovy.lang.MissingMethodException: No signature of method: com.ingim.flexiblecontent.service.DynamicMenuService.item() is applicable for argument types: (com.ingim.flexiblecontent.service.DynamicMenuService$_closure1_closure6) values: [com.ingim.flexiblecontent.service.DynamicMenuService$_closure1_closure6@aee1f98] 
Possible solutions: use([Ljava.lang.Object;), is(java.lang.Object), grep(java.lang.Object), with(groovy.lang.Closure), wait(), every() 
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:54) 
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:78) 
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44) 
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141) 
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149) 
        at com.ingim.flexiblecontent.service.DynamicMenuService$_closure1.doCall(DynamicMenuService.groovy:85) 
..... 

你能使用封闭装置,还是不可能?

包含闭包和调用方法的整个类:

    package com.ingim.flexiblecontent.service

import groovy.xml.*

import com.ingim.flexiblecontent.Menu

class DynamicMenuService {

    static transactional = false // not doing any transactions
    static scope = "session" // one menu per user session

    private Menu menu


    /**
     * Method to update the XML with the changes from the Menu.
     *
     */
    public menuToXml(Menu menu, def countrySpecificConfiguration) {

        def builder = new StreamingMarkupBuilder()
        builder.encoding = 'UTF-8'
        def outputFile = builder.bind {
            mkp.xmlDeclaration()
            namespaces << ['']
            siteMenu {
                menu.menuItems.each  {
                    println it.dump().toString()
                    menuItemToXml it
                }
            }
        }
        println XmlUtil.serialize(outputFile)
    }
    /**
     * Closure to create XML from a menu item. Through recursive call creates child menu item(s) if present
     * This can be multiple levels deep.
     *
     * @param  menuItem  the current menuItem
     *
     * @return the created XML
     */
    def menuItemToXml = { menuItem ->
        item {
            logicalName(menuItem.name)
            controller(menuItem.controller)
            action(menuItem.action)
            enabled(menuItem.enabled.toString())
            pageID(menuItem.pageID)
            mustBeLoggedIn(menuItem.mustBeLoggedIn.toString())
            authorizedUserRoles {
                menuItem.authorizedUserRoles.each { user -> userRole(user) }
            }
            childItems { menuItem.childItems.each menuItemToXml }
        }
    }

}

我正在使用的其他常规课程:

package com.ingim.flexiblecontent
class Menu {

  def menuItems = []
  def currentMenuItem // for storing the current menu item

  public setMenuItems(def menuItems) {
      this.menuItems = menuItems
  }

}

package com.ingim.flexiblecontent
public class MenuItem {
    String name
    String controller
    String action
    boolean enabled
    String pageID
    boolean mustBeLoggedIn
    def authorizedUserRoles = []

    def childItems = [] //list of menu items
}

我正在使用以下方法进行测试:

void testMenuToXml() {
    def menuService = new DynamicMenuService()
    def menu = new Menu(menuItems: [
        new MenuItem(name: 'menuItem1', controller: 'controller1', action: 'action1', enabled: true, pageID: '1', mustBeLoggedIn: true, authorizedUserRoles: ['role1', 'role2']),
        new MenuItem(name: 'menuItem2', controller: 'controller2', action: 'action2', enabled: true, pageID: '2', mustBeLoggedIn: false, authorizedUserRoles: ['role1', 'role2'], childItems: [
            new MenuItem(name: 'menuItem2a', controller: 'controller2a', action: 'action2a', enabled: true, pageID: '3', mustBeLoggedIn: true, authorizedUserRoles: ['role1']),
            new MenuItem(name: 'menuItem2b', controller: 'controller2b', action: 'action2b', enabled: true, pageID: '4', mustBeLoggedIn: false, authorizedUserRoles: ['role2'])
        ])
    ])


    def xml = '''<?xml version="1.0" encoding="UTF-8"?>
    <countrySpecificConfiguration>
        <country>BE</country>
        <supportedLanguages>
            <language>NL</language>
            <language>FR</language>
        </supportedLanguages>
        <siteMenu>
            <item>
            </item>
        </siteMenu>
    </countrySpecificConfiguration>'''

    def config = new XmlSlurper().parseText(xml)

    menuService.menuToXml(menu, config)

}

2 个答案:

答案 0 :(得分:0)

这有用吗?

menu.menuItems.each { menuItemToXml it }

而不是:

menu.menuItems.each menuItemToXml 

很难说它是否适用于您的情况,因为您没有提供运行失败示例所需的所有信息......

答案 1 :(得分:0)

所以我可能会感到困惑,但我不认为你可以在你的“menuItemToXml”闭包中使用DSL。 builder.bind方法允许您使用DSL,但不能在您自己的闭包中使用。 因此,请尝试将所有{和}更改为地图符号[:]

即。 :item {---&gt;&gt;&gt;项目:[