【问题标题】:Transform XML elements of the same name into JSON properties of the same name将同名的 XML 元素转换为同名的 JSON 属性
【发布时间】:2017-12-01 22:43:57
【问题描述】:

同名的 XML 元素和 JSON 属性可能是同级的。即:

<container>
  <value>value1</value>
  <value>value2</value>
</container>

object-node {
  "value" : "value1",
  "value" : "value2"
}

都是有效的,但我还没有找到一种有效的方法将一个转换为另一个。在 object-node 构造函数中动态构建属性是无效的,即:

object-node {
  for $v in $values
  return 'value' : $v
}

使用映射不起作用,因为重复的键名已折叠:

xdmp:to-json(map:new((
  map:entry("value", "value1"), 
  map:entry("value", "value2")))
  )

=> {"value":"value2"}

而在使用json:object时,最后一个键值是重复的:

json:object(<json:object>
  <json:entry key="value">
    <json:value>value1</json:value>
  </json:entry>
  <json:entry key="value">
    <json:value>value2</json:value>
  </json:entry>
</json:object>)

=> {"value":"value2", "value":"value2"}

使用+ 运算符连接映射更好,但它会将重复的键合并为一个带有值数组的单个键 ({"value":["value1", "value2"]}),这仍然不是我想要的。有没有办法在 XQuery 中动态构建同名的同级 JSON 属性?

【问题讨论】:

  • 我同意 Michael Kay 的观点,并建议避免使用非唯一的属性名称。有一些方法可以让它工作,但稍后您会得到一些副作用,例如一旦保存在 MarkLogic 数据库中,更新具有非唯一属性的 JSON 文档可能会遇到困难。
  • @grtjn 是的,我同意这似乎是正确的做法。但是,MarkLogic 明确允许这种行为,而其他人似乎没有。处理重复的属性名称本来可以方便地使转换后的 JSON 文档在结构上更接近其 XML 等价物,但我会解决它。
  • MarkLogic 只容忍它,因为它不喜欢数据丢失,但这并不意味着它不介意。如前所述,您可以使用非唯一属性持久化 JSON,但每次触摸 JSON 时都必须小心处理它的方式。虽然xdmp:unquote 允许解析非唯一属性,但xdmp:from-json-string 不允许,并且会抛出错误。

标签: json xquery marklogic marklogic-8


【解决方案1】:

您的 JSON 示例:

object-node {
  "value" : "value1",
  "value" : "value2"
}

不是真的有效:或者无论如何,最好避免。 RFC 7159 说:

当对象中的名称不唯一时, 接收此类对象的软件是不可预测的。许多 实现仅报告姓氏/值对。其他 实现报告错误或无法解析对象,并且 一些实现报告所有的名称/值对,包括 重复。

【讨论】:

  • 谢谢迈克尔。我对什么是有效 JSON 的假设是基于 MarkLogic 特定的行为。 FF、Safari、Chrome 和 eXist-db 中的等效 JSON 构造函数都导致相同的行为:仅报告最后一个键/值对(Safari 会抛出异常,除了创建变量)。
【解决方案2】:

我不认为可以在 object-node() 构造函数中嵌入 FLWOR。

您可以构造一个字符串并使用xdmp:eval()xdmp:value() 进行评估:

let $container := 
    <container>
      <value>value1</value>
      <value>value2</value>
    </container>

return
  xdmp:value(
   "object-node {" || 
     fn:string-join($container/value ! ('"' || local-name() || '": "' || . || '"'), ",") || 
   " }"
  )

或者构建 JSON 字符串并使用 xdmp:unquote():

let $container := 
    <container>
      <value>value1</value>
      <value>value2</value>
    </container>

return
  xdmp:unquote(
   "{" || 
     fn:string-join($container/value ! ('"' || local-name() ||'": "' || . || '"'), ",") || 
   "}"
  )

【讨论】:

  • xdmp:eval 很慢,xdmp:value 会更快。如果您无论如何要生成一个字符串,请考虑构建一个 JSON 字符串,并使用xdmp:unquote 对其进行解析。不过,我仍然不推荐非唯一属性.. :)
猜你喜欢
  • 1970-01-01
  • 2021-07-23
  • 1970-01-01
  • 2017-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
相关资源
最近更新 更多