Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address Issue 85 - Convertor should support arrays for DisplayName and Description #87

Merged
merged 6 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 101 additions & 13 deletions NodeSetToAML.cs
Original file line number Diff line number Diff line change
Expand Up @@ -586,27 +586,109 @@ private void AddBaseNodeClassAttributes( AttributeSequence seq, UANode uanode, U
uriatt.Value = myuri;
}

if (uanode.DisplayName != null &&
uanode.DisplayName.Length > 0 &&
uanode.DisplayName[0].Value != uanode.DecodedBrowseName.Name)
BuildLocalizedTextAttribute( seq, "DisplayName", uanode.DisplayName,
uanode.DecodedBrowseName.Name, ignoreEqual: true );
BuildLocalizedTextAttribute( seq, "Description", uanode.Description,
uanode.DecodedBrowseName.Name, ignoreEqual: false );

UAType uaType = uanode as UAType;
if ( uaType != null && uaType.IsAbstract )
{
AddModifyAttribute(seq, "DisplayName", "LocalizedText",
uanode.DisplayName[0].Value);
AddModifyAttribute(seq, "IsAbstract", "Boolean", uaType.IsAbstract);
}
}

if (uanode.Description != null &&
uanode.Description.Length > 0 &&
uanode.Description[0].Value.Length > 0)
private void BuildLocalizedTextAttribute(
AttributeSequence seq,
string attributeName,
NodeSet.LocalizedText[] localizedTexts,
string equalityString, bool ignoreEqual )
{
if( localizedTexts != null )
{
AddModifyAttribute(seq, "Description", "LocalizedText",
uanode.Description[0].Value);
if( localizedTexts.Length > 1 )
{
AddModifyAttribute( seq, attributeName, "LocalizedText", localizedTexts[ 0 ].Value );

AttributeType displayNameAttribute = seq[ attributeName ];
if( displayNameAttribute != null )
{
string previousLocaleId = string.Empty;
string defaultLocaleId = GetLocaleId( localizedTexts[ 0 ], ref previousLocaleId );
AttributeType arrayRoot = AddModifyAttribute( displayNameAttribute.Attribute, defaultLocaleId, "String",
localizedTexts[ 0 ].Value );

// Redo first element
previousLocaleId = string.Empty;
for( int index = 0; index < localizedTexts.Length; index++ )
{
string localeId = GetLocaleId( localizedTexts[ index ], ref previousLocaleId );
AddModifyAttribute( arrayRoot.Attribute, "aml-lang=" + localeId,
"String", localizedTexts[ index ].Value );
}
}
}
else if( localizedTexts.Length > 0 )
{
NodeSet.LocalizedText localizedText = localizedTexts[ 0 ];
if( ignoreEqual == false ||
localizedText.Value != equalityString )
{
AttributeType root = AddModifyAttribute( seq, attributeName, "LocalizedText", localizedText.Value );

if( !String.IsNullOrEmpty( localizedText.Locale ) )
{
AddModifyAttribute( root.Attribute, localizedText.Locale, "LocalizedText", localizedText.Value );
}
}
}
}
}

UAType uaType = uanode as UAType;
if ( uaType != null && uaType.IsAbstract )
private string GetLocaleId( NodeSet.LocalizedText localizedText, ref string lastUnknownLocale )
{
string localeId = string.Empty;

if ( localizedText != null )
{
AddModifyAttribute(seq, "IsAbstract", "Boolean", uaType.IsAbstract);
if ( String.IsNullOrEmpty( localizedText.Locale ) )
{
if ( String.IsNullOrEmpty( lastUnknownLocale ) )
{
localeId = "qaa";
}
else
{
if ( lastUnknownLocale.Length == 3 && lastUnknownLocale[0] == 'q' )
{
char secondChar = lastUnknownLocale[1];
char lastChar = lastUnknownLocale[ 2 ];
if ( lastChar == 'z' )
{
// It's pretty impractical to have 20*26 unknown locales for a single node.
if( secondChar < 't' )
{
secondChar++;
localeId = "q" + secondChar + 'a';
}
}
else
{
localeId = "q" + secondChar + (char)( lastChar + 1 );
}
}
}
lastUnknownLocale = localeId;
}
else
{
localeId = localizedText.Locale;
}

return localeId;
}

return localeId;
}

private AttributeType AddModifyAttribute(AttributeSequence seq, string name, string refDataType, Variant val, bool bListOf = false, string sURI = uaNamespaceURI)
Expand Down Expand Up @@ -910,7 +992,13 @@ private AttributeType AddModifyAttribute(AttributeSequence seq, string name, str
if( localizedText != null && localizedText.Text != null )
{
a.DefaultAttributeValue = a.AttributeValue = localizedText.Text;
if ( !string.IsNullOrEmpty( localizedText.Locale ) )
{
AddModifyAttribute(a.Attribute, localizedText.Locale,
"String", localizedText.Text);
}
}

break;
}

