首页 > 解决方案 > xmlstarlet 默认命名空间

问题描述

我想使用 xmlstarlet 将第三方 xml 文件转换为 csv 文件。一些文件使用带有 xmlns 声明的默认命名空间,其他文件使用没有 xmlns 声明的默认命名空间,而其他文件在最精确的解释中使用严格的默认命名空间。

这是一些较小的文件,应该可以澄清我的问题。
foo1.xml

<?xml version="1.0"?>
<root xmlns="http://my.namespace" xmlns:fooNS="http://foo.namespace" xmlns:barNS="http://bar.namespace">
    <fooNS:foo id="1">FOO 1</fooNS:foo>
    <fooNS:foo id="2">FOO 2</fooNS:foo>
    <barNS:bar ref="2" unitRef="Unit1">2000</barNS:bar>
    <unit id="Unit1">
        <measure>bars</measure>
    </unit>
</root>

foo2.xml

<?xml version="1.0"?>
<root xmlns:fooNS="http://foo.namesapece" xmlns:barNS="http://bar.namespace">
    <fooNS:foo id="1">FOO 1</fooNS:foo>
    <fooNS:foo id="2">FOO 2</fooNS:foo>
    <barNS:bar ref="2" unitRef="Unit1">2000</barNS:bar>
    <unit id="Unit1">
        <measure>bars</measure>
    </unit>
</root>

foo3.xml

<?xml version="1.0"?>
<myNS:root xmlns:myNS="http://my.namespace" xmlns:fooNS="http://foo.namesapece" xmlns:barNS="http://bar.namespace">
    <fooNS:foo id="1">FOO 1</fooNS:foo>
    <fooNS:foo id="2">FOO 2</fooNS:foo>
    <barNS:bar ref="2" unitRef="Unit1">2000</barNS:bar>
    <unit id="Unit1">
        <measure>bars</measure>
    </unit>
</myNS:root>

现在我想要一个文件"FOO 2 | 2000 | bars"作为输出。属性“unitRef”在 xsd 中定义为 IDREF。

此命令适用于foo1.xml(但不适用于 foo2.xml 和 foo3.xml):

$> xmlstarlet sel -N xbrli="http://my.namespace" \
         -t -m "//fooNS:foo[../barNS:bar/@ref = @id]"
         -v . -o " | " \
         -v "../barNS:bar[@ref=current()/@id]" -o " | " \
         -v \
"//xbrli:unit[@id=current()/../barNS:bar[@ref=current()/@id]/@unitRef]/xbrli:measure" \
         -n foo1.xml

此命令适用于foo2.xml 和 foo3.xml(但不适用于 foo1.xml):

$> xmlstarlet sel -N xmlns="http://my.namespace" \
         -t -m "//fooNS:foo[../barNS:bar/@ref = @id]" \
         -v . -o " | " \
         -v "../barNS:bar[@ref=current()/@id]" -o " | " \
         -v \
"//unit[@id=current()/../barNS:bar[@ref=current()/@id]/@unitRef]/measure" \
         -n foo[23].xml

问题:是否有适用于所有三个第三方文件的语法?如果不使用 xmlstarlet,那么也许使用 xslt 文件?或者也许可以处理所有 xml 文件(使用 xmlstarlet 或 xslt),以便它们的行为相似?

谢谢。

标签: xmlxsltnamespacesxmlstarlet

解决方案


因为没有人提供更好的解决方案,所以我使用了#kjhughes 提出的解决方案。

所以(不推荐)答案:-v "// [local-name()='unit'][@id=current()/../barNS:bar[@ref=current()/@id]/ @unitRef]/ [local-name()='measure']"

另请参阅“ XPath 如何处理 XML 名称空间? ”以获得所有推荐解决方案的描述。但它们都不适用于我的所有情况。


推荐阅读