xml - 从 xmlstarlet 输出中删除命名空间

标签 xml xpath namespaces xmlstarlet xmllint

背景

希望从以下 XML 内容中提取元素:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:inputText id="id"/>
    ...
</ui:composition>

提取

可以使用以下方式选择所有 h:inputText 元素:

xmlstarlet sel -t -c "//h:inputText" filename.xml

问题

这会产生以下受命名空间影响的输出:

<h:inputText
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets" id="id"/>

问题

如何从输出中抑制 namespace ?

想法

使用正则表达式进行后处理;然而:

  • sed 没有非贪婪匹配;
  • perl 太重量级(并且需要复杂的正则表达式)。

通过 xmllint 或 xmlstarlet 进行第二次传递,但这需要格式良好的 XML 文档。

使用 xmllint 会带来一系列命名空间问题。

生成仅由 ui:compositionh:inputText 元素组成的文档:

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:inputText id="id"/>
  <h:inputText id="id"/>
</ui:composition>

这很棘手,因为 h:inputText 元素可以出现在文档的任何深度。

最佳答案

您可以使用 XSLT。如果你想输出h:inputText按原样,您将无法抑制绑定(bind)前缀 h: 的命名空间声明。到 uri http://java.sun.com/jsf/html

XSLT 1.0

创建input.xsl :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:h="http://java.sun.com/jsf/html">
  <xsl:output omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <xsl:apply-templates select="//h:inputText"/>
  </xsl:template>

  <xsl:template match="h:inputText">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

xmlstarlet 命令

xmlstarlet tr input.xsl filename.xml

输出

<h:inputText xmlns:h="http://java.sun.com/jsf/html" id="id"/>

您可以输出inputText虽然没有命名空间...

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:h="http://java.sun.com/jsf/html" exclude-result-prefixes="h">
  <xsl:output omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <xsl:apply-templates select="//h:inputText"/>
  </xsl:template>

  <xsl:template match="h:inputText">
    <inputText>
      <xsl:copy-of select="@*"/>
    </inputText>
  </xsl:template>

</xsl:stylesheet>

输出

使用上面相同的命令行:

<inputText id="id"/>

注意:您可能需要添加 <xsl:text>&#xA;</xsl:text>之后</xsl:copy> (或第二个示例中的 </inputText> )显式添加换行符。否则 xmlstartlet 可能会在一行上输出所有元素。 (它对我使用 xmlstarlet 1.6.1 和 indent="yes"xsl:output 上没有帮助。)

JSF 输出

由于涉及 JSF,请考虑:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:c="http://java.sun.com/jsp/jstl/core"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:a4j="http://richfaces.org/a4j"
                exclude-result-prefixes="h f c ui a4j">
    <xsl:output method="xml" omit-xml-declaration="yes" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <h:html>
            <xsl:apply-templates select="//h:inputText"/>
        </h:html>
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>

    <xsl:template match="h:inputText">
        <xsl:text>&#xA;</xsl:text>
        <h:inputText>
            <xsl:copy-of select="@*"/>
        </h:inputText>
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

关于xml - 从 xmlstarlet 输出中删除命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40537300/

相关文章:

xml - 创建XML文件,尝试添加记录时出现错误

Android - 从一个 textView 获取文本并使用 Android 数据绑定(bind)设置到另一个

text - XPath无法使用text()定位元素

XSLT - 在谓词过滤器中,为什么有时必须使用 XSLT current() 函数而不是 XPath 上下文节点点运算符?

c# - 如何验证 CodeDOM 中的命名空间名称?

python - 为什么 LXML Write 不能很好地打印到新文件?

c# - 解析 XElement

xml - XST - 使用调用模板的输出作为返回值

c++ - 在匿名命名空间中声明的常量与函数范围静态常量相比有哪些(缺点)优势?

c++ - gSoap 中的多个命名空间