Expand Down
3 changes: 2 additions & 1 deletion Opc2AmlConsole/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"profiles": {
"Opc2AmlConsole": {
"commandName": "Project"
"commandName": "Project",
"commandLineArgs": "--Nodeset TestAml.xml"
}
}
}
147 changes: 142 additions & 5 deletions SystemTest/NodeSetFiles/TestAml.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2126,7 +2126,8 @@
</References>
</UAObject>
<UAVariable DataType="Int32" ValueRank="1" NodeId="ns=1;i=6126" ArrayDimensions="10" BrowseName="1:OneDimension" ParentNodeId="ns=1;i=5011" UserAccessLevel="3" AccessLevel="3">
<DisplayName>OneDimension</DisplayName>
<DisplayName>OneDimensionArray</DisplayName>
<Description>A One Dimensional Array</Description>
<References>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5011</Reference>
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
Expand All @@ -2147,7 +2148,10 @@
</Value>
</UAVariable>
<UAVariable DataType="Int32" ValueRank="2" NodeId="ns=1;i=6127" ArrayDimensions="2,5" BrowseName="1:TwoDimensions" ParentNodeId="ns=1;i=5011" UserAccessLevel="3" AccessLevel="3">
<DisplayName>TwoDimensions</DisplayName>
<DisplayName>TwoDimensionArray</DisplayName>
<DisplayName>aTwoDimensionalArray</DisplayName>
<Description>A Different Two Dimension Array </Description>
<Description>Another Two Dimension Array </Description>
<References>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5011</Reference>
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
Expand All @@ -2168,7 +2172,10 @@
</Value>
</UAVariable>
<UAVariable DataType="Int32" ValueRank="5" NodeId="ns=1;i=6128" ArrayDimensions="2,2,2,2,2" BrowseName="1:FiveDimensions" ParentNodeId="ns=1;i=5011" UserAccessLevel="3" AccessLevel="3">
<DisplayName>FiveDimensions</DisplayName>
<DisplayName Locale="en">FiveDimensionArray</DisplayName>
<Description Locale="fr">A Five DimensionArray</Description>
<Description>Another Five Dimension Array </Description>

<References>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5011</Reference>
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
Expand Down Expand Up @@ -3087,13 +3094,143 @@
</uax:ExtensionObject>
</Value>
</UAVariable>
<UAObject SymbolicName="LocalizedTextAttributes" NodeId="ns=1;i=5024" BrowseName="1:LocalizedTextAttributes" ParentNodeId="i=85">
<DisplayName>Localized Text Attributes</DisplayName>
<References>
<Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
</References>
</UAObject>

<UAVariable NodeId="ns=1;i=6227" BrowseName="1:NoLocalizedText" DataType="LocalizedText" ValueRank="-1" ArrayDimensions="" ParentNodeId="ns=1;i=5024" UserAccessLevel="3" AccessLevel="3" >
<References>
<Reference ReferenceType="HasTypeDefinition" BrowseName="PropertyType">i=63</Reference>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5024</Reference>
</References>
</UAVariable>

<UAVariable NodeId="ns=1;i=6228" BrowseName="1:SingleLocalizedText" DataType="LocalizedText" ValueRank="-1" ArrayDimensions="" ParentNodeId="ns=1;i=5024" UserAccessLevel="3" AccessLevel="3" >
<DisplayName>Single Localized Text</DisplayName>
<Description>A Single Description with no Locale</Description>
<References>
<Reference ReferenceType="HasTypeDefinition" BrowseName="PropertyType">i=63</Reference>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5024</Reference>
</References>
<Value>
<uax:LocalizedText>
<uax:Text>Attributes have display name and description, but no Locale</uax:Text>
</uax:LocalizedText>
</Value>
</UAVariable>

<UAVariable NodeId="ns=1;i=6229" BrowseName="1:SingleLocalizedTextLocale" DataType="LocalizedText" ValueRank="-1" ArrayDimensions="" ParentNodeId="ns=1;i=5024" UserAccessLevel="3" AccessLevel="3" >
<DisplayName Locale="en">Single Localized Text with Locale</DisplayName>
<Description Locale="en">A Single Description with a Locale</Description>
<References>
<Reference ReferenceType="HasTypeDefinition" BrowseName="PropertyType">i=63</Reference>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5024</Reference>
</References>
<Value>
<uax:LocalizedText>
<uax:Locale>en</uax:Locale>
<uax:Text>Attributes have display name and description with a single Locale</uax:Text>
</uax:LocalizedText>
</Value>
</UAVariable>

