Export component event scripts

Is there any way to export all the component event scripts? I would like to be able to see all event code in one place so I know what can be safely re-factored. I’m hoping to end up with text files, but I don’t mind writing an XML decoder or a python script to get there.

Any pointers would be appreciated.

Thanks.

To my understanding, no, your still not able to do this. I found another thread in the forums related to this where it was suggested to do a copy and paste. I don’t see any other alternative to this.

I was hoping there might be an SDK method to access this information, but I haven’t been able to find one.

No, unfortunately there isn’t a method to extract just the component event handlers. You can select all of the components inside of the window and press Ctrl-C to copy. If you paste it in a text editor you can see the underlying XML. You might be able to write something to get the event handlers if you can understand the XML.

Is there any way to get that XML for all windows at once? If I use any of the export options I get a ‘.proj’ file with XML CDATA. I presume it is just compressed, but what format does it use?

Thanks.

The .proj file itself is XML, but all of the project resources are Base64-encoded binary. In Ignition 7.3+, the format is binary, which can be transcoded into XML via the XMLSerializer.

I’m getting “java.lang.ClassNotFoundException: str” when trying to use the XMLDeserialiser.

It looks like that’s the Python ‘str’ class that it’s trying to find, which leads me to suspect some sort of problem with Jython, but this happens even within the designer environment so I’m not sure where to proceed from here.

Any suggestions?

Thanks.

This has nothing to do with Python’s ‘str’. How are you creating the XMLDeserializer? Where is this code running? Are you compiling against the SDK? If so, are you in the Designer?

I’m currently making this using the module SDK and running in within the designer.

Very basic test code to read from a manually extracted and base64-decoded chunk of binary data from my ‘.proj’ file:

import com.inductiveautomation.ignition.common.xmlserialization.deserialization.XMLDeserializer;
import com.inductiveautomation.ignition.common.xmlserialization.serialization.XMLSerializer;
import java.io.*;

public class Decoder {
    public static String run() throws Exception {
        XMLDeserializer xml = new XMLDeserializer();
        return xml.transcodeToXML(new FileInputStream("/tmp/foo.bin"), new XMLSerializer());
    }
}

Registered in the designer like this:

public class DesignerHook extends AbstractDesignerModuleHook {
    public void initializeScriptManager(ScriptManager manager) {
        manager.addScriptModule("decoder", Decoder.class);
    }
}

Then in the designer script playground:

import decoder
print decoder.run()

Thanks.

Ok great.

  1. You shouldn’t instantiate an XMLDecoder directly like that. You need to ask the DesignerContext for one via DesignerContext.createDeserializer()

  2. Any chance the resources you want to investigate are in the project that the Designer has open right now? If so, your options are much more direct.

  3. If you’re dealing with a *.proj file, you can use Project.fromXML(InputStream) to read it in - no need to extract the base64 yourself.

  4. I’m going to move this thread to the module forum so we don’t scare away the nice people here.

Thanks, that explains a lot.

The project I’m working with is open in the designer, so I can probably simplify this by working with the Project object directly. I was originally going to write a standalone script to convert a .proj file into something human readable, but it looks like the binary serialisation system won’t allow that.

If I use context.getProject().toXML() it produces the same as the exported .proj file. How can I serialise resources as plain XML (i.e. no binary data)? The copy/paste system uses plain XML- that’s more what I’m looking for.

I tried this, but it produces a blank file:

        XMLSerializer xml = this.context.createSerializer();
        for (ProjectResource resource : this.context.getProject().getResources()) {
            xml.addObject(resource);
        }
        xml.serializeXML(new FileOutputStream("/tmp/ignition.xml"), "UTF-8");

Also, how can I obtain the data for a ProjectResource without locking (or unlocking??) the resource for other developers? Similarly, can I still read the data for a resource that is locked by another developer?

Thanks.

