XMLSTARLET 编辑/更新修改元素标记



我正在使用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 的库存、位置、价格,有时还有"促销"和"折扣"字段。 以其中一个为例,我正在尝试以下操作:

XMLSTARLET ed --inplace -u "//LIST/STUFF/xSTUFF/ITEM/ITEM_DATA[ATTRIBUTE_DATA='X-123']/../库存" -v 是测试.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>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 与trxmlstarlet 命令一起使用,并将输出方法设置为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 1.0实例上不需要XML声明。

另一种选择是将 XSLT 2.0/3.0 与不同的处理器一起使用。这样您就可以使用输出方法xhtml.

下面是从命令行将 XSLT 3.0 与 Java 版本的 Saxon-HE 9.8(免费/开源(一起使用的示例...

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>&#xA;</xsl:text>
<xsl:apply-templates/>
</xsl:template>

此外,如果您最终能够使用当前的输出,则可以在 xmlstarlet 命令中稍微简化 XPath:

/LIST/STUFF/xSTUFF/ITEM[ITEM_DATA/ATTRIBUTE_DATA='X-123']/INSTOCK

最新更新