Hi I've the following file.
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="" xmlns:uap="" IgnorableNamespaces="">
<Identity Name="xxxxxxxxxx" Publisher="CN=$username$" Version="xxxx"/>
<mp:PhoneIdentity PhoneProductId="xxxxxxxxxxx" PhonePublisherId=""/>
<Properties>
<DisplayName>xxxxxxxxxx</DisplayName>
<PublisherDisplayName>xxxxxxxx</PublisherDisplayName>
<Logo>images\StoreLogo.png</Logo>
<Description>A sample Apache Cordova application that responds to the deviceready event.</Description>
</Properties>
<Dependencies>
<TargetDeviceFamily MaxVersionTested="" MinVersion="" Name="Windows.Universal"/>
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="" StartPage="">
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient"/>
<DeviceCapability Name="webcam"/>
<DeviceCapability Name="location"/>
</Capabilities>
</Package>
I wanted to insert under the Capabilities element. So, the output should look like
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="" xmlns:uap="" IgnorableNamespaces="">
<Identity Name="xxxxxxxxxx" Publisher="CN=$username$" Version="xxxx"/>
<mp:PhoneIdentity PhoneProductId="xxxxxxxxxxx" PhonePublisherId=""/>
<Properties>
<DisplayName>xxxxxxxxxx</DisplayName>
<PublisherDisplayName>xxxxxxxx</PublisherDisplayName>
<Logo>images\StoreLogo.png</Logo>
<Description>A sample Apache Cordova application that responds to the deviceready event.</Description>
</Properties>
<Dependencies>
<TargetDeviceFamily MaxVersionTested="" MinVersion="" Name="Windows.Universal"/>
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="" StartPage="">
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient"/>
<Capability Name="privateNetworkClientServer"/>
<DeviceCapability Name="webcam"/>
<DeviceCapability Name="location"/>
</Capabilities>
</Package>
To achieve the above I'm using XMLStarlet as below.
xmlstarlet ed \
-a '/Package/Capabilities' -t elem -n Capability \
-i '/Package/Capabilities/Capability' -t attr -n Name -v privateNetworkClientServer \
<inputfile >outputfile
The output I'm getting is the same without any modifications. Am I doing anything silly.
CodePudding user response:
If I strip out all the namespace-related stuff, then
xmlstarlet ed \
-a '/Package/Capabilities/Capability[last()]' -t elem -n 'Capability' \
-a '/Package/Capabilities/Capability[last()]' -t attr -n Name -v privateNetworkClientServer \
inputfile.no_namespace
adds the node after the last Capability:
<?xml version="1.0" encoding="utf-8"?>
<Package IgnorableNamespaces="">
...
<Capabilities>
<Capability Name="internetClient"/>
<Capability Name="privateNetworkClientServer"/>
<DeviceCapability Name="webcam"/>
<DeviceCapability Name="location"/>
</Capabilities>
</Package>
However, with your given XML, xmlstarlet spits out errors:
$ xmlstarlet ... inputfile
inputfile:2.93: xmlns:mp: Empty XML namespace is not allowed
ns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp=""
^
inputfile:2.106: xmlns:uap: Empty XML namespace is not allowed
hemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="" xmlns:uap=""
^
inputfile:4.69: Namespace prefix mp on PhoneIdentity is not defined
<mp:PhoneIdentity PhoneProductId="xxxxxxxxxxx" PhonePublisherId=""/>
^
[original XML here]
You're dealing with invalid XML, and xmlstarlet is not very forgiving.
CodePudding user response:
The target node exists in the default namespace so adjust your XPath expression:
xmlstarlet edit \
-a '/_:Package/_:Capabilities/_:Capability[last()]' -t elem -n 'Capability' \
-s '$prev' -t attr -n Name -v 'privateNetworkClientServer' \
file.xml
- using the _ (underscore) shortcut
since the default namespace is declared in the root element
(option
--doc-namespace
being in effect) - the
$prev
(aka$xstar:prev
) variable refers to the node created by the most recent-i (--insert)
,-a (--append)
, or-s (--subnode)
; examples of$prev
are given in doc/xmlstarlet.txt.
Due to a bug in xmlstarlet edit
(see this)
the $prev
back reference is required when referencing a
newly created element which is not in the null namespace.
Since xmlstarlet edit
(unlike xmlstarlet select
) isn't an XSLT
processor it'll accept stuff -- such as xmlns:mp=""
-- XSLT processors
will reject as non-XML.