Skip to content
Draft
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
5 changes: 5 additions & 0 deletions libraries/MTConnect.NET-XML/MTConnect.NET-XML.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
<ProjectReference Include="..\MTConnect.NET-Common\MTConnect.NET-Common.csproj" />
</ItemGroup>

<ItemGroup>
<!-- Grants MTConnect.NET-XML-Tests reach into the internal helpers (MTConnectVersion, Namespaces) that have no public equivalent. The assembly is not strong-named, so no PublicKey clause is required. -->
<InternalsVisibleTo Include="MTConnect.NET-XML-Tests" />
</ItemGroup>

<ItemGroup>
<None Include="README-Nuget.md">
<Pack>True</Pack>
Expand Down
11 changes: 7 additions & 4 deletions libraries/MTConnect.NET-XML/MTConnectVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace MTConnect
internal static class MTConnectVersion
{
/// <summary>
/// Gets the Version of the MTConnect standard being used based on the XML Namespace that is used
/// Gets the Version of the MTConnect standard from a raw XML document by extracting the root element's namespace URI and dispatching through <see cref="GetByNamespace"/>.
/// </summary>
public static Version Get(string xml)
{
Expand All @@ -17,12 +17,14 @@ public static Version Get(string xml)
}

/// <summary>
/// Gets the Version of the MTConnect standard being used based on the XML Namespace that is used
/// Gets the Version of the MTConnect standard from an already-resolved namespace URI. Returns <see cref="MTConnectVersions.Max"/> when the namespace is null, empty, or does not match a declared MTConnect namespace.
/// </summary>
public static Version GetByNamespace(string ns)
{
if (ns != null)
{
if (Namespaces.Version27.Match(ns)) return MTConnectVersions.Version27;
if (Namespaces.Version26.Match(ns)) return MTConnectVersions.Version26;
if (Namespaces.Version25.Match(ns)) return MTConnectVersions.Version25;
if (Namespaces.Version24.Match(ns)) return MTConnectVersions.Version24;
if (Namespaces.Version23.Match(ns)) return MTConnectVersions.Version23;
Expand All @@ -40,7 +42,8 @@ public static Version GetByNamespace(string ns)
if (Namespaces.Version10.Match(ns)) return MTConnectVersions.Version10;
}

return new Version();
// unknown namespace → default to latest supported version
return MTConnectVersions.Max;
}
}
}
}
35 changes: 30 additions & 5 deletions libraries/MTConnect.NET-XML/Namespaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,40 @@ internal static class Namespaces
private static Regex _streamRemoveNamespaceRegex = new Regex(@"\s{1}xmlns:xsi=\""http:\/\/www\.w3\.org\/2001\/XMLSchema-instance\""\s{1}xmlns:xsd=\""http:\/\/www\.w3\.org\/2001\/XMLSchema\""", RegexOptions.Compiled);
private static Regex _streamNamespaceRegex = new Regex("<MTConnectStreams", RegexOptions.Compiled);

// XmlDocument.LoadXml delegates to an internal XmlReader whose
// DtdProcessing default varies across TFMs and whose XmlResolver
// historically resolved external entities. Route the parse through
// an explicit XmlReader with DTD processing prohibited and no
// resolver so unknown or hostile documents cannot exercise
// external-entity or entity-expansion (billion-laughs) paths.
// Shared/static so it isn't reallocated on every Get() call.
private static readonly XmlReaderSettings _namespaceReaderSettings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null,
};

public static string Get(string xml)
{
var doc = new XmlDocument();
doc.LoadXml(xml);
if (doc != null && doc.DocumentElement != null)
if (string.IsNullOrEmpty(xml)) return null;

try
{
return doc.DocumentElement.NamespaceURI;
using (var stringReader = new StringReader(xml))
using (var xmlReader = XmlReader.Create(stringReader, _namespaceReaderSettings))
{
// Only the root start-tag's namespace is needed — advance
// to it directly rather than materializing a full
// XmlDocument DOM, which doubles the parse/allocation
// cost for large payloads that get re-parsed for real
// deserialization immediately afterwards anyway.
if (xmlReader.MoveToContent() == XmlNodeType.Element)
{
return xmlReader.NamespaceURI;
}
}
}
catch (XmlException) { }

return null;
}
Expand Down Expand Up @@ -478,7 +503,7 @@ internal static class Version12

public static bool Match(string ns)
{
return ns == Devices || ns == Error || ns == Streams;
return ns == Assets || ns == Devices || ns == Error || ns == Streams;
}
}

Expand Down
Loading