xmlstarlet编辑/更新修改元素标签

时间:2017-08-24 15:15:14

标签: xml 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的INSTOCK,LOCATION,PRICE,有时还会更新ONSALE和DISCOUNT字段。以其中一个为例,我正在尝试以下方法:

  

xmlstarlet ed --inplace -u   “//LIST/STUFF/xSTUFF/ITEM/ITEM_DATA[ATTRIBUTE_DATA='X-123']/../INSTOCK”   -v是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完全是绿色的,所以非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

为防止空元素自行关闭,可以使用带有tr xmlstarlet命令的XSLT,并将输出方法设置为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 ...?>),即使我indent="yes"设置xsl:output,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