Frage

I need to create a specificly formatted document from a map

I have the following code:

declare function local:buid-map-doc(
  $wijk as xs:string,
  $wm as map:map) as element()
{  
  let $a := for $k in map:keys($wm)
              let $v := map:get($wm,$k)
              return element x {$v}
  return <y>{$a}</y>
};

let $wijk := "101101"
let $wm := map:map()
let $p := map:put($wm, "cat1:::k1",45683)
let $p := map:put($wm, "cat1:::k2",123)
let $p := map:put($wm, "cat2:::k2",123)

return  local:buid-map-doc($wijk,$wm)

gives:

<y>
  <x>123</x>
  <x>123</x>
  <x>45683</x>
</y>

but i want to have the map:keys i the element names ... if I do this:

declare function local:buid-map-doc(
  $wijk as xs:string,
  $wm as map:map) as element()
{  
  let $a := for $k in map:keys($wm)
              let $v := map:get($wm,$k)
              return element {$k} {$v}
  return <y>{$a}</y>
};

let $wijk := "101101"
let $wm := map:map()
let $p := map:put($wm, "cat1:::k1",45683)
let $p := map:put($wm, "cat1:::k2",123)
let $p := map:put($wm, "cat2:::k2",123)

return  local:buid-map-doc($wijk,$wm)

then i get error like:

[1.0-ml] XDMP-QNAMELEXFORM: let $s := fn:QName("http://www.example.com/example", "k") -- Invalid lexical form for QName

ADDED:

Ideally I would like to get output like this, potentially with deeper nesting as well:

<results>
    <cat1>
        <k1>45683</k1>
        <k2>123</k2>
    </cat1>
    <cat2>
        <k2>123</k2>
    </cat2>
</results>
War es hilfreich?

Lösung 2

The problem with your code is that your map keys are not valid QNames. So, the actual error id is correct, but it is indeed odd that it reports the wrong code with it. I'll make sure it gets reported at MarkLogic.

The solution is quite simple, don't use colons in the map:keys, or use only one, and have the part before match with a known namespace prefix. E.g. this would work:

declare function local:buid-map-doc(
  $wijk as xs:string,
  $wm as map:map) as element()
{  
  let $a := for $k in map:keys($wm)
            let $v := map:get($wm,$k)
            return element {$k} {$v}
  return <y>{$a}</y>
};

let $wijk := "101101"
let $wm := map:map()
let $p := map:put($wm, "cat1_k1",45683)
let $p := map:put($wm, "cat1_k2",123)
let $p := map:put($wm, "cat2_k2",123)

return  local:buid-map-doc($wijk,$wm)

ADDED:

In case the triple-colon actually indicates hierarchy, you best convert the flattened maps into nested maps first. Converting nested maps to nested XML is pretty straight-forward. Here a rough implementation to build nested maps:

declare function local:nest-keys($nested-map, $keys, $value) {
  let $key := $keys[1]
  let $remainder := $keys[position() > 1]
  return
  if ($key) then
    let $_ :=
      if (not(map:contains($nested-map, $key))) then
        map:put($nested-map, $key, map:map())
      else()
    let $key-map :=
      map:get($nested-map, $key)
    return
      if ($remainder) then
        local:nest-keys($key-map, $remainder, $value)
      else
        map:put($nested-map, $key, $value)
  else
    ()
};

let $map := map:map(
<map:map xmlns:map="http://marklogic.com/xdmp/map">
  <map:entry>
    <map:key>cat1:::var1:::seg1</map:key>
    <map:value>waarde1</map:value>
  </map:entry>
  <map:entry>
    <map:key>cat1:::var1:::seg2</map:key>
    <map:value>waarde2</map:value>
  </map:entry>
  <map:entry>
    <map:key>cat1:::var2:::seg1</map:key>
    <map:value>waarde3</map:value>
  </map:entry>
  <map:entry>
    <map:key>cat1:::var2:::seg2</map:key>
    <map:value>waarde4</map:value>
  </map:entry>
  <map:entry>
    <map:key>cat2:::var1:::seg1</map:key>
    <map:value>waarde5</map:value>
  </map:entry>
</map:map>
)
let $nested-map := map:map()
let $_ :=
  for $key in map:keys($map)
  let $keys := tokenize($key, ":::")
  return
    local:nest-keys($nested-map, $keys, map:get($map, $key))
return $nested-map

HTH!

Andere Tipps

For computed element constructors, the expression for the element name needs to be in brackets: CompElemConstructor ::= "element" (QName | ("{" Expr "}")) "{" ContentExpr? "}"

declare function local:buid-map-doc(
  $wijk as xs:string,
  $wm as map:map) as element()
{  
  let $a := 
    for $k in map:keys($wm)
    let $v := map:get($wm, $k)
    return element { replace($k, ':::', '-')} { $v }
  return <y>{$a}</y>
};
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top