XML命令行(shell脚本)操作


9

如何在Shell脚本中从命令行操作XML?

有许多用于处理表格数据,替换环境变量或用正则表达式替换文本片段的命令,但是我还没有发现任何针对XML的命令。

我的构建脚本需要在xml文档的主标签中插入一个带有内容的标签,为此我发现在OS中安装Java,Perl或python是一个杀手kill脚(我的脚本是在gitlab中使用docker镜像完成的,因此我的工作使用maven:3.5-jdk-8图片中可用的工具将是一个梦想)。

我不想用sed处理XML,尽管在我的构建脚本中它可以工作,因为它很邪恶

示例:我有以下xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>  
  <!-- a lot of other tags-->
</project>  

我想插入以下代码块:

<distributionManagement>
    <repository>
        <id>private-releases</id>
        <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
</distributionManagement>

在项目代码中(并且无论是在开始还是结束时都没有关系。


发布您的输入xml和预期的输出
RomanPerekhrest

因此,对XML解析器的特定要求是可以从命令行调用的,而该解析器不是在任何主要脚本语言中实现的,而是独立的C或C ++(或其他编译的)实用程序?
库萨兰达

@Kusalanda我已指定我正在docker容器中运行scipts,所以对我来说最重要的是向docker映像中添加尽可能少的内容。
9ilsdx 9rvj 0lo

如果您有一个带有maven和jdk的图像,那么Java听起来对我来说是最好的选择....为什么在这种情况下您认为Java重量级?
丹尼尔·普里登

在Stack Overflow和进行标记时可能值得提出这个问题maven-我怀疑有一种更好的方法可以在Maven本身中完成您想做的事情。
丹尼尔·普里登

Answers:


10

XMLStarlet(http://xmlstar.sourceforge.net/overview.php)用C编写,并使用libxml2libxslt

给定XML文档

<?xml version="1.0"?>
<root>
  <tag>data</tag>
</root>

root可以使用插入一个子节点

xml ed -s '/root' -t elem -n 'newtag' -v 'newdata' file.xml

产生

<?xml version="1.0"?>
<root>
  <tag>data</tag>
  <newtag>newdata</newtag>
</root>

插入许多内容(使用file.xml此处顶部的原始内容):

xml ed -s '/root' -t elem -n 'newtag' \
       -s '/root/newtag' -t elem -n 'subtag' -v 'subdata' file.xml

这产生

<?xml version="1.0"?>
<root>
  <tag>data</tag>
  <newtag>
    <subtag>subdata</subtag>
  </newtag>
</root>

对于问题中的示例:

xml ed -N x="http://maven.apache.org/POM/4.0.0" \
       -s '/x:project' -t elem -n 'distributionManagement' \
       -s '/x:project/distributionManagement' -t elem -n 'repository' \
       -s '/x:project/distributionManagement/repository' -t elem -n 'id' \
         -v 'private-releases' \
       -s '/x:project/distributionManagement/repository' -t elem -n 'url' \
         -v 'https://my.private.server.com/nexus/repository/maven-releases/' \
    file.xml

结果:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- a lot of other tags-->
  <distributionManagement>
    <repository>
      <id>private-releases</id>
      <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

在XML中的某个位置插入先前准备好的XML文件:

假设来自问题的原始XML已经放入,file.xml并且应该在新distributinManagement节点中添加其他位new.xml(但不是节点标签本身),则可以执行以下操作以插入new.xml根节点:

xml ed -N x="http://maven.apache.org/POM/4.0.0" \
       -s '/x:project' -t elem -n 'distributionManagement' \
       -v "$(<new.xml)" file.xml | xml unesc | xml fo

XMLStarlet将自动转义需要转义的数据,例如<>字符。该xml unesc取消转义插入的数据(实际上取消转义整个文档,这可能是问题,也可能不是问题),并xml fo重新格式化生成的XML文档。

结果是

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- a lot of other tags-->
  <distributionManagement>
    <repository>
      <id>private-releases</id>
      <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

用这种方式我有点不安,“但它能起作用”。

另请参阅StackOverflow上的相关问题:https ://stackoverflow.com/questions/29298507/xmlstarlet-xinclude-xslt


看起来很有趣,尽管对于插入多个标签来说,语法很长。仅在ubuntu中将其命名为“ xmlstarlet”。假设内容是有效的xml,是否可以将其他文件的内容作为标记插入?
9ilsdx 9rvj 0lo

@ 9ilsdx9rvj0lo查看最新答案。
库萨兰达

“它实际上使整个文档脱轨,这可能是问题,也可能不是问题”。是的,所有现有的&amp; 被未编码导致XML不再有效:(
rob

1

我发现为此目的在操作系统中安装java,perl或python是一个杀手((我的脚本是在gitlab中使用docker镜像完成的,因此使用maven:3.5-jdk-8镜像中可用的工具来做我的工作将是一个梦想)。

它可能仍然过高,但是如果您只关心容器的大小,则可以使用非常轻量级的语言,例如Lua或Guile。

从Lua文档中:

将Lua添加到应用程序不会使其膨胀。Lua 5.3.4的压缩文件包含源代码和文档,压缩后为297K,未压缩时为1.1M。该源包含大约24000行C。在64位Linux下,使用所有标准Lua库构建的Lua解释器需要246K,而Lua库则需要421K。


值得考虑的是,只需将LUA添加到Maven容器中,谢谢。
9ilsdx 9rvj 0lo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.