xmlstarlet shell 脚本添加属性和属性下的元素

xmlstartlet shell script to add attribute and elements under an attribute

我正在尝试在 XML 文件中的现有属性下添加属性。我一直在使用 xmlstarted 进行编辑,但从未使用它进行更新。如果有人告诉您如何在该新 attrb 下添加新的 attr 和元素 -

会很有帮助

这是我的 xml 文件的片段 -

这是我通常在 xmlstarlet-

的帮助下编辑子元素的方法;
xmlstarlet edit  --inplace -u "/allocations/queue[@name='root']/queue[@name='paas_api_q1']/queue[@name='child1_sq1']/minResources" --value "$value" myfile.xml

之前 -

<?xml version="1.0"?>
<allocations>
  <queue name="root">
    <aclSubmitApps> bddbagrp,mapr</aclSubmitApps>
    <aclAdministerApps> bddbagrp,root,mapr,trmte_id</aclAdministerApps>
    <schedulingPolicy>drf</schedulingPolicy>
    <defaultMinSharePreemptionTimeout>60</defaultMinSharePreemptionTimeout>
    <fairSharePreemptionTimeout>60</fairSharePreemptionTimeout>
    <queue name="paas_api_q1">
      <minResources>90000 mb,15 vcores,2 disks</minResources>
      <maxResources>135000 mb,22 vcores,3 disks</maxResources>
      <queue name="child1_sq1">
        <minResources>66000 mb,11 vcores,2 disks</minResources>
        <maxResources>264000 mb,44 vcores,8 disks</maxResources>
        <aclSubmitApps> paas_opsauto_admin_unix</aclSubmitApps>
        <aclAdministerApps> paas_opsauto_admin_unix</aclAdministerApps>
        <label>allnodes||balanced</label>
      </queue>
    </queue>
  </queue>
  <queuePlacementPolicy>
    <rule create="false" name="specified"/>
    <rule name="reject"/>
  </queuePlacementPolicy>
</allocations>

之后它应该看起来像这样..在这里我在现有的 attr 下添加一个新属性 - pass_api_q1 .

<!-- language: lang-xml -->
<?xml version="1.0"?>
<allocations>
  <queue name="root">
    <aclSubmitApps> bddbagrp,mapr</aclSubmitApps>
    <aclAdministerApps> bddbagrp,root,mapr,trmte_id</aclAdministerApps>
    <schedulingPolicy>drf</schedulingPolicy>
    <defaultMinSharePreemptionTimeout>60</defaultMinSharePreemptionTimeout>
    <fairSharePreemptionTimeout>60</fairSharePreemptionTimeout>
    <queue name="paas_api_q1">
      <minResources>90000 mb,15 vcores,2 disks</minResources>
      <maxResources>135000 mb,22 vcores,3 disks</maxResources>
      <queue name="child1_sq1">
        <minResources>66000 mb,11 vcores,2 disks</minResources>
        <maxResources>264000 mb,44 vcores,8 disks</maxResources>
        <aclSubmitApps> paas_opsauto_admin_unix</aclSubmitApps>
        <aclAdministerApps> paas_opsauto_admin_unix</aclAdministerApps>
        <label>allnodes||balanced</label>
      </queue>
      <queue name="child2_sq1">
        <minResources>66000 mb,11 vcores,2 disks</minResources>
        <maxResources>132000 mb,22 vcores,4 disks</maxResources>
        <aclSubmitApps> paas_opsauto_admin_unix</aclSubmitApps>
        <aclAdministerApps> paas_opsauto_admin_unix</aclAdministerApps>
        <label>allnodes||balanced</label>
      </queue>
    </queue>
  </queue>
  <queuePlacementPolicy>
    <rule create="false" name="specified"/>
    <rule name="reject"/>
  </queuePlacementPolicy>
</allocations>

任何help/direction将不胜感激。

可以使用一堆-i/-a/-s来添加新元素(see here),但我认为使用XSLT会更容易tr。您可以将您的元素放在另一个文件中并将其作为参数传递。

示例...

XML 要添加的片段 (fragment.xml)

<?xml version="1.0"?>
<queue name="child2_sq1">
    <minResources>66000 mb,11 vcores,2 disks</minResources>
    <maxResources>132000 mb,22 vcores,4 disks</maxResources>
    <aclSubmitApps> paas_opsauto_admin_unix</aclSubmitApps>
    <aclAdministerApps> paas_opsauto_admin_unix</aclAdministerApps>
    <label>allnodes||balanced</label>
</queue>

XSLT (test.xsl)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="frag"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!--If you wanted to make this stylesheet reusable, you could pass a new
  value in for the "match" attribute by selecting this template by its
  "name" value (@name='target').-->
  <xsl:template match="queue[@name='paas_api_q1']" name="target">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <xsl:copy-of select="$frag"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

xmlstarlet 命令行

xmlstarlet tr test.xsl -p frag='document("fragment.xml")/*' input.xml

输出

<?xml version="1.0"?>
<allocations>
  <queue name="root">
    <aclSubmitApps> bddbagrp,mapr</aclSubmitApps>
    <aclAdministerApps> bddbagrp,root,mapr,trmte_id</aclAdministerApps>
    <schedulingPolicy>drf</schedulingPolicy>
    <defaultMinSharePreemptionTimeout>60</defaultMinSharePreemptionTimeout>
    <fairSharePreemptionTimeout>60</fairSharePreemptionTimeout>
    <queue name="paas_api_q1">
      <minResources>90000 mb,15 vcores,2 disks</minResources>
      <maxResources>135000 mb,22 vcores,3 disks</maxResources>
      <queue name="child1_sq1">
        <minResources>66000 mb,11 vcores,2 disks</minResources>
        <maxResources>264000 mb,44 vcores,8 disks</maxResources>
        <aclSubmitApps> paas_opsauto_admin_unix</aclSubmitApps>
        <aclAdministerApps> paas_opsauto_admin_unix</aclAdministerApps>
        <label>allnodes||balanced</label>
      </queue>
      <queue name="child2_sq1">
        <minResources>66000 mb,11 vcores,2 disks</minResources>
        <maxResources>132000 mb,22 vcores,4 disks</maxResources>
        <aclSubmitApps> paas_opsauto_admin_unix</aclSubmitApps>
        <aclAdministerApps> paas_opsauto_admin_unix</aclAdministerApps>
        <label>allnodes||balanced</label>
      </queue>
    </queue>
  </queue>
  <queuePlacementPolicy>
    <rule create="false" name="specified"/>
    <rule name="reject"/>
  </queuePlacementPolicy>
</allocations>

正如 Daniel Haley 指出的那样,单独使用 xmlstarlet 可能会很乏味,因为它没有 copy/paste 可以使任务变得更简单的功能。作为练习,我尝试了下面似乎有效的代码:

xmlstarlet ed  
     -a "//queue/queue[@name='paas_api_q1']/queue"
     -t elem -n queue -v "$(xmlstarlet sel  -t -m //queue/queue[@name]/*/* -c . myfile.xml)"
     -i "//queue[@name='paas_api_q1']//queue[not(@name)]" --type attr --name "name" -v "child2_sq1" \
   myfile.xml | xmlstarlet unesc

基本上,它在适当的地方创建一个新节点,创建原始节点的副本(使用变量),将副本插入到新节点的值中,向新节点添加属性和值最后,从原始节点的副本中取消转义标签。

正如我所说,只是一个练习...

虽然我还没有尝试过,但我猜也可以使用 xidel 及其对 xquery 的支持来执行此任务,而不是使用 xmlstarlet。