Reputation: 431
I want to be able to parse some values in browser-side (no Node etc.) Javascript from an XML of the following format:
<list>
<dict>
<key>BuildMachineOSBuild</key>
<string>16B2555</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>App AutoUpdate</string>
<key>CFBundleExecutable</key>
<string>App AutoUpdate</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>com.app.autoupdate2</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App AutoUpdate</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.8.1</string>
<key>CFBundleSignature</key>
<string>MSau</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>3.8.16112200</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>8B62</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>16B2649</string>
<key>DTSDKName</key>
<string>macosx10.12</string>
<key>DTXcode</key>
<string>0810</string>
<key>DTXcodeBuild</key>
<string>8B62</string>
<key>LSHasLocalizedDisplayName</key>
<true/>
<key>LSMinimumSystemVersion</key>
<string>10.10</string>
<key>LSRequiresNativeExecution</key>
<true/>
<key>MbuLoggingFullLegacyUpload</key>
<true/>
<key>AppBuildNumber</key>
<string>161122</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSMainNibFile</key>
<string>SAUMainWindow</string>
<key>NSPrincipalClass</key>
<string>SAUApplication</string>
</dict>
</list>
Specifically, I want to be able to parse the values of CFBundleIdentifier
and CFBundleShortVersionString
. Suppose, I want to store them in an object metadata = {id, version}
.
I learned from Parsing properties from certain nodes in XML using Javascript? how to parse data from XML nodes. The problem now is that unlike the abovementioned question, this format of XML doesn't store the values between the tags like so <CFBundleIdentifier>com.app.autoupdate2</CFBundleIdentifier>
, but, instead, the name of the property I want to parse is between <key>
tags and the property value follows after that--between the <string>
tags.
If it can be done using XPATH, how would I form the query in this situation?
Upvotes: 1
Views: 69
Reputation: 167571
Using JavaScript and the browser's XPath 1.0 evaluate
method:
const xml = `<list>
<dict>
<key>BuildMachineOSBuild</key>
<string>16B2555</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>App AutoUpdate</string>
<key>CFBundleExecutable</key>
<string>App AutoUpdate</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>com.app.autoupdate2</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App AutoUpdate</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.8.1</string>
<key>CFBundleSignature</key>
<string>MSau</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>3.8.16112200</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>8B62</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>16B2649</string>
<key>DTSDKName</key>
<string>macosx10.12</string>
<key>DTXcode</key>
<string>0810</string>
<key>DTXcodeBuild</key>
<string>8B62</string>
<key>LSHasLocalizedDisplayName</key>
<true/>
<key>LSMinimumSystemVersion</key>
<string>10.10</string>
<key>LSRequiresNativeExecution</key>
<true/>
<key>MbuLoggingFullLegacyUpload</key>
<true/>
<key>AppBuildNumber</key>
<string>161122</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSMainNibFile</key>
<string>SAUMainWindow</string>
<key>NSPrincipalClass</key>
<string>SAUApplication</string>
</dict>
</list>`;
const xmlDoc = new DOMParser().parseFromString(xml, 'application/xml');
console.log(["CFBundleIdentifier","CFBundleShortVersionString"].map(key => { return { [key] : xmlDoc.evaluate(`string(//key[. = '${key}']/following-sibling::*[1])`, xmlDoc, null, XPathResult.STRING_TYPE, null).stringValue };}));
Using JavaScript and Saxon-JS 2 to exploit XPath 3.1:
const xml = `<list>
<dict>
<key>BuildMachineOSBuild</key>
<string>16B2555</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>App AutoUpdate</string>
<key>CFBundleExecutable</key>
<string>App AutoUpdate</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>com.app.autoupdate2</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App AutoUpdate</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.8.1</string>
<key>CFBundleSignature</key>
<string>MSau</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>3.8.16112200</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>8B62</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>16B2649</string>
<key>DTSDKName</key>
<string>macosx10.12</string>
<key>DTXcode</key>
<string>0810</string>
<key>DTXcodeBuild</key>
<string>8B62</string>
<key>LSHasLocalizedDisplayName</key>
<true/>
<key>LSMinimumSystemVersion</key>
<string>10.10</string>
<key>LSRequiresNativeExecution</key>
<true/>
<key>MbuLoggingFullLegacyUpload</key>
<true/>
<key>AppBuildNumber</key>
<string>161122</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSMainNibFile</key>
<string>SAUMainWindow</string>
<key>NSPrincipalClass</key>
<string>SAUApplication</string>
</dict>
</list>`;
console.log(["CFBundleIdentifier","CFBundleShortVersionString"].map(key => SaxonJS.XPath.evaluate(`parse-xml($xml)//key[. = $key] ! map { $key : following-sibling::*[1]/string() }`, [], { params : { xml : xml, key : key } })));
<script src="https://www.saxonica.com/saxon-js/documentation/SaxonJS/SaxonJS2.rt.js"></script>
Upvotes: 2
Reputation: 24930
Try something along these lines:
#this assumes your xml string is assigned to xmldoc
let domElement = new DOMParser().parseFromString(xmldoc,'text/xml');
identifiers = ["CFBundleIdentifier","CFBundleShortVersionString"]
for (let id of identifiers){
exp = `//key[text()="${id}"]/following-sibling::string[1]/text()`;
let target = domElement.evaluate(exp, domElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
console.log(target.snapshotItem(0).nodeValue);
}
Output:
"com.app.autoupdate2"
"3.8.1"
You can then assign these to whatever variables you want.
Upvotes: 2