使用 xmlstarlet 上的 xpath 检索 XML 元素的所有属性名称
Retrieving all attribute names of an XML element with xpath on xmlstarlet
我可以看到如何检索所有属性值:
xml sel -t -v "//element/@*"
但我想获取所有属性 names.
我可以通过 xml sel -t -v "name(//x:mem/@*[3])"
获得第 n 个名称,其中 returns 第三个属性名称。
但是 xml sel -t -v "name(//x:mem/@*)"
不起作用(returns 仅第一个属性名称)...
有没有办法获取所有个属性名称?
这个 xmlstarlet 命令:
xml tr attnames.xsl in.xml
使用这个 XSLT 转换,命名为 attnames.xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="@*">
<xsl:value-of select="name(.)"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
和这个 XML 文件,名为 in.xml:
<root att1="one">
<a att2="two"/>
<b att3="three">
<c att4="four"/>
</b>
</root>
将生成在 in.xml 中找到的所有属性的列表:
att1
att2
att3
att4
为了 select 仅来自 b
元素的所有属性,像这样修改 XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="@*">
<xsl:value-of select="name(.)"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="b">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
使用 -t
和 -m
定义模板匹配,然后使用 -v
.
应用另一个 XPath 表达式
$ xml sel -T -t -m "//mem/@*" -v "name()" -n input.xml
应用于此输入时 XML:
<root>
<mem yes1="1" yes2="2"/>
<other no="1" no2="2"/>
</root>
将打印:
yes1
yes2
那是"short line on the shell",但完全看不懂。因此,我仍然更喜欢 kjhughes 的 XSLT 解决方案。不要为了简洁而牺牲可理解的代码。
您可以编写一个从命令行获取输入参数的样式表,这样如果您想检索不同元素的属性名称,就不必更改 XSLT 代码。
正如@npostavs 所建议的,在内部,xmlstarlet 无论如何都使用XSLT。您可以检查通过将 -T
替换为 -C
:
生成的 XSLT
$ xml sel -C -t -m "//mem/@*" -v "name()" -n app.xml
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//mem/@*">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="name()"/>
</xsl:call-template>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
还有更多选项可供探索,请参阅 xmlstarlet documentation。
我可以看到如何检索所有属性值:
xml sel -t -v "//element/@*"
但我想获取所有属性 names.
我可以通过 xml sel -t -v "name(//x:mem/@*[3])"
获得第 n 个名称,其中 returns 第三个属性名称。
但是 xml sel -t -v "name(//x:mem/@*)"
不起作用(returns 仅第一个属性名称)...
有没有办法获取所有个属性名称?
这个 xmlstarlet 命令:
xml tr attnames.xsl in.xml
使用这个 XSLT 转换,命名为 attnames.xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="@*">
<xsl:value-of select="name(.)"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*"/>
</xsl:template>
</xsl:stylesheet>
和这个 XML 文件,名为 in.xml:
<root att1="one">
<a att2="two"/>
<b att3="three">
<c att4="four"/>
</b>
</root>
将生成在 in.xml 中找到的所有属性的列表:
att1
att2
att3
att4
为了 select 仅来自 b
元素的所有属性,像这样修改 XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="@*">
<xsl:value-of select="name(.)"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="b">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
使用 -t
和 -m
定义模板匹配,然后使用 -v
.
$ xml sel -T -t -m "//mem/@*" -v "name()" -n input.xml
应用于此输入时 XML:
<root>
<mem yes1="1" yes2="2"/>
<other no="1" no2="2"/>
</root>
将打印:
yes1
yes2
那是"short line on the shell",但完全看不懂。因此,我仍然更喜欢 kjhughes 的 XSLT 解决方案。不要为了简洁而牺牲可理解的代码。
您可以编写一个从命令行获取输入参数的样式表,这样如果您想检索不同元素的属性名称,就不必更改 XSLT 代码。
正如@npostavs 所建议的,在内部,xmlstarlet 无论如何都使用XSLT。您可以检查通过将 -T
替换为 -C
:
$ xml sel -C -t -m "//mem/@*" -v "name()" -n app.xml
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//mem/@*">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="name()"/>
</xsl:call-template>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
还有更多选项可供探索,请参阅 xmlstarlet documentation。