diff --git a/SabreTools.Serialization/Internal.cs b/SabreTools.Serialization/Internal.cs
new file mode 100644
index 00000000..410f06f6
--- /dev/null
+++ b/SabreTools.Serialization/Internal.cs
@@ -0,0 +1,60 @@
+using System.Collections.Generic;
+using System.Linq;
+using SabreTools.Models.Internal;
+
+namespace SabreTools.Serialization
+{
+ public class Internal
+ {
+ ///
+ /// Extract nested items from a Part
+ ///
+ public static DatItem[]? ExtractItems(Part? item)
+ {
+ if (item == null)
+ return null;
+
+ var datItems = new List();
+
+ var features = item.Read(Part.FeatureKey);
+ if (features != null && features.Any())
+ datItems.AddRange(features);
+
+ var dataAreas = item.Read(Part.DataAreaKey);
+ if (dataAreas != null && dataAreas.Any())
+ datItems.AddRange(dataAreas.SelectMany(ExtractItems));
+
+ var diskAreas = item.Read(Part.DiskAreaKey);
+ if (diskAreas != null && diskAreas.Any())
+ datItems.AddRange(diskAreas.SelectMany(ExtractItems));
+
+ var dipSwitches = item.Read(Part.DipSwitchKey);
+ if (dipSwitches != null && dipSwitches.Any())
+ datItems.AddRange(dipSwitches);
+
+ return datItems.ToArray();
+ }
+
+ ///
+ /// Extract nested items from a DataArea
+ ///
+ private static Rom[]? ExtractItems(DataArea? item)
+ {
+ if (item == null)
+ return null;
+
+ return item.Read(DataArea.RomKey);
+ }
+
+ ///
+ /// Extract nested items from a DiskArea
+ ///
+ private static Disk[]? ExtractItems(DiskArea? item)
+ {
+ if (item == null)
+ return null;
+
+ return item.Read(DiskArea.DiskKey);
+ }
+ }
+}
\ No newline at end of file