I'm trying to automate adding new subnodes to nexus-core-feature-3.16.1-02.xml Because we are using some plugins for work that not come with "box" solution. The main point that when new version of the nexus-container releases I have a bash-script that runs new test-container version and copies the new default-xml file to a proper folder. The next step is to redact this file and add some new features to make plug-in work. When this done old container stops, new xml-replace old one and I'm starting a docker-container with mapped nexus-data and default-xml. For proper work of this plug-in I need to add some changes to the default-xml file. And I want to use xmlstarlet for that. Add this to "nexus-core-feature" section:
<feature version="1.0.9" prerequisite="false" dependency="false">nexus-repository-apt</feature>
</feature>
And this to the end of the file xml-file
<feature name="nexus-repository-apt" description="net.staticsnow:nexus-repository-apt" version="1.0.10">
<details>net.staticsnow:nexus-repository-apt</details>
<bundle>mvn:net.staticsnow/nexus-repository-apt/1.0.10</bundle>
<bundle>mvn:org.apache.commons/commons-compress/1.18</bundle>
<bundle>mvn:org.tukaani/xz/1.8</bundle>
</feature>
</features>
So I was google and SO for a while but I'm still stuck. For example this case: How to insert a new element under another with xmlstarlet?
It seems pretty straightforward to do something similar and I tried this:
xmlstarlet ed -s /features/feature/feature -t elem -n featureTMP -v "nexus-apt-repositroy" \
-i //featureTMP -t attr -n "version" -v "1.0.9" \
-i //featureTMP P -t attr -n "prerequisite" -v "false" \
-i //featureTMP -t attr -n "dependency" -v "false" \
-r //featureTMP -v feature nexus-core-feature-3.16.1-02-features.xml
I suspect that my mistake was (and is) in nodes path.
Next step was to examine nodes
xmlstarlet sel -t -c "/" nexus-core-feature-3.16.1-02-features.xml
Output was the whole xml-file and it seems to be fine
<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="nexus-core-feature">
<feature name="nexus-core-feature" description="org.sonatype.nexus.assemblies:nexus-core-feature" version="3.16.1.02">
<details>org.sonatype.nexus.assemblies:nexus-core-feature</details>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-audit-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-blobstore-tasks</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-ssl-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-coreui-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-repository-httpbridge</feature>
...
But when I try to get into the node the result is always empty:
xmlstarlet sel -t -c "/features" nexus-core-feature-3.16.1-02-features.xml
With attribute selector it's still empty:
xmlstarlet sel -t -c "/features/feature[@name="nexus-core-feature"]" nexus-core-feature-3.16.1-02-features.xml
Tried to chek this in XPath-online tester and inside of tester everything OK.
Next I use more simple example in this article: https://unix.stackexchange.com/questions/386965/insert-custom-xml-tag-into-a-xml-file-in-a-bash-script
and tried to navigate throught example file that was in arctilce and it seems to be fine.
xmlstarlet sel -t -c "/server-groups" file.xml
output:
<server-groups>
<server-group name="main-server-group" profile="full">
<jvm name="default">
<heap size="64m" max-size="512m"/>
<jvm-options>
<option value="somevalue"/>
</jvm-options>
</jvm>
<socket-binding-group ref="full-sockets"/>
</server-group>
</server-groups>
Next step
xmlstarlet sel -t -c "/server-groups/server-group/jvm" file.xml
output:
<jvm name="default">
<heap size="64m" max-size="512m"/>
<jvm-options>
<option value="somevalue"/>
</jvm-options>
</jvm>
And it's very confusing for me... Why the same approach doesn't work with nexus-xml file? More complex\strange structure? Will be glad for any advise
Why the same approach doesn't work with nexus-xml file?
It's because your nexus XML file is in a default namespace (http://karaf.apache.org/xmlns/features/v1.4.0
).
If you're using xmlstarlet version 1.0.5 or later, you can use _:
in your XPath to match any namespace. Otherwise you'll have to bind the namespace to a prefix with -N
. See here for more info.
Here's an updated example of your first attempt:
xmlstarlet ed -s /_:features/_:feature -t elem -n featureTMP -v "nexus-repository-apt" \
-i //featureTMP -t attr -n "version" -v "1.0.9" \
-i //featureTMP -t attr -n "prerequisite" -v "false" \
-i //featureTMP -t attr -n "dependency" -v "false" \
-r //featureTMP -v feature nexus-core-feature-3.16.1-02-features.xml
Here's the alternative approach of using -N
...
xmlstarlet ed -N f="http://karaf.apache.org/xmlns/features/v1.4.0" -s /f:features/f:feature -t elem -n featureTMP -v "nexus-repository-apt" \
-i //featureTMP -t attr -n "version" -v "1.0.9" \
-i //featureTMP -t attr -n "prerequisite" -v "false" \
-i //featureTMP -t attr -n "dependency" -v "false" \
-r //featureTMP -v feature nexus-core-feature-3.16.1-02-features.xml
Both of these produce the following output:
<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="nexus-core-feature">
<feature name="nexus-core-feature" description="org.sonatype.nexus.assemblies:nexus-core-feature" version="3.16.1.02">
<details>org.sonatype.nexus.assemblies:nexus-core-feature</details>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-audit-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-blobstore-tasks</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-ssl-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-coreui-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-repository-httpbridge</feature>
<feature version="1.0.9" prerequisite="false" dependency="false">nexus-repository-apt</feature>
</feature>
</features>
Adding your second feature
can be done the same way, but you could also simplify the whole thing by using XSLT in xmlstarlet with the tr command. (It's simpler in my opinion anyway.)
XSLT (test.xsl)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://karaf.apache.org/xmlns/features/v1.4.0"
xmlns="http://karaf.apache.org/xmlns/features/v1.4.0"
exclude-result-prefixes="f">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="f:features">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<feature name="nexus-repository-apt" description="net.staticsnow:nexus-repository-apt" version="1.0.10">
<details>net.staticsnow:nexus-repository-apt</details>
<bundle>mvn:net.staticsnow/nexus-repository-apt/1.0.10</bundle>
<bundle>mvn:org.apache.commons/commons-compress/1.18</bundle>
<bundle>mvn:org.tukaani/xz/1.8</bundle>
</feature>
</xsl:copy>
</xsl:template>
<xsl:template match="f:feature[@name='nexus-core-feature']">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<feature version="1.0.9" prerequisite="false" dependency="false">nexus-repository-apt</feature>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
xmlstarlet command
xmlstarlet tr test.xsl nexus-core-feature-3.16.1-02-features.xml
Output
<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="nexus-core-feature">
<feature name="nexus-core-feature" description="org.sonatype.nexus.assemblies:nexus-core-feature" version="3.16.1.02">
<details>org.sonatype.nexus.assemblies:nexus-core-feature</details>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-audit-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-blobstore-tasks</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-ssl-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-coreui-plugin</feature>
<feature version="3.16.1.02" prerequisite="false" dependency="false">nexus-repository-httpbridge</feature>
<feature version="1.0.9" prerequisite="false" dependency="false">nexus-repository-apt</feature>
</feature>
<feature name="nexus-repository-apt" description="net.staticsnow:nexus-repository-apt" version="1.0.10">
<details>net.staticsnow:nexus-repository-apt</details>
<bundle>mvn:net.staticsnow/nexus-repository-apt/1.0.10</bundle>
<bundle>mvn:org.apache.commons/commons-compress/1.18</bundle>
<bundle>mvn:org.tukaani/xz/1.8</bundle>
</feature>
</features>