如何用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>
问题分析与解决方案
你的代码存在两个核心问题:
- 第一个
-s命令是在<Service>节点内部添加子元素,默认会把新元素放到<Service>的末尾(即<Engine>之后),而非在最后一个<Connector>之后添加同级元素。 - 第二个
-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
相关产品推荐
相关产品推荐

