You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用xmlstarlet在Tomcat的server.xml最后一个Connector后添加元素?

解决Tomcat server.xml中用xmlstarlet在最后一个Connector后添加新Connector的问题

我正在修改Apache Tomcat的server.xml文件,想在最后一个<Connector>定义后添加一个新的<Connector>元素,但当前用xmlstarlet写的代码把新元素加到了<Service>的末尾,而不是目标位置。

原XML内容(简化后):

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
    <Listener className="org.aaa"/>
    <Listener className="org.bbb" SSLEngine="on"/>
    <GlobalNamingResources>
        <Resource name="UserDatabase" auth="Container"/>
    </GlobalNamingResources>
    <Service name="Catalina">

        <Connector port="8080" protocol="HTTP/1.1"/> 
        <!-- INSERT A NEW CONNECTOR HERE -->

        <Engine name="Catalina" defaultHost="localhost">
            <Realm className="aa">...</Realm>
        </Engine>
    </Service>
</Server>

错误的xmlstarlet命令:

xmlstarlet edit \
    -s "//Server/Service[last()]" -t elem -n "Connector" \
    -s "//Server/Service[last()]/Connector" -t attr -n port -v "443" \
    -s "//Server/Service/Connector[@port='443']" -t attr -n protocol -v "org.apache.coyote.http11.Http11NioProtocol" \
    1.xml

执行后的错误结果:

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.aaa"/>
  <Listener className="org.bbb" SSLEngine="on"/>
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"/>
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1" port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"/>
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="aa">...</Realm>
    </Engine>

    <Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"/>

  </Service>
</Server>

期望的正确结果:

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.aaa"/>
  <Listener className="org.bbb" SSLEngine="on"/>
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"/>
  </GlobalNamingResources>
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"/>

    <Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"/>

    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="aa">...</Realm>
    </Engine>
  </Service>
</Server>

问题分析与解决方案

你的代码存在两个核心问题:

  1. 第一个-s命令是在<Service>节点内部添加子元素,默认会把新元素放到<Service>的末尾(即<Engine>之后),而非在最后一个<Connector>之后添加同级元素。
  2. 第二个-s命令的XPath匹配了<Service>下所有<Connector>,导致给原有8080端口的<Connector>错误添加了重复的port和protocol属性。

修正后的命令(基础版)

xmlstarlet edit \
    -a "//Server/Service[last()]/Connector[last()]" -t elem -n "Connector" \
    -s "//Server/Service[last()]/Connector[last()]" -t attr -n port -v "443" \
    -s "//Server/Service[last()]/Connector[last()]" -t attr -n protocol -v "org.apache.coyote.http11.Http11NioProtocol" \
    1.xml

命令解释:

  • -a选项表示在指定节点之后添加同级元素,目标节点//Server/Service[last()]/Connector[last()]精准定位到<Service>下最后一个<Connector>,确保新元素出现在正确位置。
  • 后续添加属性时,同样用//Server/Service[last()]/Connector[last()]定位刚创建的新<Connector>(此时它是最后一个),避免影响原有节点。

更精准的版本(用变量标记新元素)

如果担心后续XML结构变化导致定位偏差,可以用--var标记新创建的元素:

xmlstarlet edit \
    --var newConnector -a "//Server/Service[last()]/Connector[last()]" -t elem -n "Connector" \
    -s "$newConnector" -t attr -n port -v "443" \
    -s "$newConnector" -t attr -n protocol -v "org.apache.coyote.http11.Http11NioProtocol" \
    1.xml

内容的提问来源于stack exchange,提问作者zappee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 23:30:53