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。
我正在尝试在 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。