Home > Mobile >  Add a new element exactly after the existing same one
Add a new element exactly after the existing same one

Time:01-31

I am trying to modify the server.xml file of the Apache Tomcat. I would like to add a new element exactly after the last Connector definition but my solution adds the new content at the end of the Service, not after the last Connector.

This is my XML:

(I removed the irrelevant attributes and elements from the real XML to make it more readable)

<?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>

My xmlstarlet code inserts the desired content, but the position of the new Connector element is wrong.

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

Result:

<?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>

But I want to have the new Connector after the existing one:

<?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"/>

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

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

What I missed in my code?

CodePudding user response:

Try:

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

CodePudding user response:

With xmlstarlet edit option -s adds a node as last child, -i as preceding sibling, and -a as following sibling, to each member of their XPath argument. With -t attr they all add an attribute and have no influence on attribute order.

xmlstarlet edit \
  -a '/Server/Service[@name="Catalina"]/Connector[last()]' -t elem -n 'Connector' \
  --var T '$prev' \
  -s '$T' -t attr -n port -v '443' \
  -s '$T' -t attr -n protocol -v 'org.apache.coyote.http11.Http11NioProtocol' \
file.xml

--var defines a named variable, and the back reference $prev variable (aka $xstar:prev) refers to the node(s) created by the most recent -s, -i, or -a option which all define or redefine it (see xmlstarlet.txt for examples of --var and $prev).

  • Related