0

我有一个名为 employees.xml 的 XML 文档:

<employees>
    <row>
        <emp_no>10001</emp_no>
        <first_name>Georgi</first_name>
        <last_name>Facello</last_name>
    </row>
    <row>
        <emp_no>10002</emp_no>
        <first_name>Bezalel</first_name>
        <last_name>Simmel</last_name>
    </row>
</employees>

我想编写一个名为的函数my-remove-elements,它将删除未选择的属性。例如,只在 XML 文档中保留first_name和:last_name

  <employees>
        <row>
            <first_name>Georgi</first_name>
            <last_name>Facello</last_name>
        </row>
        <row>
            <first_name>Bezalel</first_name>
            <last_name>Simmel</last_name>
        </row>
    </employees>

我的函数的定义是:

declare function local:my-remove-elements($input as element(), $remove-names as xs:string*) as element() {
   element {node-name($input) }
      {$input/@*,
       for $child in $input/node()[name(.)=$remove-names]
          return
             if ($child instance of element())
                then local:my-remove-elements($child, $remove-names)
                else $child
      }
};

这就是我所说的方式:

  let $doc := doc("employees.xml")
    return 
         local:my-remove-elements($doc, ('first_name', 'last_name'))

它抛出我“err:XPTY0004 ...不是元素()的子类型......”我已经更改了代码:

let $rows:= doc("employees.xml")//row
        return 
             local:my-remove-elements($rows, ('first_name', 'last_name'))

这次仍然是:“err:XPTY0004: 参数 1 的实际基数与函数签名中的基数不匹配......”。你知道如何解决这个问题并让它发挥作用吗?

4

2 回答 2

0

该错误err:XPTY0004是因为您正在调用将 adocument-node()作为第一个参数传递的函数,但第一个参数必须是element().

更改调用它的方式,传入文档元素(即$doc/*)而不是document-node()

然后,您需要调整函数中的逻辑。如果您只选择$child等于 的节点$remove-names(这很令人困惑,请考虑重命名为 $keep-leaf-names 之类的名称),那么这些employees元素将被排除在外。向下移动该过滤器,如果元素有子元素或它name()等于任何$remove-names.

declare function local:my-remove-elements($input as element(), $remove-names as xs:string*) as element() {
   element {node-name($input) }
      {$input/@*,
       for $child in $input/node()
          return
             if ($child instance of element()) then 
                if ($child/* or name($child)=$remove-names) then 
                  local:my-remove-elements($child, $remove-names) 
                else ()
             else $child
      }
};
于 2018-03-10T22:44:55.577 回答
0

这是一种可能的解决方案:

declare function local:remove-elements(
  $node as node(),
  $keep-names as xs:string*
) as node()? {
  if($node instance of element()) then (
    let $name := name($node)
    where $name = $keep-names
    return element { $name } {
      $node/@*,
      for $child in $node/node()
      return local:remove-elements($child, $keep-names)
    }
  ) else (
    $node
  )
};

local:remove-elements(
  doc("employees.xml")/employees,
  ('employees', 'row', 'first_name', 'last_name')
)

这是另一个,它使用 XQuery 更新:

declare function local:remove-elements(
  $node as node(),
  $keep-names as xs:string*
) as node()? {
  copy $c := $node
  modify delete node $c//*[not(name() = $keep-names)]
  return $c
};

local:remove-elements(
  doc("employees.xml")/employees,
  ('employees', 'row', 'first_name', 'last_name')
)
于 2018-03-10T22:40:08.353 回答