背景
希望从以下 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:composition
和 h: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>
</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>
</xsl:text>
</xsl:template>
<xsl:template match="h:inputText">
<xsl:text>
</xsl:text>
<h:inputText>
<xsl:copy-of select="@*"/>
</h:inputText>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
关于xml - 从 xmlstarlet 输出中删除命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40537300/