【问题标题】:Dynamic Map and XML Generation in GroovyGroovy 中的动态映射和 XML 生成
【发布时间】:2014-10-23 00:16:08
【问题描述】:

我正在尝试动态生成以下 XML。它是一个元素列表(它也可以有子列表和子子列表,等等)。

<root>
  <Fault>
    <Code>100</Code>
    <Type>USER</Type>
    <DetailList>
      <DetailText>Incorrect name</DetailText>
      <DetailText>Incorrect ID</DetailText>
    </DetailList>
    <severity>ABORT</severity>
  </Fault>
  <Fault>
    <Code>200</Code>
    <Type>SYSTEM</Type>
    <DetailList>
      <DetailText>Invalid DB</DetailText>
      <DetailText>Invalid Access</DetailText>
    </DetailList>
    <severity>CRITICAL</severity>
  </Fault>
</root>

我一次只能访问一个行项目的数据源,所以我想我需要将数据存储在某种地图中。我开始创建一个动态映射来保存可以写为 XML 的项目列表,如 SO answer 中提供的那样。

这是我期望实现的结构 -

def map = [
     ["Fault": [
        "Code":"100",
        "Type":"USER",
        "DetailList" : [
            ["DetailText":"Incorrect name"],
            ["DetailText":"Incorrect ID"]
            ],
        "severity":"ABORT"
        ]],
    ["Fault": [
        "Code":"200",
        "Type":"SYSTEM",
        "DetailList" : [
            ["DetailText":"Invalid DB"],
            ["DetailText":"Invalid Access"]
            ],
        "severity":"CRITICAL"
        ]]
]

在运行时,我将动态获取这些值,所以现在这是我一直在尝试按上述方式工作的部分 -

 String root = "Fault"
 String item1 = "Code"
 String item2 = "Type"
 String nextLevel = "DetailList"
 String levelItem = "DetailText"
 String innerItem1 = "Incorrect name"
 String innerItem2 = "Incorrect ID"

 def dummyMap = { [:].withDefault{ owner.call() } }()
 def map = { [:].withDefault{ owner.call() } }()
 map.put(root, [:])
 map."$root"[item1] = "100"
 map."$root"[item2] = "USER"
 map."$root"["$nextLevel"] = [:]
 x = map."$root"["$nextLevel"]
 x."$levelItem" = innerItem1

这就是我卡住的地方。我无法弄清楚如何在同一级别的列表中添加第二项,而不覆盖第一项。

我对 Groovy 完全陌生,所以我可能没有以最好的方式来做这件事。如果有任何其他方法可以实现生成的 XML,我很乐意根据您的建议工作。

【问题讨论】:

  • 为什么不使用[XMLSlurper](http://groovy.codehaus.org/api/groovy/util/XmlSlurper.html),它会给你一个属性,比如访问xml(就像使用地图一样)?
  • 另外,“我一次只能访问一个行项目”是什么意思。它是巨大的还是你真的每个例如只得到一条线? methodcall又不能累积?还是只是被换行符和列表分割?

标签: xml groovy map soapui


【解决方案1】:

错误就在这里:

 map."$root"["$nextLevel"] = [:]
 x = map."$root"["$nextLevel"]
 x."$levelItem" = innerItem1

您正在为DetailList 创建一个地图 ([:]),但顾名思义,您需要在此处列出一个列表。所以你必须使用[] 然后在那里添加你的项目。例如

 map."$root"["$nextLevel"] = [] // list!  no map
 map."$root"."$nextLevel" << ["$itemLevel": item1] // add new maps at end of list
 map."$root"."$nextLevel" << ["$itemLevel": item2] // ...

如果您的最终目标是创建一个地图以对那里的代码进行类似“属性”的访问(例如root[0].Fault.Code),那么您也可以使用XMLSlurper,这样您就可以轻松获得类似的东西( root.Fault[0].Code.text())。

【讨论】:

  • 这对我有用。最初它失败了,因为我使用 $levelItem 作为 var 名称,而您的示例使用 $itemLevel,但是一旦我弄清楚了,效果就很好。
【解决方案2】:

如果您想向地图添加多个项目,您可以将地图设为数组地图,而不仅仅是常规地图。然后,要在同一个键下添加第二个项目,只需将其添加到数组的末尾即可。

但是,我对手动实现这一点持谨慎态度,尤其是使用地图 - 当您尝试提取数据并且项目以随机顺序而不是顺序出现时,这可能会给您带来问题你添加了它们。最好给自己找一个 XML 库。

【讨论】:

    【解决方案3】:

    如果您在 Groovy 中构建任何东西(例如 XML),您总是要使用 Builder

    def builder = new groovy.xml.MarkupBuilder()
    
    // using your variables from above!
    
    def xmlRoot = builder.root {
        "$root" {
            "$item1"(100)
            "$item2"("USER")
            "$nextLevel" {
                "$levelItem"(innerItem1)
                "$levelItem"(innerItem2)
            }
            severity("ABORT")
        }
        // repeat as necessary
    }
    

    生成:

    <root>
      <Fault>
        <Code>100</Code>
        <Type>USER</Type>
        <DetailList>
          <DetailText>Incorrect name</DetailText>
          <DetailText>Incorrect ID</DetailText>
        </DetailList>
        <severity>ABORT</severity>
      </Fault>
    </root>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-22
      • 1970-01-01
      • 1970-01-01
      • 2022-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多