xmlstarlet edit/update 修改元素标签
xmlstarlet edit/update modifies element tags
我正在使用 xmlstarlet 对 xml 文件进行一些修改(我们称之为 test.xml),但我 运行 遇到了以下问题我的更新声明(注意:我也是 xmlstarlet 的新手!)。
这是我正在使用的 xml 的示例:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LIST>
<STUFF>
<xSTUFF>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-123</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Purple</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<VULN_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>5</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>No</INSTOCK>
<LOCATION></LOCATION>
<PRICE></PRICE>
<ONSALE></ONSALE>
<DISCOUNT></DISCOUNT>
</ITEM>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-124</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Red</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<VULN_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>3</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION>IsleA</LOCATION>
<PRICE>2.99</PRICE>
<ONSALE>No</ONSALE>
<DISCOUNT>No</DISCOUNT>
</ITEM>
</xSTUFF>
</STUFF>
</LIST>
有多个项目,每个项目都有唯一的项目 ID。我正在尝试更新给定商品 ID 的 INSTOCK、LOCATION、PRICE,有时还更新 ONSALE 和 DISCOUNT 字段。以其中一个为例,我正在尝试以下操作:
xmlstarlet ed --inplace -u
"//LIST/STUFF/xSTUFF/ITEM/ITEM_DATA[ATTRIBUTE_DATA='X-123']/../INSTOCK"
-v Yes test.xml
这似乎可行,但出于某种原因,在匹配项元素内去除了下方所有内容的前导元素标签,因此我的输出文件最终看起来像这样(注意缺少的 LOCATION、PRICE、ONSALE 和 DISCOUNT 前导标签):
*** 编辑:标签实际上被重新格式化为自动关闭标签,下面更新了结果。谢谢 Daniel Haley。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LIST>
<STUFF>
<xSTUFF>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-123</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Purple</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<VULN_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>5</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION/>
<PRICE/>
<ONSALE/>
<DISCOUNT/>
</ITEM>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-124</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Red</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<VULN_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>3</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION>IsleA</LOCATION>
<PRICE>2.99</PRICE>
<ONSALE>No</ONSALE>
<DISCOUNT>No</DISCOUNT>
</ITEM>
</xSTUFF>
</STUFF>
</LIST>
我猜我遗漏了一些简单的东西,因为我对 xmlstarlet 完全陌生,所以非常感谢任何帮助!
为了防止空元素被自闭,您可以将 XSLT 与 tr
xmlstarlet 命令一起使用,并将输出方法设置为 HTML
。
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="html"/>
<xsl:strip-space elements="*"/>
<xsl:param name="id"/>
<xsl:param name="newValue"/>
<xsl:template match="@*|node()" name="ident">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="INSTOCK">
<xsl:choose>
<xsl:when test="../ITEM_DATA/ATTRIBUTE_DATA=$id">
<xsl:copy>
<xsl:value-of select="$newValue"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="ident"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
命令行
xml tr test.xsl -s id="X-123" -s newValue="Yes" input.xml
输出
<LIST><STUFF><xSTUFF><ITEM><ITEM_DATA><ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>X-123</ATTRIBUTE_DATA></ITEM_DATA><ITEM_DATA><ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>Purple</ATTRIBUTE_DATA></ITEM_DATA><ITEM_DATA><ITEM_ATTRIBUTE>Weight</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>5</ATTRIBUTE_DATA></ITEM_DATA><INSTOCK>Yes</INSTOCK><LOCATION></LOCATION><PRICE></PRICE><ONSALE></ONSALE><DISCOUNT></DISCOUNT></ITEM><ITEM><ITEM_DATA><ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>X-124</ATTRIBUTE_DATA></ITEM_DATA><ITEM_DATA><ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>Red</ATTRIBUTE_DATA></ITEM_DATA><ITEM_DATA><ITEM_ATTRIBUTE>Weight</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>3</ATTRIBUTE_DATA></ITEM_DATA><INSTOCK>Yes</INSTOCK><LOCATION>IsleA</LOCATION><PRICE>2.99</PRICE><ONSALE>No</ONSALE><DISCOUNT>No</DISCOUNT></ITEM></xSTUFF></STUFF></LIST>
请注意,您没有得到 XML 声明 (<?xml ...?>
),即使我在 xsl:output
上设置了 indent="yes"
,XML最终都在一条线上。
XML 仍然是格式正确的,因为 XML 声明在 XML 1.0 实例上不是必需的。
另一种选择是使用具有不同处理器的 XSLT 2.0/3.0。这样你就可以使用输出方法 xhtml
.
这是一个在命令行中使用 XSLT 3.0 和 Saxon-HE 9.8(free/open 源代码)的 Java 版本的示例...
XSLT 3.0
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xhtml" standalone="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="id" required="yes"/>
<xsl:param name="newValue" required="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="ITEM[ITEM_DATA/ATTRIBUTE_DATA=$id]/INSTOCK">
<xsl:copy>
<xsl:value-of select="$newValue"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
命令行
java -cp "C:/apps/saxon/saxon9he.jar" net.sf.saxon.Transform -s:"input.xml" -xsl:"test.xsl" id="X-123" newValue="Yes"
输出
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><LIST>
<STUFF>
<xSTUFF>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-123</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Purple</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>5</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION></LOCATION>
<PRICE></PRICE>
<ONSALE></ONSALE>
<DISCOUNT></DISCOUNT>
</ITEM>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-124</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Red</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>3</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION>IsleA</LOCATION>
<PRICE>2.99</PRICE>
<ONSALE>No</ONSALE>
<DISCOUNT>No</DISCOUNT>
</ITEM>
</xSTUFF>
</STUFF>
</LIST>
注意 XML 声明和 <LIST>
开始标记之间没有换行符。如果这是一个问题(不应该是),您可以将以下模板添加到 XSLT。
<xsl:template match="/">
<xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
此外,如果您最终能够使用当前输出,则可以稍微简化 xmlstarlet 命令中的 XPath:
/LIST/STUFF/xSTUFF/ITEM[ITEM_DATA/ATTRIBUTE_DATA='X-123']/INSTOCK
我正在使用 xmlstarlet 对 xml 文件进行一些修改(我们称之为 test.xml),但我 运行 遇到了以下问题我的更新声明(注意:我也是 xmlstarlet 的新手!)。
这是我正在使用的 xml 的示例:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LIST>
<STUFF>
<xSTUFF>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-123</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Purple</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<VULN_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>5</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>No</INSTOCK>
<LOCATION></LOCATION>
<PRICE></PRICE>
<ONSALE></ONSALE>
<DISCOUNT></DISCOUNT>
</ITEM>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-124</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Red</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<VULN_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>3</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION>IsleA</LOCATION>
<PRICE>2.99</PRICE>
<ONSALE>No</ONSALE>
<DISCOUNT>No</DISCOUNT>
</ITEM>
</xSTUFF>
</STUFF>
</LIST>
有多个项目,每个项目都有唯一的项目 ID。我正在尝试更新给定商品 ID 的 INSTOCK、LOCATION、PRICE,有时还更新 ONSALE 和 DISCOUNT 字段。以其中一个为例,我正在尝试以下操作:
xmlstarlet ed --inplace -u "//LIST/STUFF/xSTUFF/ITEM/ITEM_DATA[ATTRIBUTE_DATA='X-123']/../INSTOCK" -v Yes test.xml
这似乎可行,但出于某种原因,在匹配项元素内去除了下方所有内容的前导元素标签,因此我的输出文件最终看起来像这样(注意缺少的 LOCATION、PRICE、ONSALE 和 DISCOUNT 前导标签):
*** 编辑:标签实际上被重新格式化为自动关闭标签,下面更新了结果。谢谢 Daniel Haley。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LIST>
<STUFF>
<xSTUFF>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-123</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Purple</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<VULN_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>5</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION/>
<PRICE/>
<ONSALE/>
<DISCOUNT/>
</ITEM>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-124</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Red</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<VULN_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>3</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION>IsleA</LOCATION>
<PRICE>2.99</PRICE>
<ONSALE>No</ONSALE>
<DISCOUNT>No</DISCOUNT>
</ITEM>
</xSTUFF>
</STUFF>
</LIST>
我猜我遗漏了一些简单的东西,因为我对 xmlstarlet 完全陌生,所以非常感谢任何帮助!
为了防止空元素被自闭,您可以将 XSLT 与 tr
xmlstarlet 命令一起使用,并将输出方法设置为 HTML
。
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="html"/>
<xsl:strip-space elements="*"/>
<xsl:param name="id"/>
<xsl:param name="newValue"/>
<xsl:template match="@*|node()" name="ident">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="INSTOCK">
<xsl:choose>
<xsl:when test="../ITEM_DATA/ATTRIBUTE_DATA=$id">
<xsl:copy>
<xsl:value-of select="$newValue"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="ident"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
命令行
xml tr test.xsl -s id="X-123" -s newValue="Yes" input.xml
输出
<LIST><STUFF><xSTUFF><ITEM><ITEM_DATA><ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>X-123</ATTRIBUTE_DATA></ITEM_DATA><ITEM_DATA><ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>Purple</ATTRIBUTE_DATA></ITEM_DATA><ITEM_DATA><ITEM_ATTRIBUTE>Weight</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>5</ATTRIBUTE_DATA></ITEM_DATA><INSTOCK>Yes</INSTOCK><LOCATION></LOCATION><PRICE></PRICE><ONSALE></ONSALE><DISCOUNT></DISCOUNT></ITEM><ITEM><ITEM_DATA><ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>X-124</ATTRIBUTE_DATA></ITEM_DATA><ITEM_DATA><ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>Red</ATTRIBUTE_DATA></ITEM_DATA><ITEM_DATA><ITEM_ATTRIBUTE>Weight</ITEM_ATTRIBUTE><ATTRIBUTE_DATA>3</ATTRIBUTE_DATA></ITEM_DATA><INSTOCK>Yes</INSTOCK><LOCATION>IsleA</LOCATION><PRICE>2.99</PRICE><ONSALE>No</ONSALE><DISCOUNT>No</DISCOUNT></ITEM></xSTUFF></STUFF></LIST>
请注意,您没有得到 XML 声明 (<?xml ...?>
),即使我在 xsl:output
上设置了 indent="yes"
,XML最终都在一条线上。
XML 仍然是格式正确的,因为 XML 声明在 XML 1.0 实例上不是必需的。
另一种选择是使用具有不同处理器的 XSLT 2.0/3.0。这样你就可以使用输出方法 xhtml
.
这是一个在命令行中使用 XSLT 3.0 和 Saxon-HE 9.8(free/open 源代码)的 Java 版本的示例...
XSLT 3.0
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xhtml" standalone="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="id" required="yes"/>
<xsl:param name="newValue" required="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="ITEM[ITEM_DATA/ATTRIBUTE_DATA=$id]/INSTOCK">
<xsl:copy>
<xsl:value-of select="$newValue"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
命令行
java -cp "C:/apps/saxon/saxon9he.jar" net.sf.saxon.Transform -s:"input.xml" -xsl:"test.xsl" id="X-123" newValue="Yes"
输出
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><LIST>
<STUFF>
<xSTUFF>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-123</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Purple</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>5</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION></LOCATION>
<PRICE></PRICE>
<ONSALE></ONSALE>
<DISCOUNT></DISCOUNT>
</ITEM>
<ITEM>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Item_ID</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>X-124</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Color</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>Red</ATTRIBUTE_DATA>
</ITEM_DATA>
<ITEM_DATA>
<ITEM_ATTRIBUTE>Weight</ITEM_ATTRIBUTE>
<ATTRIBUTE_DATA>3</ATTRIBUTE_DATA>
</ITEM_DATA>
<INSTOCK>Yes</INSTOCK>
<LOCATION>IsleA</LOCATION>
<PRICE>2.99</PRICE>
<ONSALE>No</ONSALE>
<DISCOUNT>No</DISCOUNT>
</ITEM>
</xSTUFF>
</STUFF>
</LIST>
注意 XML 声明和 <LIST>
开始标记之间没有换行符。如果这是一个问题(不应该是),您可以将以下模板添加到 XSLT。
<xsl:template match="/">
<xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
此外,如果您最终能够使用当前输出,则可以稍微简化 xmlstarlet 命令中的 XPath:
/LIST/STUFF/xSTUFF/ITEM[ITEM_DATA/ATTRIBUTE_DATA='X-123']/INSTOCK