<UAVariable NodeId="ns=1;i=6230" BrowseName="1:MultipleFirstNoLocale" DataType="LocalizedText" ValueRank="1" ArrayDimensions="1" ParentNodeId="ns=1;i=5024" UserAccessLevel="3" AccessLevel="3" >
<DisplayName>First DisplayName with no Locale</DisplayName>
<Description>First Description with no Locale</Description>
<DisplayName Locale="en">Second DisplayName with a Locale</DisplayName>
<Description Locale="en">Second Description with a Locale</Description>
<DisplayName Locale="fr">Troisième texte localisé avec paramètres régionaux</DisplayName>
<Description Locale="fr">Troisième description avec un paramètre régional</Description>
<DisplayName Locale="de">Letzter lokalisierter Text mit Gebietsschema</DisplayName>
<Description Locale="de">Letzte Beschreibung mit einem Gebietsschema</Description>
<References>
<Reference ReferenceType="HasTypeDefinition" BrowseName="PropertyType">i=63</Reference>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5024</Reference>
</References>
<Value>
<uax:ListOfLocalizedText>
<uax:LocalizedText>
<uax:Text>Multiple</uax:Text>
</uax:LocalizedText>
<uax:LocalizedText>
<uax:Locale>en</uax:Locale>
<uax:Text>DisplayNames and Descriptions</uax:Text>
</uax:LocalizedText>
<uax:LocalizedText>
<uax:Locale>en</uax:Locale>
<uax:Text>first without a locale</uax:Text>
</uax:LocalizedText>
</uax:ListOfLocalizedText>
</Value>
</UAVariable>

<UAVariable NodeId="ns=1;i=6231" BrowseName="1:MultipleLastNoLocale" DataType="LocalizedText" ValueRank="1" ArrayDimensions="1" ParentNodeId="ns=1;i=5024" UserAccessLevel="3" AccessLevel="3" >
<DisplayName Locale="en">First DisplayName with a Locale</DisplayName>
<Description Locale="en">First Description with a Locale</Description>
<DisplayName Locale="fr">Deuxième DisplayName avec une locale</DisplayName>
<Description Locale="fr">Deuxième description avec une locale</Description>
<DisplayName Locale="de">Dritter DisplayName mit einem Gebietsschema</DisplayName>
<Description Locale="de">Dritte Beschreibung mit einem Gebietsschema</Description>
<DisplayName>Last DisplayName with no Locale</DisplayName>
<Description>Last Description with no Locale</Description>
<References>
<Reference ReferenceType="HasTypeDefinition" BrowseName="PropertyType">i=63</Reference>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5024</Reference>
</References>
<Value>
<uax:ListOfLocalizedText>
<uax:LocalizedText>
<uax:Locale>en</uax:Locale>
<uax:Text>Multiple</uax:Text>
</uax:LocalizedText>
<uax:LocalizedText>
<uax:Locale>en</uax:Locale>
<uax:Text>DisplayNames and Descriptions</uax:Text>
</uax:LocalizedText>
<uax:LocalizedText>
<uax:Text>last without a locale</uax:Text>
</uax:LocalizedText>
</uax:ListOfLocalizedText>
</Value>
</UAVariable>

<UAVariable NodeId="ns=1;i=6232" BrowseName="1:MultipleNoLocale" DataType="LocalizedText" ValueRank="1" ArrayDimensions="1" ParentNodeId="ns=1;i=5024" UserAccessLevel="3" AccessLevel="3" >
<DisplayName>First DisplayName with no Locale</DisplayName>
<Description>First Description with no Locale</Description>
<DisplayName>Second DisplayName with no Locale</DisplayName>
<Description>Second Description with no Locale</Description>
<DisplayName>Third DisplayName with no Locale</DisplayName>
<Description>Third Description with no Locale</Description>
<DisplayName>Last DisplayName with no Locale</DisplayName>
<Description>Last Description with no Locale</Description>
<References>
<Reference ReferenceType="HasTypeDefinition" BrowseName="PropertyType">i=63</Reference>
<Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5024</Reference>
</References>
<Value>
<uax:ListOfLocalizedText>
<uax:LocalizedText>
<uax:Text>Multiple</uax:Text>
</uax:LocalizedText>
<uax:LocalizedText>
<uax:Text>DisplayNames and Descriptions</uax:Text>
</uax:LocalizedText>
<uax:LocalizedText>
<uax:Text>all without a locale</uax:Text>
</uax:LocalizedText>
</uax:ListOfLocalizedText>
</Value>
</UAVariable>

<!-- Next Numbers
ObjectType 1009
VariableType 2001
DataType 3004
Object 5024
Variable 6227
Object 5025
Variable 6232
-->
</UANodeSet>
Loading
Loading