In my previous post, I explained what TIA Openness is and how using it can streamline your development process. Since Openness uses XML files as the basis for its import and export functions, knowing how to understand these XML files is vital for creating and modifying code with Openness.
Becoming fluent in the XML structure of Openness is not a quick and easy process; it takes time and a lot of experience. However, with the basics I’ll cover in this post, you’ll have the tools and background you need to take your first steps.
Reading an XML File
XML stands for eXtensible Markup Language and is a language used for storing data. Like HTML, it is a markup language, and is meant to be self-descriptive. XML is great for storing complex data structures since it encodes them in a hierarchical tag structure. Let’s take a look at a simple piece of XML.
<email>
<to>Alice</to>
<from>Bob</from>
<subject>XML</subject>
<message>Isn't XML the best?</message>
</email>
This code represents an email. You can see that within the Email object, it contains information for To, From, Subject, and Message. These elements are children of the Email parent. Unlike HTML, XML has no predefined tags. Having no predefined tags allows the creator of XML to make those tags as descriptive as possible. XML also relies on other programs to read and write it; it does not do anything by itself. For the sample code above, someone must have created a program to store emails. In order to do something with those stored emails, there needs to be a program that converts the XML to a more human-friendly format.
This is all that Openness does; it takes XML files that contain all the information needed for, say, a function block, reads them, and processes that information to make a new function block. When Openness exports a function block (or other piece of code), it converts all that data to an XML format. This means that when you open an Openness XML document, it will contain many tags that have been defined by Siemens. These tags are descriptive but can be hard to understand at first glance. Here’s a snippet of a function block in XML.
<Document>
<SW.Blocks.FB ID="0">
<AttributeList>
<AutoNumber>true</AutoNumber>
<HeaderAuthor />
<HeaderFamily />
<HeaderName />
<HeaderVersion>0.1</HeaderVersion>
<Interface>
<Sections xmlns="http://www.siemens.com/automation/Openness/SW/Interface/v2">
<Section Name="Input">
<Member Name="bInCondition" Datatype="Bool" Remanence="NonRetain" Accessibility="Public">
<AttributeList>
<BooleanAttribute Name="ExternalAccessible" SystemDefined="true">false</BooleanAttribute>
<BooleanAttribute Name="ExternalVisible" SystemDefined="true">false</BooleanAttribute>
<BooleanAttribute Name="ExternalWritable" SystemDefined="true">false</BooleanAttribute>
</AttributeList>
<Comment>
<MultiLanguageText Lang="en-US">Input condition</MultiLanguageText>
</Comment>
</Member>
</Section>
<Section Name="Output">
<Member Name="bOutDoSomething" Datatype="Bool" Remanence="NonRetain" Accessibility="Public">
<AttributeList>
<BooleanAttribute Name="ExternalAccessible" SystemDefined="true">false</BooleanAttribute>
<BooleanAttribute Name="ExternalVisible" SystemDefined="true">false</BooleanAttribute>
<BooleanAttribute Name="ExternalWritable" SystemDefined="true">false</BooleanAttribute>
</AttributeList>
<Comment>
<MultiLanguageText Lang="en-US">Output action</MultiLanguageText>
</Comment>
</Member>
</Section>
This is part of the block interface of a function block. Let’s start at the top and work our way down.
The Document Tag
The first element is the ‘Document’ tag. This tag is just used to delineate the start and end of the XML file. Each XML file you create for Openness should only contain one “Document” tag. Next, we have ‘SW.Blocks.FB ID=”0”’.
SW.Blocks.FB
The ‘SW.Blocks.FB’ tells Openness that we are defining a function block. In a similar fashion, we could use ‘SW.Blocks.DB’ to define a data block. The ‘ID=”0”’ part is an internal ID used by Openness. This ID is only used to identify the different data within the XML file. If you have multiple blocks defined inside one ‘Document’ tag, each block will need to have a unique ID, or the import process will fail. In the event of an error, Openness will use these ID numbers to specify where the error occurred.
Every function block has certain attributes, which are encapsulated in the ‘AttributeList’ tag. A lot of these attributes will look similar to ones you see when you go to the properties of the function block in Portal. For example, we have a value for ‘AutoNumber’ that tells us if the function block number is set automatically or manually. The ‘HeaderAuthor’, ‘HeaderFamily’, ‘HeaderName’, and ‘HeaderVersion’ attributes can be found in the properties of the block as well. The ‘Interface’ tag is used to define the block interface of the function block.
Sections
The interface contains a set of ‘Sections’. A ‘Section’ is one of the different types of data that a function block can contain. In this example, we have a section named ‘Input’ and a section named ‘Output’. These correspond to the input and output parameters of the block, respectively. To define an input parameter, we create a ‘Member’ in the ‘Input’ section. In the above image, we have an input parameter called ‘bInCondition’. A member has its own set of attributes.
Members
In the ‘Member’ definition, there are ‘Name’, ‘Datatype’, ‘Remanence’, and ‘Accessibility’ attributes. These correspond to the name of the variable, its datatype, whether or not it is retentive, and who can access the variable. Additional attributes are defined in the enclosed ‘AttributeList’. These three attributes, ‘ExternalAccessible’, ‘ExternalVisible’, and ‘ExternalWritable’ correspond to the checkboxes you see in Portal: ‘Accessible from HMI’, ‘Writable from HMI’, and ‘Visible in HMI engineering’.
The Comment Attribute
Finally, the ‘Member’ contains a ‘Comment’ attribute. The comment contains a ‘MultiLanguageText’ attribute that contains the actual comment value. If you are programming in multiple languages, additional ‘MultiLanguageText’ attributes would be defined, and would allow the comment to appear in multiple languages. By setting the values of these attributes, you can fully define the variable. So the XML code above translates into the following block definition.
Creating Code from XML
Let’s start by looking at a few examples. Here’s a network in our existing function block.
And here’s the associated XML.
<SW.Blocks.CompileUnit ID="3" CompositionName="CompileUnits">
<AttributeList>
<NetworkSource>
<FlgNet xmlns="http://www.siemens.com/automation/Openness/SW/NetworkSource/FlgNet/v1">
<Parts>
<Access Scope="LocalVariable" UId="21">
<Symbol>
<Component Name="bInCondition" />
</Symbol>
</Access>
<Access Scope="LocalVariable" UId="22">
<Symbol>
<Component Name="bOutDoSomething" />
</Symbol>
</Access>
<Part Name="Contact" UId="23" />
<Part Name="Coil" UId="24" />
</Parts>
<Wires>
<Wire UId="25">
<Powerrail />
<NameCon UId="23" Name="in" />
</Wire>
<Wire UId="26">
<IdentCon UId="21" />
<NameCon UId="23" Name="operand" />
</Wire>
<Wire UId="27">
<NameCon UId="23" Name="out" />
<NameCon UId="24" Name="in" />
</Wire>
<Wire UId="28">
<IdentCon UId="22" />
<NameCon UId="24" Name="operand" />
</Wire>
</Wires>
</FlgNet>
</NetworkSource>
<ProgrammingLanguage>LAD</ProgrammingLanguage>
</AttributeList>
<ObjectList>
<MultilingualText ID="4" CompositionName="Comment">
<ObjectList>
<MultilingualTextItem ID="5" CompositionName="Items">
<AttributeList>
<Culture>en-US</Culture>
<Text>This network uses an input condition to activate an output action</Text>
</AttributeList>
</MultilingualTextItem>
</ObjectList>
</MultilingualText>
<MultilingualText ID="6" CompositionName="Title">
<ObjectList>
<MultilingualTextItem ID="7" CompositionName="Items">
<AttributeList>
<Culture>en-US</Culture>
<Text>Simple contact/coil network</Text>
</AttributeList>
</MultilingualTextItem>
</ObjectList>
</MultilingualText>
</ObjectList>
</SW.Blocks.CompileUnit>
The XML, while more complicated than the ladder logic view, is still relatively readable. There are attributes of the network, a section for declaring all used variables, a section that defines the ladder elements used, and a section that creates the connections between the variables and the separate ladder elements. However, while the sections stay the same, adding more complex elements quickly makes this XML extremely difficult to parse.
Here’s an example of creating an instance of the Open Library fb_ValveSolenoid function block.
While still a relatively simple network, the XML to encapsulate this network is 187 lines long (I won’t post it here to save space). Every part of the XML has to be accurately defined, or you will end up with import errors. In addition, learning the various pieces that Openness uses to define function blocks takes a lot of practice.
For these reasons, it very rarely makes sense to start from scratch to create an XML version of a function block. You can add functions to your Openness application to export existing blocks to XML. Then, you can create your blocks in Portal, and have Openness generate the associated XML automatically. When editing these XML documents, I would recommend using a text editor that has support for proper XML formatting, such as Notepad++ or Visual Studio Code.
While being at least somewhat familiar with Openness’ XML format is very useful for debugging purposes, we’ve seen that it can be overwhelming when trying to write code. Using Openness to generate the XML code is easy, but requires creating the desired object in Portal anyway.
What then, you might ask, is the point of creating objects in XML? In the next post, I’ll cover how you can use Openness to automate the creation of code using XML templates.
Learn more about DMC's TIA Portal Development and contact us for more information.