使用 xmlstaret、grep 或类似工具更新 xsl 文件

update xsl file with xmlstaret, grep or similar

我有一系列类似的 XSL 文件,对于所有这些文件,我必须在特定位置添加相同的 XSL 元素。

在这里您可以找到要更新的XSL的一部分,要插入的元素是 <xsl:call-template name="distributor.xsl"/> 它必须在 </mrd:distributionFormat> 之后和 <mrd:transferOptions> 标签之前

有没有办法使用 XmlStarlet grep 或类似工具自动更新我所有的 XSL 文件?

...
<mdb:distributionInfo>
      <mrd:MD_Distribution>
         <mrd:distributionFormat>
            <mrd:MD_Format>
               <mrd:formatSpecificationCitation>
                  <cit:CI_Citation>
                     <cit:title>
                        <gco:CharacterString>WCS</gco:CharacterString>
                     </cit:title>
                     <cit:date gco:nilReason="unknown"/>
                     <cit:edition>
                        <gco:CharacterString>2.0</gco:CharacterString>
                     </cit:edition>
                  </cit:CI_Citation>
               </mrd:formatSpecificationCitation>
            </mrd:MD_Format>
         </mrd:distributionFormat>
                 <!-- call-template  -->           
                <xsl:call-template name="distributor.xsl"/>
                 <!-- call-template -->
         <mrd:transferOptions>
         ...

我试过

xmlstarlet ed -P -S -L -s //mrd:MD_Distribution -t elem -i xsl:include -t attr -n "name" -v "distributor.xsl" main.xsl 其中 main.xsl 是要更新的文件

在 POSIX shell 以下 命令中:

xmlstarlet edit \
    -N xsl="http://www.w3.org/1999/XSL/Transform" \
    -N mdb="urn:so70244776_mdb" \
    -N mrd="urn:so70244776_mrd" \
    --var templatename "'distributor-N.xsl'" \
    --var anchornode '//mrd:distributionFormat[1]' \
    -d '$anchornode/following-sibling::xsl:call-template' \
    -a '$anchornode' -t elem -n 'xsl:call-template' -v '' \
    -a '$xstar:prev' -t attr -n name -v '' \
    -u '$xstar:prev' -x '$templatename' \
main.xsl
  • 声明了一些命名空间绑定
  • 选择//mrd:distributionFormat[1]作为锚节点
  • 删除任何现有 xsl:call-template 锚点后的兄弟节点
  • 附加一个具有 name 属性的新 xsl:call-template 元素

xmlstarlet edit 代码可以使用方便的 $xstar:prev (又名 $prev) 节点引用最近创建的节点 -i / --insert-a / --append-s / --subnode 选项。 $xstar:prev 的例子在 doc/xmlstarlet.txt 和源代码的 examples/ed-backref*。 在显示的命令中,它的第一次使用是指 xsl:call-template 元素,name 属性的第二个。

编辑:事实证明xmlstarlet edit并不像我想的那么挑剔 这是一个替代的,更短的命令是(属性节点 可以添加 -s-i-a):

xmlstarlet edit \
    --var anchor '//mrd:distributionFormat[1]' \
    -d '$anchor/following-sibling::xsl:call-template' \
    -a '$anchor' -t elem -n 'xsl:call-template' -v '' \
    -s '$prev' -t attr -n name -v 'distributor-N.xsl' \
main.xsl

给定以下(演示)输入:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:mdb="urn:so70244776_mdb"
  xmlns:mrd="urn:so70244776_mrd"
>
   <xsl:template name="q">
      <mdb:distributionInfo>
         <mrd:MD_Distribution>
            <mrd:distributionFormat>
               <mrd:MD_Format>
                  <mrd:formatSpecificationCitation/>
               </mrd:MD_Format>
            </mrd:distributionFormat>
            <xsl:call-template name="distributor.xsl"/>
            <!-- x -->
            <xsl:call-template name="distributor-1.xsl"/>
            <mrd:transferOptions/>
         </mrd:MD_Distribution>
      </mdb:distributionInfo>
   </xsl:template>
</xsl:transform>

以上任一命令都会产生以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mdb="urn:so70244776_mdb" xmlns:mrd="urn:so70244776_mrd" version="1.0">
  <xsl:template name="q">
    <mdb:distributionInfo>
      <mrd:MD_Distribution>
        <mrd:distributionFormat>
          <mrd:MD_Format>
            <mrd:formatSpecificationCitation/>
          </mrd:MD_Format>
        </mrd:distributionFormat>
        <xsl:call-template name="distributor-N.xsl"/>
        <!-- x -->
        <mrd:transferOptions/>
      </mrd:MD_Distribution>
    </mdb:distributionInfo>
  </xsl:template>
</xsl:transform>

更改要求后

以下命令插入所需的 xsl:call-template 节点,其中 你想要的(详情见我的第一篇帖子),

xmlstarlet edit \
    -i '//mrd:transferOptions[1]' \
    -t elem -n 'xsl:call-template' -v '' \
    -s '$prev' -t attr -n name -v 'distributor.xsl' \
main.xsl

当 运行 在以下 XML 文件上时(根据需要调整名称空间):

<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:cit="urn:so70244776_cit"
  xmlns:gco="urn:so70244776_gco"
  xmlns:mdb="urn:so70244776_mdb"
  xmlns:mrd="urn:so70244776_mrd"
>
  <xsl:template name="x">
    <mdb:distributionInfo>
        <mrd:MD_Distribution>
           <mrd:distributionFormat>
              <mrd:MD_Format>
                 <mrd:formatSpecificationCitation>
                    <cit:CI_Citation>
                       <cit:title>
                          <gco:CharacterString>WCS</gco:CharacterString>
                       </cit:title>
                       <cit:date gco:nilReason="unknown"/>
                       <cit:edition>
                          <gco:CharacterString>2.0</gco:CharacterString>
                       </cit:edition>
                    </cit:CI_Citation>
                 </mrd:formatSpecificationCitation>
              </mrd:MD_Format>
           </mrd:distributionFormat>
           <mrd:transferOptions/>
        </mrd:MD_Distribution>
    </mdb:distributionInfo>
  </xsl:template>

</xsl:transform>