Skip to content

Commit 657ed0c

Browse files
committed
Merge feat/configuration-vendor-extensions (PR TrakHound#223) into integration/up-to-pr-223 on top of previous cascade tip
2 parents 8f1849e + e810192 commit 657ed0c

13 files changed

Lines changed: 2033 additions & 2 deletions

File tree

build/MTConnect.NET-SysML-Import/CSharp/TemplateRenderer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ public static void Render(MTConnectModel mtconnectModel, string outputPath)
175175

176176
case "Devices.Component": ((ClassModel)template).IsPartial = true; break;
177177
case "Devices.Composition": ((ClassModel)template).IsPartial = true; break;
178+
case "Devices.Configurations.Configuration": ((ClassModel)template).IsPartial = true; break;
178179
case "Devices.DataItem": ((ClassModel)template).IsPartial = true; break;
179180
case "Devices.AbstractDataItemRelationship": ((ClassModel)template).IsPartial = true; break;
180181
case "Devices.References.Reference": ((ClassModel)template).IsPartial = true; break;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2026 TrakHound Inc., All Rights Reserved.
2+
// TrakHound Inc. licenses this file to you under the MIT license.
3+
4+
using System.Collections.Generic;
5+
using System.Xml.Linq;
6+
7+
namespace MTConnect.Devices.Configurations
8+
{
9+
/// <summary>
10+
/// Hand-authored partial extension of the generated <see cref="Configuration"/>
11+
/// concrete class that carries the vendor-extension collection declared on
12+
/// <see cref="IConfiguration.VendorExtensions"/>. See the interface's remarks
13+
/// for the MTConnect v2.7 XSD citation that underpins the semantics.
14+
/// </summary>
15+
public partial class Configuration
16+
{
17+
/// <inheritdoc cref="IConfiguration.VendorExtensions"/>
18+
public IEnumerable<XElement> VendorExtensions { get; set; }
19+
}
20+
}

libraries/MTConnect.NET-Common/Devices/Configurations/Configuration.g.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace MTConnect.Devices.Configurations
88
/// <summary>
99
/// Technical information about an entity describing its physical layout, functional characteristics, and relationships with other entities.
1010
/// </summary>
11-
public class Configuration : IConfiguration
11+
public partial class Configuration : IConfiguration
1212
{
1313
/// <summary>
1414
/// The description of this type as defined by the MTConnect Standard.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) 2026 TrakHound Inc., All Rights Reserved.
2+
// TrakHound Inc. licenses this file to you under the MIT license.
3+
4+
using System.Collections.Generic;
5+
using System.Xml.Linq;
6+
7+
namespace MTConnect.Devices.Configurations
8+
{
9+
/// <summary>
10+
/// Hand-authored partial extension of the generated <see cref="IConfiguration"/>
11+
/// contract that adds the vendor-extension surface. The MTConnect Standard
12+
/// itself defines vendor extension of a component's Configuration through the
13+
/// XSD substitution group <c>AbstractConfiguration</c> — see
14+
/// <c>MTConnectDevices_2.7.xsd</c> where <c>ComponentConfigurationType</c>
15+
/// declares <c>&lt;xs:element ref="AbstractConfiguration" minOccurs="1"
16+
/// maxOccurs="unbounded"/&gt;</c>, and every standard child (SensorConfiguration,
17+
/// Specifications, Relationships, CoordinateSystems, Motion, SolidModel,
18+
/// ImageFiles, PowerSources) is declared with
19+
/// <c>substitutionGroup='AbstractConfiguration'</c>. A vendor publishes their
20+
/// own XSD declaring a vendor-namespaced element that likewise substitutes for
21+
/// <c>AbstractConfiguration</c>, and the operator supplies fully-formed
22+
/// instances of that element through this collection.
23+
/// </summary>
24+
public partial interface IConfiguration
25+
{
26+
/// <summary>
27+
/// Vendor-extension elements carried inside the component's
28+
/// <c>&lt;Configuration&gt;</c>. Each entry MUST be a fully-formed,
29+
/// vendor-namespaced XML element that a vendor XSD declares as a
30+
/// substitution of the standard <c>AbstractConfiguration</c> abstract
31+
/// element (see class-level remarks for the MTConnect XSD citation).
32+
/// The MTConnect.NET XML formatter writes each element verbatim inside
33+
/// the <c>&lt;Configuration&gt;</c> sequence, alongside any standard
34+
/// children present on this instance; the deserializer captures any
35+
/// child element it does not recognize as a standard configuration
36+
/// child and adds it here. Strict XSD validation of the emitted
37+
/// document is the caller's responsibility and requires the vendor XSD
38+
/// to be loaded alongside the MTConnect schemas.
39+
/// </summary>
40+
IEnumerable<XElement> VendorExtensions { get; }
41+
}
42+
}

libraries/MTConnect.NET-Common/Devices/Configurations/IConfiguration.g.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace MTConnect.Devices.Configurations
66
/// <summary>
77
/// Technical information about an entity describing its physical layout, functional characteristics, and relationships with other entities.
88
/// </summary>
9-
public interface IConfiguration
9+
public partial interface IConfiguration
1010
{
1111
/// <summary>
1212
/// Reference system that associates a unique set of n parameters with each point in an n-dimensional space. ISO 10303-218:2004

libraries/MTConnect.NET-XML/Devices/XmlConfiguration.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
using MTConnect.Devices.Configurations;
55
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Linq;
68
using System.Xml;
9+
using System.Xml.Linq;
710
using System.Xml.Serialization;
811

912
namespace MTConnect.Devices.Xml
@@ -15,6 +18,18 @@ namespace MTConnect.Devices.Xml
1518
/// and converts to and from the strongly-typed <see cref="Configuration"/>
1619
/// model.
1720
/// </summary>
21+
/// <remarks>
22+
/// Any child element that is neither a standard configuration child nor a
23+
/// namespaced vendor extension declared on this surrogate is captured
24+
/// into <see cref="VendorExtensions"/> as a raw <see cref="XmlElement"/>
25+
/// via <see cref="XmlAnyElementAttribute"/>, then projected onto
26+
/// <see cref="IConfiguration.VendorExtensions"/> as an
27+
/// <see cref="XElement"/>. This mirrors the MTConnect XSD's
28+
/// <c>ComponentConfigurationType</c> which permits any element that
29+
/// substitutes for the abstract <c>AbstractConfiguration</c> element —
30+
/// i.e. any element a vendor XSD has declared with
31+
/// <c>substitutionGroup='AbstractConfiguration'</c>.
32+
/// </remarks>
1833
[XmlRoot("Configuration")]
1934
public class XmlConfiguration
2035
{
@@ -61,6 +76,16 @@ public class XmlConfiguration
6176
[XmlArrayItem("ProcessSpecification", typeof(XmlProcessSpecification))]
6277
public List<XmlAbstractSpecification> Specifications { get; set; }
6378

79+
/// <summary>
80+
/// Vendor-extension child elements captured verbatim from the
81+
/// <c>&lt;Configuration&gt;</c> element by <see cref="XmlAnyElementAttribute"/>
82+
/// — every child not bound to a strongly-typed slot above lands here.
83+
/// See <see cref="IConfiguration.VendorExtensions"/> for the standard
84+
/// citation.
85+
/// </summary>
86+
[XmlAnyElement]
87+
public XmlElement[] VendorExtensions { get; set; }
88+
6489

6590
/// <summary>
6691
/// Converts this surrogate into the strongly-typed
@@ -122,6 +147,43 @@ public IConfiguration ToConfiguration()
122147
configuration.Specifications = specifications;
123148
}
124149

150+
// Vendor Extensions — every unrecognized child element captured by
151+
// [XmlAnyElement] projects to an XElement on the model. Elements are
152+
// preserved verbatim so downstream consumers see the exact
153+
// vendor-namespaced XML the operator authored.
154+
if (VendorExtensions != null && VendorExtensions.Length > 0)
155+
{
156+
var extensions = new List<XElement>(VendorExtensions.Length);
157+
foreach (var element in VendorExtensions)
158+
{
159+
if (element != null)
160+
{
161+
// Defense-in-depth against XML External Entity (XXE)
162+
// attacks: .NET 6+ already defaults XmlResolver to
163+
// null and disables DTD processing on the outer
164+
// document read (and a DOCTYPE cannot legally appear
165+
// inside a captured element's OuterXml), but pinning
166+
// both explicitly here mirrors the repo-wide
167+
// convention (see XmiDeserializer.FromXml) and
168+
// survives a future framework downgrade or
169+
// accidental restoration of XmlUrlResolver.
170+
var settings = new XmlReaderSettings
171+
{
172+
DtdProcessing = DtdProcessing.Prohibit,
173+
XmlResolver = null,
174+
};
175+
using var stringReader = new StringReader(element.OuterXml);
176+
using var xmlReader = XmlReader.Create(stringReader, settings);
177+
extensions.Add(XElement.Load(xmlReader, LoadOptions.PreserveWhitespace));
178+
}
179+
}
180+
181+
if (extensions.Count > 0)
182+
{
183+
configuration.VendorExtensions = extensions;
184+
}
185+
}
186+
125187
return configuration;
126188
}
127189

@@ -196,6 +258,20 @@ public static void WriteXml(XmlWriter writer, IConfiguration configuration, bool
196258
writer.WriteEndElement();
197259
}
198260

261+
// Write Vendor Extensions — each XElement is a fully-formed,
262+
// vendor-namespaced element that a vendor XSD declares as a
263+
// substitution of the standard AbstractConfiguration abstract
264+
// element. Serialise verbatim via WriteRaw so namespace
265+
// declarations and mixed content are preserved as authored.
266+
if (configuration.VendorExtensions != null)
267+
{
268+
foreach (var extension in configuration.VendorExtensions)
269+
{
270+
if (extension == null) continue;
271+
writer.WriteRaw(extension.ToString(SaveOptions.DisableFormatting));
272+
}
273+
}
274+
199275
writer.WriteEndElement();
200276
}
201277
}

0 commit comments

Comments
 (0)