【问题标题】:How to get Child elements in Karate framework如何在空手道框架中获取子元素
【发布时间】:2018-05-16 06:08:40
【问题描述】:

我需要从一个 api 的响应中提取子元素,然后将其动态传递给下一个 api 请求。

假设我有以下 xml:

* def foo =
"""
<records>
  <record index="1">a</record>
  <record index="2">b</record>
  <record index="3" foo="bar">c</record>
</records>
"""

我只想提取这个:

  <record index="1">a</record>
  <record index="2">b</record>
  <record index="3" foo="bar">c</record>

我尝试了以下选项,但都没有成功:

* def chk = foo//records/*
* def chk = foo//records/child::*
* def chk = foo//records/descendant::*
* print chk

打印后,我得到以下内容,如果我遗漏了什么或任何其他方法,请提出建议。谢谢!

13:51:07.046 INFO  - [print] {
  "records": {
    "record": [
      {
        "_": "a",
        "@": {
          "index": "1"
        }
      },
      {
        "_": "b",
        "@": {
          "index": "2"
        }
      },
      {
        "_": "c",
        "@": {
          "foo": "bar",
          "index": "3"
        }
      }
    ]
  }
}

【问题讨论】:

    标签: karate


    【解决方案1】:

    编辑:如果您需要做的只是获取一组元素并将它们填充到另一个 XML 模板中,那么看起来简单的字符串替换就可以解决问题: (我将在此答案末尾留下原始较长的答案以供参考)

    * def foo =
    """
    <records>
      <record index="1">a</record>
      <record index="2">b</record>
      <record index="3" foo="bar">c</record>
    </records>
    """
    * replace foo.<records> = ''
    * replace foo.</records> = ''
    # you can do def bar = read('template.txt') in your case
    * text bar = 
    """
    <after new="namespace">
      @@foo@@
    </after>
    """
    * replace bar.@@foo@@ = foo
    * xml bar = bar
    * match bar ==
    """
    <after new="namespace">
      <record index="1">a</record>
      <record index="2">b</record>
      <record index="3" foo="bar">c</record>
    </after>
    """
    

    是的,Karate 本身不支持 XML 节点列表,通常您不需要它。 XML 有这样一个特性,你总是需要一个“父”或“包装”元素。

    正如您在上面看到的,您确实拥有所有需要的信息。我仍然不清楚您需要将哪种 XML 传递给下一个 API - 但无论如何,空手道有一种方法。这里有 2 个选项。首先,遍历数据并手动发出 XML:

    * def foo =
    """
    <records>
      <record index="1">a</record>
      <record index="2">b</record>
      <record index="3" foo="bar">c</record>
    </records>
    """
    
    * json records = foo.records.record
    * def temp = <bar></bar>
    * def fun = 
    """
    function(r, i){ 
      karate.set('temp', '/bar/record[' + (i+1) + ']', r._); 
      karate.set('temp', '/bar/record[' + (i+1) + ']/@index', r['@'].index); 
    }
    """
    * eval karate.forEach(records, fun)
    * match temp == 
    """
    <bar>
      <record index="1">a</record>
      <record index="2">b</record>
      <record index="3">c</record>
    </bar>
    """
    

    请注意,karate.forEach 仅在即将推出的 0.8.0 中可用,但您可以尝试 0.8.0.RC3

    这是另一个有趣的选项,如果您只需要更改 XML 父级,那么字符串替换就可以解决问题:

    * replace foo.<records> = '<bar>'
    * replace foo.</records> = '</bar>'
    * xml bar = foo
    * match bar ==
    """
    <bar>
      <record index="1">a</record>
      <record index="2">b</record>
      <record index="3" foo="bar">c</record>
    </bar>
    """
    

    【讨论】:

    • 感谢您一如既往的快速回复!我希望这是因为父元素的命名空间在后续请求中发生变化,我编写了一个 js 函数并像这样使用它: * def resp = get response //*[local-name()="records"] * xmlstring holder = resp * xml newRecords= replacer (holder,/n1/g,"n2")
    • @nagpai 我会说你在正确的轨道上使用字符串替换。但set 不会工作* set response /records/@foo = 'bar'
    • 附加信息:在 nextrequest.xml 中,这被定义为 #(newRecords)。我想以某种方式避免这种命名空间替换,因为我从具有所需名称空间的文件中读取请求,然后空手道可以根据之前的响应替换子元素(计数不是静态的)。
    • @nagpai 那么空手道字符串replace 可能是解决方案。您已经知道如何将 xml 转换为字符串。获取该字符串并在另一个字符串中使用占位符:github.com/intuit/karate#replace,如果需要,转换回 xml
    • 谢谢彼得,这更简单了。
    猜你喜欢
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多