xmlstarlet 默认命名空间

Posted

技术标签:

【中文标题】xmlstarlet 默认命名空间【英文标题】:xmlstarlet default namespace 【发布时间】:2018-12-20 22:23:22 【问题描述】:

我想使用 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 AND 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),以便它们的行为相似?

谢谢。

【问题讨论】:

XMLStarlet v1.2.1 和更新版本具有默认命名空间的 _: 语法(请参阅第一个重复链接),但您的 XML 文件并不完全等效,因为命名空间前缀名称的解析和默认命名空间不会产生在相同的元素名称中。 (在尝试针对它们编写 XPath 表达式之前,请确保您了解三个文件之间的 XML 命名空间差异。)如果您真的想忽略命名空间(通常不推荐),您可以针对 @987654328 进行测试@。有关详细信息,请参阅第二个重复链接。 @kjhughes 。谢谢。问题是我使用第三方 xml 文件,其中命名空间的声明方式不同。我正在寻找适用于三个 xml 文件的语法。如果我使用_: 语法,它只适用于 foo1.xml,不适用于 foo2.xml 和 foo3.xml。列出的答案都没有回答我的问题。 请注意,命名空间前缀本身仅在它们与命名空间 URI 的绑定中很重要;实际使用的前缀并不重要。 (也就是说,您的 XML 文件仍然不等价。)*[local-name() = 'foo'] 是否适合您然后忽略 foo 上的命名空间? @kjhughes 。再次感谢。 不客气,但您是说您的问题已经解决,还是需要进一步的帮助——我不清楚。 【参考方案1】:

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

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

有关所有推荐解决方案的说明,另请参阅“How does XPath deal with XML namespaces?”。但它们都不适用于我的所有情况。

【讨论】:

以上是关于xmlstarlet 默认命名空间的主要内容,如果未能解决你的问题,请参考以下文章

如何从默认命名空间发送到自定义命名空间?

XPATHS 和默认命名空间

VS2015-项目默认的XML命名空间必须是MSBuild XML命名空间

项目的默认 XML 命名空间必须是 MSBuild XML 命名空间

具有显式默认命名空间的 XML 文档的 XPath 和命名空间规范

Hadoop—如何查看HDFS默认的ns命名空间和所有命名空间列表