I’m new to applescript and I’m trying to use it for creating some tools for work.
I used to be a programmer a long time ago (assembly, C, bit of Java) so this is all very strange to me. However, I read a lot of tutorials here and there and was able to concatenate some pieces of code.
I’d like to use the XMLFind command to parse specific data from an XML file.
Since I did not know how to use it, I wrote myself some Find command that is unfortunately very rigid and and change to the XML tag I’m looking for is a consequent work in itself (for me ;)).
Here’s an example of the XML file I’m looking into:
Basically, I’d like to understand how to format my XMLFind command to be able to (for example):
list all ‘scenario’ containing a ‘configuration’ that has a specific value
list all ‘scenario’ with an ‘operation’ name “SetUp”
I guess that with this as a start I’ll be able to extend to my other needs as they rise.
XMLLib is an OSAX by Satimage Software. I haven’t played around with it much myself, but there’s a tutorial here on Satimage’s Web site. Maybe you’ll be able to glean what you want from it.
One thing I’ve noticed while trying the first few examples in the tutorial is that the ‘XMLDisplay’ command shown compiles to ‘XMLNodeInfo’ in Script Editor on my machine. That just means Emmanuel’s changed his mind about what the command should be called since he wrote the tutorial. Don’t worry when you see it happen!
Edit:
Thinking about it further, what you want may be easier with System Events’s XML Suite:
set XML_path to (path to desktop as Unicode text) & "Test.xml"
tell application "System Events"
tell contents of XML file XML_path
tell XML element "package"
tell (first XML element whose name is "initial-state" and value of XML attribute "name" is "SECURED")
set RSASupportedScenarii to XML elements whose name is "scenario" and value of XML attribute "name" of (XML elements whose name is "configuration") contains "RSA_Supported"
set setupScenarii to XML elements whose name is "scenario" and value of XML attribute "name" of XML element "operation" of XML element "call" of XML element "preamble" is "SetUp"
end tell
end tell
end tell
end tell
I prefer to use an XSL file to parse XML. It is built for the purpose; though it can be a bit cryptic at first glance. You can then use the built-in Unix xsltproc command to transform the xml via the xsl.
First I’ll put the xsl file contents (2 files), for the two ways you wanted to search. These forums always translate the XML/HTML line endings entities, which is annoying; don’t know how to stop that; but read the comment.
To get the scenarios which match a configuration name (this is an xsl file):
xsl:textXML/HTML line feed entity here</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
To use each of the two files above to parse the original XML file (AppleScript):
set xml_file to quoted form of POSIX path of (choose file with prompt "XML File")
set xsl_file to quoted form of POSIX path of (choose file with prompt "XSL File")
-- return results here
set txt to do shell script "xsltproc " & xsl_file & " " & xml_file
set lst to paragraphs of txt
To Nigel:
I have started my script with the tutorial from satimage, practised for a few days but the issue I had was that the XML format of my file is not the same as the one they use in their example. I’m sorry, there’s probably some accurate name to qualify the differences but I’m no XML expert.
Their XML file is like
Basically they use only tags with values whereas I also have attributes and I tend to mix all up
This is why I do not know how to format a XMLFind request to cope with my XML format.
But I might as well try your option which does not require any extra library (better). I did not know it was possible to do that with System Events.
I think I’ll give it a shot.
To Fenton:
I discovered xsl and it looks a bit tough to setup. The problem I see is that I need to create a dedicated xsl file for each configuration I need to find.
I was looking for something flexible and it does not look this way to me (at this moment).
I’m sorry but I think I’ll try Nigel’s proposal before anything else.
For example, here’s a bit of my script parsing my file with my own construction of a XMLFind-like:
to parseXMLForConfiguration(configurationSearchLocal, outputFileLocal, inputFileLocal)
try
-- open the package file
set XMLFile to XMLOpen inputFileLocal
-- set the root of the file and get its size
set rootPackage to XMLRoot XMLFile
set packageSize to XMLCount rootPackage
set initialStateNumber to 1
repeat -- loop on initial states at package level
repeat -- find an initial state not empty
set initialState to XMLChild rootPackage index initialStateNumber without all nodes
set maxNumberOfScenarios to XMLCount initialState
if maxNumberOfScenarios = 0 then
set initialStateNumber to initialStateNumber + 1
else
exit repeat
end if
end repeat -- from here we have a not empty initialState node
set initialStateName to XMLGetAttribute initialState name "name"
set scenarioNumber to 1
repeat -- loop on scenarios at initial state level
set currentScenario to XMLChild initialState index scenarioNumber
set scenarioSize to XMLCount currentScenario
set configurationParsed to false
if scenarioSize is not 0 then
-- scenario is not empty
set currentScenarioName to (XMLGetAttribute currentScenario name "name")
set scenarioNodeNumber to 1
repeat -- loop at scenario node level
set scenarioNode to XMLChild currentScenario index scenarioNodeNumber
if (XMLTagName scenarioNode) is not equal to "configuration" then
if configurationParsed then exit repeat
else
-- if node is a configuration
set configurationParsed to true
set configName to XMLGetAttribute scenarioNode name "name" -- retrieve config name
if configName is equal to configurationSearchLocal then
-- store the config name & scenario & init state & package
write (XMLGetAttribute rootPackage name "name") & " > " & initialStateName & " > " & currentScenarioName & " > " & configName & " vs. " & configurationSearchLocal & crlf to outputFileLocal
end if
end if
set scenarioNodeNumber to scenarioNodeNumber + 1
if (scenarioNodeNumber ≥ scenarioSize + 1) then exit repeat
end repeat
end if
set scenarioNumber to scenarioNumber + 1
if (scenarioNumber ≥ maxNumberOfScenarios + 1) then exit repeat
end repeat
write "------> " & initialStateName & " index " & (initialStateNumber as string) & " of " & (packageSize as string) to outputFileLocal
display dialog "completed for " & initialStateName & " index " & (initialStateNumber as string) & " of " & (packageSize as string) giving up after 3
set initialStateNumber to initialStateNumber + 1
if (initialStateNumber ≥ packageSize) then exit repeat
end repeat
display dialog "Package " & (XMLGetAttribute rootPackage name "name") & " finished"
XMLClose XMLFile
on error return
end try
end parseXMLForConfiguration
Well, I know it’s rookie’s style but it made me happy
Hopefully I find some more optimized way soon.
Thanx for your help, I appreciate any comment on how to improve my code :lol:
long time no post but I have been using my little scripts for a while. They work ok, simply very complicated.
So now I have to do more complicated work on my XML files.
My first problem here is fairly simple:
I’ve been trying the script from Nigel, using different combinations and they seem to return “stuff”.
But my ignorance in applescript is such that I don’t know how to read the content of RSASupportedScenarii (for ex).
I’d like to output it to a file but I need to put my hands on the properties.
OK, I made some progress. I can get the name of a scenario with:
get value of XML attribute “name” of (item i of RSASupportedScenarii) as string
Next challenge, being able to get the scenarios from all initial-state and not only from one. The goal is not to have to enumerate them because it might be non-exhautive.
Sorry I’ve been quite occupied this weekend. Also, I’ve found that, on my system, the items in the lists returned by my script are unusable. When I try to extract their properties, values, etc. I get an error saying they’re invalid references. (That is, they’re invalid object specifiers. I can get their properties using the filter references which return them. Weird.) I don’t know if this is a glitch in my system, a bug in System Events’s XML Suite, or something to do with the way I’ve stitched up the bleeding stump of your XML fragment to work on the script. It would also help to know exactly what is (or might be) in the full XML and what information you want to extract from it.
your problems might come from the fact that you don’t have the full XML because it’s working on my side.
I can send it to you zipped (130kB) if you wish. It would be one of many but they are all alike.
Let me know.
What I’m looking for in those files is actually many things
The more I work with the files, the more I have needs for them.
I need to manage to write my own queries as the logic is not straight forward for me. This textual semantic is quite weird to me.
Here’s an other example of XML of which I’m working on at the moment:
I’m looking for all the scenarios with scenario/preamble/call/observations/operation/argument/value=SUCCESS.
Based on the example above from Nigel, I adapted:
set XML_path to (path to desktop as Unicode text) & "Test.xml"
tell application "System Events"
tell contents of XML file XML_path
tell XML element "package"
tell (first XML element whose name is "initial-state" and value of XML attribute "name" is "OPREADY")
set errorSWScenarii to XML elements whose name is "scenario" and value of XML attribute "name" of XML element "value" of XML element "argument" of XML element "operation" of XML element "observations" of XML element "call" of XML element "body" is "SUCCESS"
end tell
end tell
end tell
end tell
but strangely enough I don’t get my scenarios …
There is only one “body” per “scenario” so it’s fairly easy to check.
Some match and some don’t without a single reference to “SUCCESS”.
I have to say that I don’t have a clue why this is.
If I can’t trust that tool, it’s unfortunately pointless for me as it’s for work.
I keep looking but any help is appreciated.
PS: it’s also fairly slow compared to the other Sile lib I was using but I think I understand it better.