EDIT: The output file is blank because I was ignoring exceptions. I’m getting “com.inductiveautomation.ignition.common.xmlserialization.SerializationException: Unable to create clean copy of class com.inductiveautomation.ignition.common.project.ProjectResource”. Any idea what I’m doing wrong?

It seems that ProjectResources have to be deserialised first:

    XMLSerializer xml = this.context.createSerializer();
    for (ProjectResource resource : this.context.getProject().getResources()) {
        try {
            for (Object o : context.createDeserializer().deserialize(resource.getData()).getRootObjects()) {
                System.out.println(o);
                xml.addObject(o);
                System.out.println(xml.serialize());
            }
        } catch (Exception e) {
            log.info("exception " + e);
        }
    }

This works, but regardless of whether I use serialize() or serializeXML() I’m still only getting binary data :frowning:

Having used getRootObjects(), is there a generic way to descend down the tree and see all the children or is that different for each resource?

Thanks.

1 Like

Ok, so once you get a Project object via Project.fromXML(), you can loop through it’s ProjectResources.

Each of ProjectResource has a byte[] of data on it. This will be serialized data (binary or gzipped, base64’ed xml - the XMLDeserializer will auto-detect between these anyhow).

If you want to inspect the project resource in memory, create an XMLDeserializer and call deserialize(byte[]) on the ProjectResource.getData(), and then look at the root objects on the deserialization context.

If you want to inspect the project resource as xml, create an XMLDeserializer and an XMLSerializer, and call XMLDeserializer.transcodeToXML()

It seems that I’ve actually had this working for some time.

My confusion was a result of the need to deserialize window resources twice

Deserializing an fpmi.window resource gives something a bit like this:

<?xml version="1.0" encoding="UTF-8"?>
<objects fpmi.version="6.5.1.638" framework.version="7.5.1.1122" timestamp="Fri Sep 14 14:38:14 BST 2012">
	<o cls="com.inductiveautomation.factorypmi.application.model.WindowInfo">
		<o-c m="setSerializedCode" s="1;[byt"><gzbarr>BASE64 ENCODED DATA HERE</gzbarr></o-c>
		<o-c m="setWindowName" s="1;str"><str>Inner Window</str></o-c>
		<o-c m="setXmlFormatVersion" s="1;i"><int>1</int></o-c>
	</o>
</objects>

To get the actual data for a window, a second deserialization step must be performed on the result of getSerializedCode(). Unfortunately the module SDK doesn’t expose any types with getSerializedCode(), making this somewhat tricky.

I hope you realize that there is a reason this is "tricky". You're waaay off the beaten path here..

1 Like

Is there a chance this will ever be an official way to import and export data?

It will give so many advantages, like version control to keep track of GUI modifications (not only when something changed, but also who changed what exactly). Or grepping for certain functions or variable names or UDT types (which will work a lot faster than text search through SQLite BLOBs).

1 Like

In my quest to do ALL my script editing in Kate, I am copying & save all scripts to text files. However, I can’t do that with anything in Component Scripting windows, below is an example:

  • I can PASTE into this window without problems.
  • I can COPY one line at a time out of this window.
  • But I have found no way to copy all lines of a script.
  • I’m on 7.9.12

My dirty work-around is to maximize window, screen-capture to GIF (1 pg at a time), upload to https://www.newocr.com/, paste into Kate, reformat & fixup OCR mistakes, etc. I’m about 15 scripts in and got 30+ to go, hence the question. Please have pity on me :slight_smile:

P.S. I understand this is an old thread but I didn’t see anything more recent.

The solution hasn’t really changed since this thread was written, and likely won’t, at least for Vision.

If you’re able to migrate to 8.0 (and change visualization to Perspective), every view is just a plain-text JSON file, including all scripts :). Project scripts and webdev endpoints are also .py files on disk, and in a future release we’re hoping to make client & gateway events (and the new session events added by Perspective) into text resources as well.

I’ve never had a problem copying the entire script as long as I omit the signature and top comment block.

Also, look as copying the entire window in XML format using the menu options when you shift-right-click on a vision window in the designer’s nav tree.