I am working on generating (actually editing) a mobileconfig file (aka iOS profile, XML) via bash script.
The script fetch data from a MS Database and has now to inject/replace this data in my mobileconfig file (XML).
The XML file has the following structure:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PayloadContent</key>
    <array>
        <dict>
            <key>Host</key>
            <string>outlook.office365.com</string>
            <key>MailNumberOfPastDaysToSync</key>
            <integer>7</integer>
            <key>Password</key>
            <string>ActiveSyncPassword</string>
            <key>PayloadDescription</key>
            <string>Configures an Exchange account</string>
            <key>PayloadDisplayName</key>
            <string>Exchange ActiveSync</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <key>SSL</key>
            <true/>
            <key>UserName</key>
            <string>[email protected]</string>
            <key>disableMailRecentsSyncing</key>
            <false/>
        </dict>
        <dict>
            <key>AutoJoin</key>
            <true/>
            <key>EncryptionType</key>
            <string>WPA</string>
            <key>HIDDEN_NETWORK</key>
            <true/>
            <key>IsHotspot</key>
            <false/>
            <key>Password</key>
            <string>WEPWPAWPSPEAPTLS</string>
            <key>PayloadType</key>
            <string>com.apple.wifi.managed</string>
            <key>PayloadVersion</key>
            <real>1</real>
            <key>ProxyType</key>
            <string>None</string>
            <key>SSID_STR</key>
            <string>SSID</string>
        </dict>
        <dict>
I would like to replace the WiFi Password but also ActiveSync "Password" fields between the < string> < /string> using any native (xmllint, sed) or non-native tool.
Can anyone please help ?
                        
Editing structured data (such as XML) with plain-text tools invariably ends in misery when the file format changes in ways that nobody expects to make a difference (such as inserting benign whitespace). Instead, use a tool that parses XML properly and works on the tree, such as
xmlstarlet.The general form for this is
Where
xpathis an XPath expression that identifies the node you want to update, andvalueis the new value you want to give it. The magic is in constructing an XPath expression that uniquely and reliably identifies the node you want to update. The MobileConfig XML format makes this somewhat harder than usual; after discussion in the comments we ended up withThe core of this is the XPath expression
..which requires some explanation. We use the following features:
//dictmatches anydictnode in the document,//dict/keymatches anykeynode that is the child of adictnode,//dict/key[text() = "Password"]matches anykeynote that is the child of adictnode and contains the textPassword,//dict/key[text() = "Password"]/following-siblingmatches any following sibling node of such akeynode, which is to say any node that is a child of the same parent and comes after thekeynode in the XML,//dict/key[text() = "Password"]/following-sibling::stringmatches anystringnode that is such a following sibling node, and//dict/key[text() = "Password"]/following-sibling::string[1]matches any node that is the first following siblingstringnode of such akeynode.We've already used a condition in
//dict/key[text() = "Password"]; in order to find thedictnode whose password entry is to be changed, we need more of that. Thedictnode we want to find is identified byThat is a
dictnode that fulfills the conditionThe XPath expressions in this condition are all relative to the
dictnode that's being tested, sorefers to a
keysubnode of thatdictnode that contains the textPayloadDisplayName, andis true if the text in the
stringnode that follows thekeynode that contains the textPayloadDisplayNameisExchange ActiveSync. So we chuck that into the simplified expression I explained above and get the full filter.I feel compelled to point out that the structure of this XML file makes the whole thing more difficult than necessary or usual. Sanely structured XML can be handled with much simpler XPath expressions (most of the time).