SobekCM.Resource_Object.Metadata_File_ReaderWriters.METS_File_ReaderWriter.Write_Metadata C# (CSharp) Method

Write_Metadata() public method

Writes the formatted metadata from the provided item to a TextWriter (usually to an output stream)
OPTIONS: Accepts 'METS_File_ReaderWriter:METS_Writing_Profile', otherwise the default METS writing profile is utilized.
public Write_Metadata ( TextWriter Output_Stream, SobekCM_Item Item_To_Save, object>.Dictionary Options, string &Error_Message ) : bool
Output_Stream System.IO.TextWriter
Item_To_Save SobekCM_Item Package with all the metadata to save
Options object>.Dictionary Dictionary of any options which this metadata reader/writer may utilize
Error_Message string [OUTPUT] Explanation of the error, if an error occurs during write
return bool
        public bool Write_Metadata(TextWriter Output_Stream, SobekCM_Item Item_To_Save, Dictionary<string, object> Options, out string Error_Message)
        {
            // PERHAPS MAKE THESE OPTIONS?
            List<string> mimes_to_exclude = new List<string>();
            const bool MINIMIZE_FILE_SIZE = false;

            // Get the METS writing profile
            METS_Writing_Profile profile = ResourceObjectSettings.MetadataConfig.Default_METS_Writing_Profile;


            // Set default error outpt message
            Error_Message = String.Empty;

            // Ensure the METS ID is set from BibID and VID
            if (Item_To_Save.METS_Header.ObjectID.Length == 0)
            {
                Item_To_Save.METS_Header.ObjectID = Item_To_Save.BibID + "_" + Item_To_Save.VID;
                if (Item_To_Save.VID.Length == 0)
                    Item_To_Save.METS_Header.ObjectID = Item_To_Save.BibID;
            }

            // If this is bib level, it is different
            if ((Item_To_Save.VID == "*****") || (Item_To_Save.METS_Header.RecordStatus_Enum == METS_Record_Status.BIB_LEVEL))
                Item_To_Save.METS_Header.ObjectID = Item_To_Save.BibID;

            // If this is juat a project XML, do this differently
            if (Item_To_Save.Bib_Info.SobekCM_Type == TypeOfResource_SobekCM_Enum.Project)
            {
                Item_To_Save.Bib_Info.Main_Title.Title = "Project level metadata for '" + Item_To_Save.BibID + "'";
                Item_To_Save.METS_Header.ObjectID = Item_To_Save.BibID;
            }

            // Ensure the source code appears in the METS header correctly
            Item_To_Save.METS_Header.Creator_Organization = Item_To_Save.Bib_Info.Source.Code;
            if ((Item_To_Save.Bib_Info.Source.Statement.Length > 0) && (String.Compare(Item_To_Save.Bib_Info.Source.Statement, Item_To_Save.Bib_Info.Source.Code, StringComparison.OrdinalIgnoreCase) != 0))
            {
                Item_To_Save.METS_Header.Creator_Organization = Item_To_Save.Bib_Info.Source.Code + "," + Item_To_Save.Bib_Info.Source.XML_Safe_Statement;
            }

            // Get the list of divisions from the physical tree and the download/other file tre
            List<abstract_TreeNode> physicalDivisions = Item_To_Save.Divisions.Physical_Tree.Divisions_PreOrder;
            List<abstract_TreeNode> downloadDivisions = Item_To_Save.Divisions.Download_Tree.Divisions_PreOrder;
            List<abstract_TreeNode> allDivisions = new List<abstract_TreeNode>();
            List<SobekCM_File_Info> allFiles = new List<SobekCM_File_Info>();

            #region Prepare the list of divisions and files to be written by assigning proper ID's and groupid's to all

            // Create some private variables for this
            int page_and_group_number = 1;
            int division_number = 1;
            bool hasPageFiles = false;
            bool hasDownloadFiles = false;
            Dictionary<string, List<SobekCM_File_Info>> mimeHash = new Dictionary<string, List<SobekCM_File_Info>>();
            List<string> fileids_used = new List<string>();

            // Clear any existing ID's here since the ID's are only used for writing METS files
            foreach (abstract_TreeNode thisNode in physicalDivisions)
            {
                thisNode.ID = String.Empty;
                thisNode.DMDID = String.Empty;
                thisNode.ADMID = String.Empty;
            }

            // First, assign group numbers for all the files on each page (physical or other)
            // Group numbers in the METS file correspond to files on the same page (physical or other)
            // At the same time, we will build the list of all files and files by mime type
            foreach (abstract_TreeNode thisNode in physicalDivisions)
            {
                // If this node was already hit (perhaps if a div has two parent divs), 
                // then skip it
                if (thisNode.ID.Length > 0)
                    continue;

                // Add this to the list of all nodes
                allDivisions.Add(thisNode);

                // Was this a PAGE or a DIVISION node?
                if (thisNode.Page)
                {
                    // Get this page node
                    Page_TreeNode pageNode = (Page_TreeNode) thisNode;

                    // Only do anything if there are actually any files here
                    if ((pageNode.Files != null) && (pageNode.Files.Count > 0))
                    {

                        // Set the page ID here
                        pageNode.ID = "PAGE" + page_and_group_number;

                        // Step through any files under this page
                        foreach (SobekCM_File_Info thisFile in pageNode.Files)
                        {
                            // Set the ADMID and DMDID to empty in preparation for METS writing
                            thisFile.ADMID = String.Empty;
                            thisFile.DMDID = String.Empty;

                            // If no file name, skip this
                            if (String.IsNullOrEmpty(thisFile.System_Name))
                                continue;

                            // Get this file extension and MIME type
                            string fileExtension = thisFile.File_Extension;
                            string mimetype = thisFile.MIME_Type(thisFile.File_Extension);

                            // If this is going to be excluded from appearing in the METS file, just skip 
                            // it here as well.
                            if (!mimes_to_exclude.Contains(mimetype))
                            {
                                // Set the group number on this file
                                thisFile.Group_Number = "G" + page_and_group_number;

                                // Set the ID for this file as well
                                switch (mimetype)
                                {
                                    case "image/tiff":
                                        thisFile.ID = "TIF" + page_and_group_number;
                                        break;
                                    case "text/plain":
                                        thisFile.ID = "TXT" + page_and_group_number;
                                        break;
                                    case "image/jpeg":
                                        if (thisFile.System_Name.ToLower().IndexOf("thm.jp") > 0)
                                        {
                                            thisFile.ID = "THUMB" + page_and_group_number;
                                            mimetype = mimetype + "-thumbnails";
                                        }
                                        else
                                            thisFile.ID = "JPEG" + page_and_group_number;
                                        break;
                                    case "image/gif":
                                        if (thisFile.System_Name.ToLower().IndexOf("thm.gif") > 0)
                                        {
                                            thisFile.ID = "THUMB" + page_and_group_number;
                                            mimetype = mimetype + "-thumbnails";
                                        }
                                        else
                                            thisFile.ID = "GIF" + page_and_group_number;
                                        break;
                                    case "image/jp2":
                                        thisFile.ID = "JP2" + page_and_group_number;
                                        break;
                                    default:
                                        if (fileExtension.Length > 0)
                                        {
                                            thisFile.ID = fileExtension + page_and_group_number;
                                        }
                                        else
                                        {
                                            thisFile.ID = "NOEXT" + page_and_group_number;
                                        }
                                        break;
                                }

                                // Ensure this fileid is really unique.  It may not be if there are multiple
                                // files of the same mime-type in the same page.  (such as 0001.jpg and 0001.qc.jpg)
                                if (fileids_used.Contains(thisFile.ID))
                                {
                                    int count = 2;
                                    while (fileids_used.Contains(thisFile.ID + "." + count))
                                        count++;
                                    thisFile.ID = thisFile.ID + "." + count;
                                }

                                // Save this file id
                                fileids_used.Add(thisFile.ID);

                                // Also add to the list of files
                                allFiles.Add(thisFile);

                                // Also ensure we know there are page image files
                                hasPageFiles = true;


                                // If this is a new MIME type, add it, else just save this file in the MIME hash
                                if (!mimeHash.ContainsKey(mimetype))
                                {
                                    List<SobekCM_File_Info> newList = new List<SobekCM_File_Info> {thisFile};
                                    mimeHash[mimetype] = newList;
                                }
                                else
                                {
                                    mimeHash[mimetype].Add(thisFile);
                                }
                            }
                        }

                        // Prepare for the next page
                        page_and_group_number++;
                    }
                    else
                    {
                        // Page has no files, so it should be skipped when written
                        pageNode.ID = "SKIP";
                    }
                }
                else
                {
                    // This node is a DIVISION (non-page)
                    thisNode.ID = "PDIV" + division_number;
                    division_number++;
                }
            }


            // Clear any existing ID's here since the ID's are only used for writing METS files
            foreach (abstract_TreeNode thisNode in downloadDivisions)
            {
                thisNode.ID = String.Empty;
                thisNode.DMDID = String.Empty;
                thisNode.ADMID = String.Empty;
            }

            // Now, do the same thing for the download/other files division tree
            // Group numbers in the METS file correspond to files on the same page (physical or other)
            // At the same time, we will build the list of all files and files by mime type
            page_and_group_number = 1;
            division_number = 1;
            foreach (abstract_TreeNode thisNode in downloadDivisions)
            {
                // If this node was already hit (perhaps if a div has two parent divs), 
                // then skip it
                if (thisNode.ID.Length > 0)
                    continue;

                // Add this to the list of all nodes
                allDivisions.Add(thisNode);

                // Was this a PAGE or a DIVISION node?
                if (thisNode.Page)
                {
                    // Get this page node
                    Page_TreeNode pageNode = (Page_TreeNode) thisNode;

                    // Only do anything if there are actually any files here
                    if ((pageNode.Files != null) && (pageNode.Files.Count > 0))
                    {

                        // Set the page ID here
                        pageNode.ID = "FILES" + page_and_group_number;

                        // Step through any files under this page
                        foreach (SobekCM_File_Info thisFile in pageNode.Files)
                        {
                            // Set the ADMID and DMDID to empty in preparation for METS writing
                            thisFile.ADMID = String.Empty;
                            thisFile.DMDID = String.Empty;

                            // If no file name, skip this
                            if (String.IsNullOrEmpty(thisFile.System_Name))
                                continue;

                            // Get this file extension and MIME type
                            string fileExtension = thisFile.File_Extension;
                            string mimetype = thisFile.MIME_Type(thisFile.File_Extension);

                            // If this is going to be excluded from appearing in the METS file, just skip 
                            // it here as well.
                            if (!mimes_to_exclude.Contains(mimetype))
                            {
                                // Set the group number on this file
                                thisFile.Group_Number = "G" + page_and_group_number;

                                // Set the ID for this file as well
                                switch (mimetype)
                                {
                                    case "image/tiff":
                                        thisFile.ID = "TIF" + page_and_group_number;
                                        break;
                                    case "text/plain":
                                        thisFile.ID = "TXT" + page_and_group_number;
                                        break;
                                    case "image/jpeg":
                                        if (thisFile.System_Name.ToLower().IndexOf("thm.jp") > 0)
                                        {
                                            thisFile.ID = "THUMB" + page_and_group_number;
                                            mimetype = mimetype + "-thumbnails";
                                        }
                                        else
                                            thisFile.ID = "JPEG" + page_and_group_number;
                                        break;
                                    case "image/gif":
                                        if (thisFile.System_Name.ToLower().IndexOf("thm.gif") > 0)
                                        {
                                            thisFile.ID = "THUMB" + page_and_group_number;
                                            mimetype = mimetype + "-thumbnails";
                                        }
                                        else
                                            thisFile.ID = "GIF" + page_and_group_number;
                                        break;
                                    case "image/jp2":
                                        thisFile.ID = "JP2" + page_and_group_number;
                                        break;
                                    default:
                                        if (fileExtension.Length > 0)
                                        {
                                            thisFile.ID = fileExtension + page_and_group_number;
                                        }
                                        else
                                        {
                                            thisFile.ID = "NOEXT" + page_and_group_number;
                                        }
                                        break;
                                }

                                // Ensure this fileid is really unique.  It may not be if there are multiple
                                // files of the same mime-type in the same page.  (such as 0001.jpg and 0001.qc.jpg)
                                if (fileids_used.Contains(thisFile.ID))
                                {
                                    int count = 2;
                                    while (fileids_used.Contains(thisFile.ID + "." + count))
                                        count++;
                                    thisFile.ID = thisFile.ID + "." + count;
                                }

                                // Save this file id
                                fileids_used.Add(thisFile.ID);

                                // Also add to the list of files
                                allFiles.Add(thisFile);

                                // Also ensure we know there are page image files
                                hasDownloadFiles = true;


                                // If this is a new MIME type, add it, else just save this file in the MIME hash
                                if (!mimeHash.ContainsKey(mimetype))
                                {
                                    List<SobekCM_File_Info> newList = new List<SobekCM_File_Info> {thisFile};
                                    mimeHash[mimetype] = newList;
                                }
                                else
                                {
                                    mimeHash[mimetype].Add(thisFile);
                                }
                            }
                        }

                        // Prepare for the next page
                        page_and_group_number++;
                    }
                    else
                    {
                        // Page has no files, so it should be skipped when written
                        pageNode.ID = "SKIP";
                    }
                }
                else
                {
                    // This node is a DIVISION (non-page)
                    thisNode.ID = "ODIV" + division_number;
                    division_number++;
                }
            }

            #endregion

            // Add the XML declaration
            Output_Stream.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>");

            #region Write some processing instructions requested by Florida SUS's / FLVC (hope to deprecate)

            // Some special code for setting processing parameters
            bool daitssWriterIncluded = false;
            foreach (METS_Section_ReaderWriter_Config thisConfig in profile.Package_Level_AmdSec_Writer_Configs)
            {
                if (thisConfig.Code_Class == "DAITSS_METS_amdSec_ReaderWriter")
                {
                    daitssWriterIncluded = true;
                    break;
                }
            }
            if (daitssWriterIncluded)
            {
                DAITSS_Info daitssInfo = Item_To_Save.Get_Metadata_Module(GlobalVar.DAITSS_METADATA_MODULE_KEY) as DAITSS_Info;
                if (daitssInfo != null)
                {
                    if ((daitssInfo.hasData) && (daitssInfo.toArchive))
                    {
                        Output_Stream.WriteLine("<?fcla fda=\"yes\"?>");
                    }
                    else
                    {
                        Output_Stream.WriteLine("<?fcla fda=\"no\"?>");
                    }
                }
            }

            #endregion

            // Add a remark here with the title and type
            Output_Stream.WriteLine("<!--  " + Item_To_Save.Bib_Info.Main_Title.Title_XML.Replace("-", " ") + " ( " + Item_To_Save.Bib_Info.SobekCM_Type_String + " ) -->");

            // Add the METS declaration information
            Output_Stream.WriteLine("<METS:mets OBJID=\"" + Item_To_Save.METS_Header.ObjectID + "\"");
            Output_Stream.WriteLine("  xmlns:METS=\"http://www.loc.gov/METS/\"");
            Output_Stream.WriteLine("  xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
            Output_Stream.WriteLine("  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");

            #region Add XMLNS and schema locations for active METS section reader/writers with data to write

            // Collect all the xmlns and schema locations
            List<string> xmlnsList = new List<string>();
            List<string> schemaLocList = new List<string>();
            foreach (METS_Section_ReaderWriter_Config thisRWconfig in profile.Package_Level_AmdSec_Writer_Configs)
            {
                iPackage_amdSec_ReaderWriter thisRw = (iPackage_amdSec_ReaderWriter) thisRWconfig.ReaderWriterObject;
                if (thisRw.Schema_Reference_Required_Package(Item_To_Save))
                {
                    string[] rwXmlns = thisRw.Schema_Namespace(Item_To_Save);
                    string[] rwSchema = thisRw.Schema_Location(Item_To_Save);
                    foreach (string thisValue in rwXmlns)
                    {
                        if (!xmlnsList.Contains(thisValue))
                            xmlnsList.Add(thisValue);
                    }
                    foreach (string thisValue in rwSchema)
                    {
                        if (!schemaLocList.Contains(thisValue))
                            schemaLocList.Add(thisValue);
                    }
                }
            }
            foreach (METS_Section_ReaderWriter_Config thisRWconfig in profile.Package_Level_DmdSec_Writer_Configs)
            {
                iPackage_dmdSec_ReaderWriter thisRw = (iPackage_dmdSec_ReaderWriter) thisRWconfig.ReaderWriterObject;
                if (thisRw.Schema_Reference_Required_Package(Item_To_Save))
                {
                    string[] rwXmlns = thisRw.Schema_Namespace(Item_To_Save);
                    string[] rwSchema = thisRw.Schema_Location(Item_To_Save);
                    foreach (string thisValue in rwXmlns)
                    {
                        if (!xmlnsList.Contains(thisValue))
                            xmlnsList.Add(thisValue);
                    }
                    foreach (string thisValue in rwSchema)
                    {
                        if (!schemaLocList.Contains(thisValue))
                            schemaLocList.Add(thisValue);
                    }
                }
            }
            foreach (METS_Section_ReaderWriter_Config thisRWconfig in profile.Division_Level_AmdSec_Writer_Configs)
            {
                iDivision_amdSec_ReaderWriter thisRw = (iDivision_amdSec_ReaderWriter)thisRWconfig.ReaderWriterObject;
                foreach (abstract_TreeNode thisNode in physicalDivisions)
                {
                    if (thisRw.Schema_Reference_Required_Division(thisNode))
                    {
                        string[] rwXmlns = thisRw.Schema_Namespace(Item_To_Save);
                        string[] rwSchema = thisRw.Schema_Location(Item_To_Save);
                        foreach (string thisValue in rwXmlns)
                        {
                            if (!xmlnsList.Contains(thisValue))
                                xmlnsList.Add(thisValue);
                        }
                        foreach (string thisValue in rwSchema)
                        {
                            if (!schemaLocList.Contains(thisValue))
                                schemaLocList.Add(thisValue);
                        }

                        break;
                    }
                }
            }
            foreach (METS_Section_ReaderWriter_Config thisRWconfig in profile.Division_Level_DmdSec_Writer_Configs)
            {
                iDivision_dmdSec_ReaderWriter thisRw = (iDivision_dmdSec_ReaderWriter)thisRWconfig.ReaderWriterObject;
                foreach (abstract_TreeNode thisNode in physicalDivisions)
                {
                    if (thisRw.Schema_Reference_Required_Division(thisNode))
                    {
                        string[] rwXmlns = thisRw.Schema_Namespace(Item_To_Save);
                        string[] rwSchema = thisRw.Schema_Location(Item_To_Save);
                        foreach (string thisValue in rwXmlns)
                        {
                            if (!xmlnsList.Contains(thisValue))
                                xmlnsList.Add(thisValue);
                        }
                        foreach (string thisValue in rwSchema)
                        {
                            if (!schemaLocList.Contains(thisValue))
                                schemaLocList.Add(thisValue);
                        }

                        break;
                    }
                }
            }

            // Add the namespaces
            foreach (string namespaces in xmlnsList)
            {
                Output_Stream.WriteLine("  xmlns:" + namespaces);
            }

            Output_Stream.WriteLine("  xsi:schemaLocation=\"http://www.loc.gov/METS/");
            Output_Stream.Write("    http://www.loc.gov/standards/mets/mets.xsd");

            // Add the schema locations
            foreach (string location in schemaLocList)
            {
                Output_Stream.WriteLine();
                Output_Stream.Write(location);
            }

            #endregion

            Output_Stream.WriteLine("\">");

            // Add the METS declaration information and METS header
            Item_To_Save.METS_Header.Add_METS(Item_To_Save, Output_Stream);

            // Create the options dictionary for these writers
            Dictionary<string, object> options = new Dictionary<string, object>();
            options["SobekCM_FileInfo_METS_amdSec_ReaderWriter:All_Files"] = allFiles;

            // Counters to keep track of the number of each section added
            int dmdSec_counter = 1;
            int digiProvMd = 1;
            int rightsMd = 1;
            int sourceMd = 1;
            int techMd = 1;

            #region Add all the package-level DMDSECs 

            // Prepare to add all the bibliographic section
            StringBuilder dmd_secid_builder = new StringBuilder();

            // Step through all the package level dmdSecs to be added
            foreach (METS_Section_ReaderWriter_Config thisConfig in profile.Package_Level_DmdSec_Writer_Configs)
            {
                iPackage_dmdSec_ReaderWriter thisWriter = (iPackage_dmdSec_ReaderWriter) thisConfig.ReaderWriterObject;
                if (thisWriter.Include_dmdSec(Item_To_Save, options))
                {
                    // Save this DMD ID
                    dmd_secid_builder.Append("DMD" + dmdSec_counter + " ");

                    // Start this METS section
                    Output_Stream.WriteLine("<METS:dmdSec ID=\"DMD" + dmdSec_counter + "\">");
                    if (thisConfig.Default_Mapping.Other_MD_Type.Length > 0)
                        Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  OTHERMDTYPE=\"" + thisConfig.Default_Mapping.Other_MD_Type + "\" MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");
                    else
                        Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");

                    Output_Stream.WriteLine("<METS:xmlData>");

                    // Add the amd section to the stream
                    thisWriter.Write_dmdSec(Output_Stream, Item_To_Save, options);

                    // Close this METS section
                    Output_Stream.WriteLine("</METS:xmlData>");
                    Output_Stream.WriteLine("</METS:mdWrap>");
                    Output_Stream.WriteLine("</METS:dmdSec>");

                    dmdSec_counter++;
                }
            }

            // Now, add any unanalyzed DMD sections
            if (( Item_To_Save.Unanalyzed_DMDSECs != null ) && ( Item_To_Save.Unanalyzed_DMDSECs.Count > 0 ))
            {
                foreach (Unanalyzed_METS_Section thisSection in Item_To_Save.Unanalyzed_DMDSECs)
                {
                    // This wll be linked to the top-level
                    dmd_secid_builder.Append("DMD" + dmdSec_counter + " ");

                    // Add this to the output stream
                    Output_Stream.Write("<METS:dmdSec ID=\"DMD" + dmdSec_counter + "\"");

                    foreach (KeyValuePair<string, string> attribute in thisSection.Section_Attributes)
                    {
                        if (attribute.Key != "ID")
                            Output_Stream.Write(" " + attribute.Key + "=\"" + attribute.Value + "\"");
                    }
                    Output_Stream.WriteLine(">");
                    Output_Stream.WriteLine(thisSection.Inner_XML);
                    Output_Stream.WriteLine("</METS:dmdSec>");

                    dmdSec_counter++;
                }
            }

            #endregion

            #region Add all the division-level DMDSECs

            // Should we add DMDSEC metadata sections for the divisions?
            // Step through all the possible division level dmdSecs to be added
            foreach (METS_Section_ReaderWriter_Config thisConfig in profile.Division_Level_DmdSec_Writer_Configs)
            {
                // Step through each division
                foreach (abstract_TreeNode thisDivision in allDivisions)
                {
                    iDivision_dmdSec_ReaderWriter thisWriter = (iDivision_dmdSec_ReaderWriter) thisConfig.ReaderWriterObject;

                    // Include the DMD Sec for this division?
                    if (thisWriter.Include_dmdSec(thisDivision, options))
                    {
                        // Save this DMD ID
                        thisDivision.DMDID = thisDivision.DMDID + "DMD" + dmdSec_counter + " ";

                        // Start this METS section
                        Output_Stream.WriteLine("<METS:dmdSec ID=\"DMD" + dmdSec_counter + "\">");
                        if (thisConfig.Default_Mapping.Other_MD_Type.Length > 0)
                            Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  OTHERMDTYPE=\"" + thisConfig.Default_Mapping.Other_MD_Type + "\" MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");
                        else
                            Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");

                        Output_Stream.WriteLine("<METS:xmlData>");

                        // Add the amd section to the stream
                        thisWriter.Write_dmdSec(Output_Stream, thisDivision, options);

                        // Close this METS section
                        Output_Stream.WriteLine("</METS:xmlData>");
                        Output_Stream.WriteLine("</METS:mdWrap>");
                        Output_Stream.WriteLine("</METS:dmdSec>");

                        dmdSec_counter++;
                    }
                }
            }


            #endregion

            #region Add all the file-level DMDSECs

            // Should we add DMDSEC metadata sections for the files?
            // Step through all the possible file level dmdSecs to be added
            foreach (METS_Section_ReaderWriter_Config thisConfig in profile.File_Level_DmdSec_Writer_Configs)
            {
                // Step through each file
                foreach (SobekCM_File_Info thisFile in allFiles)
                {
                    iFile_dmdSec_ReaderWriter thisWriter = (iFile_dmdSec_ReaderWriter)thisConfig.ReaderWriterObject;

                    // Include the DMD Sec for this file?
                    if (thisWriter.Include_dmdSec(thisFile, options))
                    {
                        // Save this DMD ID
                        thisFile.DMDID = thisFile.DMDID + "DMD" + dmdSec_counter + " ";

                        // Start this METS section
                        Output_Stream.WriteLine("<METS:dmdSec ID=\"DMD" + dmdSec_counter + "\">");
                        if (thisConfig.Default_Mapping.Other_MD_Type.Length > 0)
                            Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  OTHERMDTYPE=\"" + thisConfig.Default_Mapping.Other_MD_Type + "\" MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");
                        else
                            Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");

                        Output_Stream.WriteLine("<METS:xmlData>");

                        // Add the amd section to the stream
                        thisWriter.Write_dmdSec(Output_Stream, thisFile, options);

                        // Close this METS section
                        Output_Stream.WriteLine("</METS:xmlData>");
                        Output_Stream.WriteLine("</METS:mdWrap>");
                        Output_Stream.WriteLine("</METS:dmdSec>");

                        dmdSec_counter++;
                    }
                }
            }


            #endregion

            #region Add all the package-level AMDSECs

            // Prepare to add all the bibliographic section
            StringBuilder amd_secid_builder = new StringBuilder();

            // Step through all the package level amdSecs to be added
            foreach (METS_Section_ReaderWriter_Config thisConfig in profile.Package_Level_AmdSec_Writer_Configs)
            {
                iPackage_amdSec_ReaderWriter thisWriter = (iPackage_amdSec_ReaderWriter)thisConfig.ReaderWriterObject;
                if (thisWriter.Include_amdSec(Item_To_Save, options))
                {
                    // Start this METS section
                    Output_Stream.WriteLine("<METS:amdSec>");
                    switch (thisConfig.AmdSecType)
                    {
                        case METS_amdSec_Type_Enum.DigiProvMD:
                            Output_Stream.WriteLine("<METS:digiprovMD ID=\"DIGIPROV" + digiProvMd + "\">");
                            amd_secid_builder.Append("DIGIPROV" + digiProvMd + " ");
                            digiProvMd++;
                            break;

                        case METS_amdSec_Type_Enum.RightsMD:
                            Output_Stream.WriteLine("<METS:rightsMD ID=\"RIGHTS" + rightsMd + "\">");
                            amd_secid_builder.Append("RIGHTS" + rightsMd + " ");
                            rightsMd++;
                            break;

                        case METS_amdSec_Type_Enum.SourceMD:
                            Output_Stream.WriteLine("<METS:sourceMD ID=\"SOURCE" + sourceMd + "\">");
                            amd_secid_builder.Append("SOURCE" + sourceMd + " ");
                            sourceMd++;
                            break;

                        case METS_amdSec_Type_Enum.TechMD:
                            Output_Stream.WriteLine("<METS:techMD ID=\"TECH" + techMd + "\">");
                            amd_secid_builder.Append("TECH" + techMd + " ");
                            techMd++;
                            break;

                        default:
                            Output_Stream.WriteLine("<METS:rightsMD ID=\"RIGHTS" + rightsMd + "\">");
                            amd_secid_builder.Append("RIGHTS" + rightsMd + " ");
                            rightsMd++;
                            break;
                    }


                    if (thisConfig.Default_Mapping.Other_MD_Type.Length > 0)
                        Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  OTHERMDTYPE=\"" + thisConfig.Default_Mapping.Other_MD_Type + "\" MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");
                    else
                        Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");

                    Output_Stream.WriteLine("<METS:xmlData>");

                    // Add the amd section to the stream
                    thisWriter.Write_amdSec(Output_Stream, Item_To_Save, options);

                    // Close this METS section
                    Output_Stream.WriteLine("</METS:xmlData>");
                    Output_Stream.WriteLine("</METS:mdWrap>");

                    switch (thisConfig.AmdSecType)
                    {
                        case METS_amdSec_Type_Enum.DigiProvMD:
                            Output_Stream.WriteLine("</METS:digiprovMD>");
                            break;

                        case METS_amdSec_Type_Enum.RightsMD:
                            Output_Stream.WriteLine("</METS:rightsMD>");
                            break;

                        case METS_amdSec_Type_Enum.SourceMD:
                            Output_Stream.WriteLine("</METS:sourceMD>");
                            break;

                        case METS_amdSec_Type_Enum.TechMD:
                            Output_Stream.WriteLine("</METS:techMD>");
                            break;

                        default:
                            Output_Stream.WriteLine("</METS:rightsMD>");
                            break;
                    }

                    Output_Stream.WriteLine("</METS:amdSec>");
                }
            }

            // Now, add any unanalyzed AMD sections
            if (Item_To_Save.Unanalyzed_AMDSECs != null)
            {
                foreach (Unanalyzed_METS_Section thisSection in Item_To_Save.Unanalyzed_AMDSECs)
                {
                    // Add this to the output stream
                    Output_Stream.Write("<METS:amdSec");
                    foreach (KeyValuePair<string, string> attribute in thisSection.Section_Attributes)
                    {
                        if (attribute.Key != "ID")
                            Output_Stream.Write(" " + attribute.Key + "=\"" + attribute.Value + "\"");
                    }
                    Output_Stream.WriteLine(">");
                    Output_Stream.WriteLine(thisSection.Inner_XML);
                    Output_Stream.WriteLine("</METS:amdSec>");
                }
            }

            #endregion

            #region Add all the division-level AMDSECs

            // Should we add AMDSEC metadata sections for the divisions?
            // Step through all the possible division level amdSecs to be added
            foreach (METS_Section_ReaderWriter_Config thisConfig in profile.Division_Level_AmdSec_Writer_Configs)
            {
                // Step through each division
                foreach (abstract_TreeNode thisDivision in allDivisions)
                {

                    iDivision_amdSec_ReaderWriter thisWriter = (iDivision_amdSec_ReaderWriter) thisConfig.ReaderWriterObject;

                    // Include the DMD Sec for this division?
                    if (thisWriter.Include_amdSec(thisDivision, options))
                    {
                        // Start this METS section
                        Output_Stream.WriteLine("<METS:amdSec>");
                        switch (thisConfig.AmdSecType)
                        {
                            case METS_amdSec_Type_Enum.DigiProvMD:
                                Output_Stream.WriteLine("<METS:digiProvMD ID=\"DIGIPROV" + digiProvMd + "\">");
                                thisDivision.ADMID = thisDivision.ADMID + "DIGIPROV" + digiProvMd + " ";
                                digiProvMd++;
                                break;

                            case METS_amdSec_Type_Enum.RightsMD:
                                Output_Stream.WriteLine("<METS:rightsMD ID=\"RIGHTS" + rightsMd + "\">");
                                thisDivision.ADMID = thisDivision.ADMID + "RIGHTS" + rightsMd + " ";
                                rightsMd++;
                                break;

                            case METS_amdSec_Type_Enum.SourceMD:
                                Output_Stream.WriteLine("<METS:sourceMD ID=\"SOURCE" + sourceMd + "\">");
                                thisDivision.ADMID = thisDivision.ADMID + "SOURCE" + sourceMd + " ";
                                sourceMd++;
                                break;

                            case METS_amdSec_Type_Enum.TechMD:
                                Output_Stream.WriteLine("<METS:techMD ID=\"TECH" + techMd + "\">");
                                thisDivision.ADMID = thisDivision.ADMID + "TECH" + techMd + " ";
                                techMd++;
                                break;

                            default:
                                Output_Stream.WriteLine("<METS:rightsMD ID=\"RIGHTS" + rightsMd + "\">");
                                thisDivision.ADMID = thisDivision.ADMID + "RIGHTS" + rightsMd + " ";
                                rightsMd++;
                                break;
                        }


                        if (thisConfig.Default_Mapping.Other_MD_Type.Length > 0)
                            Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  OTHERMDTYPE=\"" + thisConfig.Default_Mapping.Other_MD_Type + "\" MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");
                        else
                            Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");

                        Output_Stream.WriteLine("<METS:xmlData>");
                        Output_Stream.WriteLine("<METS:xmlData>");

                        // Add the amd section to the stream
                        thisWriter.Write_amdSec(Output_Stream, thisDivision, options);

                        // Close this METS section
                        Output_Stream.WriteLine("</METS:xmlData>");
                        Output_Stream.WriteLine("</METS:mdWrap>");

                        switch (thisConfig.AmdSecType)
                        {
                            case METS_amdSec_Type_Enum.DigiProvMD:
                                Output_Stream.WriteLine("</METS:digiProvMD>");
                                break;

                            case METS_amdSec_Type_Enum.RightsMD:
                                Output_Stream.WriteLine("</METS:rightsMD>");
                                break;

                            case METS_amdSec_Type_Enum.SourceMD:
                                Output_Stream.WriteLine("</METS:sourceMD>");
                                break;

                            case METS_amdSec_Type_Enum.TechMD:
                                Output_Stream.WriteLine("</METS:techMD>");
                                break;

                            default:
                                Output_Stream.WriteLine("</METS:rightsMD>");
                                break;
                        }

                        Output_Stream.WriteLine("</METS:amdSec>");

                        dmdSec_counter++;
                    }
                }
            }



            #endregion

            #region Add all the file-level AMDSECs

            // Should we add AMDSEC metadata sections for the files?
            // Step through all the possible file level amdSecs to be added
            foreach (METS_Section_ReaderWriter_Config thisConfig in profile.File_Level_AmdSec_Writer_Configs)
            {
                // Step through each file
                foreach (SobekCM_File_Info thisFile in allFiles)
                {

                    iFile_amdSec_ReaderWriter thisWriter = (iFile_amdSec_ReaderWriter)thisConfig.ReaderWriterObject;

                    // Include the DMD Sec for this file?
                    if (thisWriter.Include_amdSec(thisFile, options))
                    {
                        // Start this METS section
                        Output_Stream.WriteLine("<METS:amdSec>");
                        switch (thisConfig.AmdSecType)
                        {
                            case METS_amdSec_Type_Enum.DigiProvMD:
                                Output_Stream.WriteLine("<METS:digiProvMD ID=\"DIGIPROV" + digiProvMd + "\">");
                                thisFile.ADMID = thisFile.ADMID + "DIGIPROV" + digiProvMd + " ";
                                digiProvMd++;
                                break;

                            case METS_amdSec_Type_Enum.RightsMD:
                                Output_Stream.WriteLine("<METS:rightsMD ID=\"RIGHTS" + rightsMd + "\">");
                                thisFile.ADMID = thisFile.ADMID + "RIGHTS" + rightsMd + " ";
                                rightsMd++;
                                break;

                            case METS_amdSec_Type_Enum.SourceMD:
                                Output_Stream.WriteLine("<METS:sourceMD ID=\"SOURCE" + sourceMd + "\">");
                                thisFile.ADMID = thisFile.ADMID + "SOURCE" + sourceMd + " ";
                                sourceMd++;
                                break;

                            case METS_amdSec_Type_Enum.TechMD:
                                Output_Stream.WriteLine("<METS:techMD ID=\"TECH" + techMd + "\">");
                                thisFile.ADMID = thisFile.ADMID + "TECH" + techMd + " ";
                                techMd++;
                                break;

                            default:
                                Output_Stream.WriteLine("<METS:rightsMD ID=\"RIGHTS" + rightsMd + "\">");
                                thisFile.ADMID = thisFile.ADMID + "RIGHTS" + rightsMd + " ";
                                rightsMd++;
                                break;
                        }


                        if (thisConfig.Default_Mapping.Other_MD_Type.Length > 0)
                            Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  OTHERMDTYPE=\"" + thisConfig.Default_Mapping.Other_MD_Type + "\" MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");
                        else
                            Output_Stream.WriteLine("<METS:mdWrap MDTYPE=\"" + thisConfig.Default_Mapping.MD_Type + "\"  MIMETYPE=\"text/xml\" LABEL=\"" + thisConfig.Default_Mapping.Label + "\">");

                        Output_Stream.WriteLine("<METS:xmlData>");
                        Output_Stream.WriteLine("<METS:xmlData>");

                        // Add the amd section to the stream
                        thisWriter.Write_amdSec(Output_Stream, thisFile, options);

                        // Close this METS section
                        Output_Stream.WriteLine("</METS:xmlData>");
                        Output_Stream.WriteLine("</METS:mdWrap>");

                        switch (thisConfig.AmdSecType)
                        {
                            case METS_amdSec_Type_Enum.DigiProvMD:
                                Output_Stream.WriteLine("</METS:digiProvMD>");
                                break;

                            case METS_amdSec_Type_Enum.RightsMD:
                                Output_Stream.WriteLine("</METS:rightsMD>");
                                break;

                            case METS_amdSec_Type_Enum.SourceMD:
                                Output_Stream.WriteLine("</METS:sourceMD>");
                                break;

                            case METS_amdSec_Type_Enum.TechMD:
                                Output_Stream.WriteLine("</METS:techMD>");
                                break;

                            default:
                                Output_Stream.WriteLine("</METS:rightsMD>");
                                break;
                        }

                        Output_Stream.WriteLine("</METS:amdSec>");

                        dmdSec_counter++;
                    }
                }
            }



            #endregion

            // Add file and structure map sections
            if ( allFiles.Count > 0 )
            {
                #region Add the files section

                // Start the files section
                Output_Stream.WriteLine("<METS:fileSec>");

                // Step through each mime type
                foreach (string thisMimeType in mimeHash.Keys)
                {
                    List<SobekCM_File_Info> mimeCollection = mimeHash[thisMimeType];

                    // Start this file group section
                    Output_Stream.WriteLine(thisMimeType == "image/tiff" ? "<METS:fileGrp USE=\"archive\" >" : "<METS:fileGrp USE=\"reference\" >");

                    // Step through each file of this mime type and append the METS
                    foreach (SobekCM_File_Info thisFile in mimeCollection)
                    {
                        // Is the size and checksum information here?
                        if ((!MINIMIZE_FILE_SIZE) && ( !Item_To_Save.Divisions.Suppress_Checksum )) 
                        {
                            if ((((String.IsNullOrEmpty(thisFile.Checksum)) || (thisFile.Size <= 0))) && (thisFile.METS_LocType == SobekCM_File_Info_Type_Enum.SYSTEM))
                            {
                                // Perform in a try catch
                                try
                                {
                                    if (File.Exists(Item_To_Save.Source_Directory + "/" + thisFile.System_Name))
                                    {
                                        // Get the size first
                                        if ( thisFile.Size < 0 )
                                        {
                                            FileInfo thisFileInfo = new FileInfo(Item_To_Save.Source_Directory + "/" + thisFile.System_Name);
                                            thisFile.Size = thisFileInfo.Length;
                                        }

                                        // Get the checksum, if it doesn't exist
                                        if (String.IsNullOrEmpty(thisFile.Checksum))
                                        {
                                            FileMD5 checksummer = new FileMD5(Item_To_Save.Source_Directory + "/" + thisFile.System_Name);
                                            thisFile.Checksum = checksummer.Checksum;

                                            // Set the checksum type
                                            thisFile.Checksum_Type = "MD5";
                                        }
                                    }
                                }
                                catch
                                {
                                }
                            }
                        }

                        // Start out this file 
                        Output_Stream.Write("<METS:file GROUPID=\"" + thisFile.Group_Number + "\" ID=\"" + thisFile.ID + "\" MIMETYPE=\"" + thisMimeType + "\"");

                        // Add links to dmd secs and amd secs
                        if (!String.IsNullOrEmpty(thisFile.DMDID))
                        {
                            Output_Stream.Write(" DMDID=\"" + thisFile.DMDID + "\"");
                        }
                        if (!String.IsNullOrEmpty(thisFile.ADMID))
                        {
                            Output_Stream.Write(" ADMID=\"" + thisFile.ADMID + "\"");
                        }

                        // Add the checksum it it exists
                        if ((!MINIMIZE_FILE_SIZE) && (!String.IsNullOrEmpty(thisFile.Checksum)))
                        {
                            Output_Stream.Write(" CHECKSUM=\"" + thisFile.Checksum + "\"");

                            // Add the checksum type if there was one (SHOULD be one here)
                            if (!String.IsNullOrEmpty(thisFile.Checksum_Type))
                            {
                                Output_Stream.Write(" CHECKSUMTYPE=\"" + thisFile.Checksum_Type + "\"");
                            }
                        }

                        // Add the size of the file, if it exists
                        if ((!MINIMIZE_FILE_SIZE) && (thisFile.Size > 0))
                        {
                            Output_Stream.Write(" SIZE=\"" + thisFile.Size + "\"");
                        }

                        // Close out this beginning file tag
                        Output_Stream.WriteLine(">");

                        // Include the system name or URL
                        if (thisFile.METS_LocType == SobekCM_File_Info_Type_Enum.URL)
                        {
                            Output_Stream.WriteLine("<METS:FLocat LOCTYPE=\"URL\" xlink:href=\"" + thisFile.System_Name.Replace(" ", "%20").Replace("&", "&amp;") + "\" />");
                        }
                        else
                        {
                            Output_Stream.WriteLine("<METS:FLocat LOCTYPE=\"OTHER\" OTHERLOCTYPE=\"SYSTEM\" xlink:href=\"" + thisFile.System_Name.Replace(" ", "%20").Replace("&", "&amp;").Replace("\\", "/") + "\" />");
                        }

                        // Add the closing file tag
                        Output_Stream.WriteLine("</METS:file>");
                    }

                    // Close out this file group section
                    Output_Stream.WriteLine("</METS:fileGrp>");
                }

                // Finish out the file section
                Output_Stream.WriteLine("</METS:fileSec>");

                #endregion

                #region Add the structure map section

                Dictionary<abstract_TreeNode, int> pages_to_appearances = new Dictionary<abstract_TreeNode, int>();

                // May or may not be AMDSecs and DMDsec
                string dmdSecIdString = dmd_secid_builder.ToString().Trim();
                string amdSecIdString = amd_secid_builder.ToString().Trim();

                // Add the physical page structure map first
                if (hasPageFiles)
                {
                    Output_Stream.WriteLine("<METS:structMap ID=\"STRUCT1\" TYPE=\"physical\">");

                    // Add any outer divisions here
                    if ( Item_To_Save.Divisions.Outer_Division_Count > 0)
                    {
                        foreach (Outer_Division_Info outerDiv in Item_To_Save.Divisions.Outer_Divisions)
                        {
                            Output_Stream.Write("<METS:div");
                            if (dmdSecIdString.Length > 0)
                            {
                                Output_Stream.Write(" DMDID=\"" + dmdSecIdString + "\"");
                            }
                            if (outerDiv.Label.Length > 0)
                            {
                                Output_Stream.Write(" LABEL=\"" + Convert_String_To_XML_Safe_Static(outerDiv.Label) + "\"");
                            }
                            if (outerDiv.OrderLabel > 0)
                            {
                                Output_Stream.Write(" ORDERLABEL=\"" + outerDiv.OrderLabel + "\"");
                            }
                            if (outerDiv.Type.Length > 0)
                            {
                                Output_Stream.Write(" TYPE=\"" + Convert_String_To_XML_Safe_Static(outerDiv.Type) + "\"");
                            }
                            Output_Stream.WriteLine(">");
                        }
                    }
                    else
                    {
                        // Start the main division information
                        Output_Stream.Write("<METS:div");
                        if (dmdSecIdString.Length > 0)
                        {
                            Output_Stream.Write(" DMDID=\"" + dmdSecIdString + "\"");
                        }
                        if (amdSecIdString.Length > 0)
                        {
                            Output_Stream.Write(" ADMID=\"" + amdSecIdString + "\"");
                        }


                        // Add the title, if one was provided
                        string title = Item_To_Save.Bib_Info.Main_Title.ToString();
                        if (title.Length > 0)
                        {
                            Output_Stream.Write(" LABEL=\"" + title + "\"");
                        }

                        // Finish out this first, main division tag
                        Output_Stream.WriteLine(" ORDER=\"0\" TYPE=\"main\">");
                    }

                    // Add all the divisions recursively
                    int order = 1;
                    foreach (abstract_TreeNode thisRoot in Item_To_Save.Divisions.Physical_Tree.Roots)
                    {
                        recursively_add_div_info(thisRoot, Output_Stream, pages_to_appearances, order++);
                    }

                    // Close any outer divisions here
                    if (Item_To_Save.Divisions.Outer_Division_Count > 0)
                    {
                        for (int index = 0; index < Item_To_Save.Divisions.Outer_Division_Count; index++)
                        {
                            Output_Stream.WriteLine("</METS:div>");
                        }
                    }
                    else
                    {
                        // Close out the main division tag
                        Output_Stream.WriteLine("</METS:div>");
                    }

                    // Close out this structure map portion
                    Output_Stream.WriteLine("</METS:structMap>");
                }

                if (hasDownloadFiles)
                {
                    Output_Stream.WriteLine("<METS:structMap ID=\"STRUCT2\" TYPE=\"other\">");

                   // Add any outer divisions here
                    if ( Item_To_Save.Divisions.Outer_Division_Count > 0)
                    {
                        foreach (Outer_Division_Info outerDiv in Item_To_Save.Divisions.Outer_Divisions)
                        {
                            Output_Stream.Write("<METS:div");
                            if (dmdSecIdString.Length > 0)
                            {
                                Output_Stream.Write(" DMDID=\"" + dmdSecIdString + "\"");
                            }
                            if (outerDiv.Label.Length > 0)
                            {
                                Output_Stream.Write(" LABEL=\"" + Convert_String_To_XML_Safe_Static(outerDiv.Label) + "\"");
                            }
                            if (outerDiv.OrderLabel > 0)
                            {
                                Output_Stream.Write(" ORDERLABEL=\"" + outerDiv.OrderLabel + "\"");
                            }
                            if (outerDiv.Type.Length > 0)
                            {
                                Output_Stream.Write(" TYPE=\"" + Convert_String_To_XML_Safe_Static(outerDiv.Type) + "\"");
                            }
                            Output_Stream.WriteLine(">");
                        }
                    }
                    else
                    {
                        // Start the main division information
                        Output_Stream.Write("<METS:div");
                        if (dmdSecIdString.Length > 0)
                        {
                            Output_Stream.Write(" DMDID=\"" + dmdSecIdString + "\"");
                        }
                        if (amdSecIdString.Length > 0)
                        {
                            Output_Stream.Write(" ADMID=\"" + amdSecIdString + "\"");
                        }

                        // Add the title, if one was provided
                        string title = Item_To_Save.Bib_Info.Main_Title.ToString();
                        if (title.Length > 0)
                        {
                            Output_Stream.Write(" LABEL=\"" + title + "\"");
                        }

                        // Finish out this first, main division tag
                        Output_Stream.WriteLine(" ORDER=\"0\" TYPE=\"main\">");
                    }

                    // Add all the divisions recursively
                    int order = 1;
                    foreach (abstract_TreeNode thisRoot in Item_To_Save.Divisions.Download_Tree.Roots)
                    {
                        recursively_add_div_info(thisRoot, Output_Stream, pages_to_appearances, order++);
                    }

                    // Close any outer divisions here
                    if (Item_To_Save.Divisions.Outer_Division_Count > 0)
                    {
                        for (int index = 0; index < Item_To_Save.Divisions.Outer_Division_Count; index++)
                        {
                            Output_Stream.WriteLine("</METS:div>");
                        }
                    }
                    else
                    {
                        // Close out the main division tag
                        Output_Stream.WriteLine("</METS:div>");
                    }

                    // Close out this structure map portion
                    Output_Stream.WriteLine("</METS:structMap>");
                }

                #endregion
            }
            else
            {
                // Structure map is a required element for METS
                Output_Stream.Write("<METS:structMap ID=\"STRUCT1\" > <METS:div /> </METS:structMap>\r\n");
            }

            // Add the behavior section for SobekCM views and interfaces
            //if (embedded_metadata_types.Contains(Metadata_Type_Enum.SobekCM_Behaviors))
            //{
            //    Item_To_Save.Behaviors.Add_BehaviorSec_METS(Output, Item_To_Save.Divisions.Physical_Tree.Has_Files);
            //}

            // Close out the METS file
            Output_Stream.Write("</METS:mets>\r\n");

            return true;
        }

Same methods

METS_File_ReaderWriter::Write_Metadata ( string MetadataFilePathName, SobekCM_Item Item_To_Save, object>.Dictionary Options, string &Error_Message ) : bool

Usage Example

 /// <summary> Saves this resource as a SobekCM Service METS file </summary>
 /// <remarks> The SobekCM Service METS file tries to keep the file size as small as possible and also includes service information (image properties) that the standard SobekCM METS file does not include </remarks>
 public void Save_SobekCM_METS()
 {
     // Save this to the METS file format
     METS_File_ReaderWriter writer = new METS_File_ReaderWriter();
     string Error_Message;
     writer.Write_Metadata( Source_Directory + "\\" + BibID + "_" + VID + ".mets.xml", this, null, out Error_Message);
 }
All Usage Examples Of SobekCM.Resource_Object.Metadata_File_ReaderWriters.METS_File_ReaderWriter::Write_Metadata