用于 MobileConfig 文件的 OS X 终端中的 XML 解析
Posted
技术标签:
【中文标题】用于 MobileConfig 文件的 OS X 终端中的 XML 解析【英文标题】:XML Parsing in OS X Terminal for MobileConfig file 【发布时间】:2015-06-23 06:24:41 【问题描述】:我正在通过 bash 脚本生成(实际上是编辑)一个 mobileconfig 文件(又名 ios 配置文件,XML)。
脚本从 MS 数据库中获取数据,现在必须在我的 mobileconfig 文件 (XML) 中注入/替换这些数据。
XML 文件的结构如下:
<?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>xxxxxxx@xxx.com</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>
我想使用任何本机(xmllint、sed)或非本机工具替换
有人可以帮忙吗?
【问题讨论】:
显然 /usr/libexec/PlistBuddy 是编辑 mobileconfig 的一个不错的选择(原生且专门用于处理 plist 文件) 【参考方案1】:使用纯文本工具编辑结构化数据(例如 XML)时,当文件格式以没人期望的方式改变(例如插入良性空白)时,总是以痛苦告终。相反,请使用能够正确解析 XML 并在树上工作的工具,例如 xmlstarlet
。
这个的一般形式是
xmlstarlet ed -u xpath -v value filename.xml
其中xpath
是一个XPath 表达式,用于标识您要更新的节点,value
是您要为其赋予的新值。神奇之处在于构造一个 XPath 表达式,该表达式唯一且可靠地标识您要更新的节点。 MobileConfig XML 格式使这比平时更难。在 cmets 讨论后,我们最终得到了
xmlstarlet ed -u '//dict[key[text() = "PayloadDisplayName"]/following-sibling::string[1] = "Exchange ActiveSync"]/key[text() = "Password"]/following-sibling::string[1]' -v 'abc123' filename.xml
这个的核心是XPath表达式
//dict[key[text() = "PayloadDisplayName"]/following-sibling::string[1] = "Exchange ActiveSync"]/key[text() = "Password"]/following-sibling::string[1]
..这需要一些解释。我们使用以下功能:
//dict
匹配文档中的任何 dict
节点,
//dict/key
匹配作为 dict
节点的子节点的任何 key
节点,
//dict/key[text() = "Password"]
匹配作为 dict
节点的子节点并包含文本 Password
的任何 key
注释,
//dict/key[text() = "Password"]/following-sibling
匹配此类 key
节点的任何后续兄弟节点,即任何属于同一父节点的子节点并且位于 XML 中 key
节点之后的任何节点,
//dict/key[text() = "Password"]/following-sibling::string
匹配任何 string
节点,它是这样的后续兄弟节点,并且
//dict/key[text() = "Password"]/following-sibling::string[1]
匹配作为此类key
节点的第一个后续兄弟string
节点的任何节点。
我们已经在//dict/key[text() = "Password"]
中使用了一个条件;为了找到要更改密码条目的dict
节点,我们需要更多信息。我们要查找的dict
节点由
//dict[key[text() = "PayloadDisplayName"]/following-sibling::string[1] = "Exchange ActiveSync"]
即满足条件的dict
节点
key[text() = "PayloadDisplayName"]/following-sibling::string[1] = "Exchange ActiveSync"
此条件下的 XPath 表达式都与正在测试的 dict
节点相关,所以
key[text() = "PayloadDisplayName"]
指的是包含文本PayloadDisplayName
的dict
节点的key
子节点,并且
key[text() = "PayloadDisplayName"]/following-sibling::string[1] = "Exchange ActiveSync"
如果包含文本 PayloadDisplayName
的 key
节点之后的 string
节点中的文本是 Exchange ActiveSync
,则为真。因此,我们将其放入我上面解释过的简化表达式中并获得完整的过滤器。
我不得不指出,这个 XML 文件的结构使整个事情变得比必要或通常更困难。结构合理的 XML 可以用更简单的 XPath 表达式来处理(大多数时候)。
【讨论】:
谢谢 Wintermute,我会试试这个工具并回复你。我很高兴看到 Brew 有一个可以使用的瓶子 :) 嘿,伙计,你的解决方案听起来很完美,我试过了,它就像一个魅力,只有小故障,我有两个“密码”树(我编辑了我的原始帖子)。可以请教吗? 这只是在 XPath 中编码选择标准的问题。不过,根据已编辑问题中的描述,我并不完全确定您的选择标准是什么——比如更改dict
条目中的密码,其PayloadDisplayName
是Exchange ActiveSync
?请澄清。
所以,我有两个 /plist/dict/array/dict[1]/key[text() = "Password"]/following-sibling::string[1]
,但我不确定我是否愿意依赖它。问题是:如何可靠地识别包含您要更改的密码的dict
节点?【参考方案2】:
你可以这样做
sed -r "s#(<string>)SSID_STR(</string>)#\1AMD\2#g" File
对于就地替换:
sed -i -r "s#(<string>)SSID_STR(</string>)#\1AMD\2#g" File
(
, )
用于分组。 \1
和 \2
代表 first
和 second
这样的组。
用您的实际内容替换 AMD。同样,你可以为密码做。
【讨论】:
感谢您的努力,理想情况下我会寻找一个特定于 xml 的解析工具以上是关于用于 MobileConfig 文件的 OS X 终端中的 XML 解析的主要内容,如果未能解决你的问题,请参考以下文章
当我单击网页上的按钮时生成 .mobileconfig 文件
在 Safari ios 中打开保存在应用程序中的 .mobileconfig 文件