/// <summary>
        /// Заполнение хеш таблицы данными о fb2-книгах в контексте Авторов
        /// </summary>
        /// <param name="fb2">объект класса FictionBook</param>
        /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param>
        /// <param name="SrcPath">путь к fb2-файлу</param>
        /// <param name="Encoding">кодировка текщего файла в fb2</param>
        /// <param name="sAuthor">Фамилия и 1-я буква Имени текущего автора</param>
        /// <param name="htFB2ForAuthorFIO">Хеш Таблица с книгами одинаковых Авторов</param>
        private void FB2AuthorFIOSetHashTable(FictionBook fb2, string ZipPath, string SrcPath, string Encoding,
                                              string sAuthor, ref HashtableClass htFB2ForAuthorFIO)
        {
            // данные о книге
            BookData fb2BookData = new BookData(
                fb2.TIBookTitle, fb2.TIAuthors, fb2.TIGenres, fb2.TILang, fb2.DIID, fb2.DIVersion, fb2.DIAuthors, SrcPath, Encoding
                );

            if (ZipPath != null)
            {
                fb2BookData.Path = ZipPath;
            }

            if (!htFB2ForAuthorFIO.ContainsKey(sAuthor))
            {
                // этого Автора sAuthor в Группе еще нет
                FB2FilesDataInGroup fb2f = new FB2FilesDataInGroup(fb2BookData, sAuthor);
                fb2f.Group = sAuthor;
                htFB2ForAuthorFIO.Add(sAuthor, fb2f);
            }
            else
            {
                // этот Автор sAuthor в Группе уже есть
                FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)htFB2ForAuthorFIO[sAuthor];
                fb2f.Add(fb2BookData);
                //htFB2ForBT[sAuthor] = fb2f; //ИЗБЫТОЧНЫЙ КОД
            }
        }
示例#2
0
        /// <summary>
        /// Заполнение хеш таблицы данными о fb2-книгах в контексте их md5
        /// </summary>
        /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param>
        /// <param name="SrcPath">путь к fb2-файлу;</param>
        /// <param name="htFB2ForMd5">Хеш Таблица с книгами с одинаковыми значениями Md5</param>
        private void MakeFB2Md5HashTable(string ZipPath, string SrcPath, ref HashtableClass htFB2ForMd5)
        {
            string md5 = ComputeMD5Checksum(SrcPath);

            FictionBook fb2 = null;

            try {
                fb2 = new FictionBook(SrcPath);
            } catch (Exception ex) {
                Debug.DebugMessage(
                    SrcPath, ex, "Дубликатор.CompareForm.MakeFB2Md5HashTable(): Заполнение хеш таблицы данными о fb2-книгах в контексте их md5."
                    );
                _nonOpenedFileList = _compComm.collectBadFB2(!string.IsNullOrEmpty(ZipPath) ? ZipPath : SrcPath);
                return;
            }

            string Encoding = fb2.getEncoding();

            if (string.IsNullOrWhiteSpace(Encoding))
            {
                Encoding = "?";
            }
            string ID = fb2.DIID;

            if (ID == null)
            {
                return;
            }

            if (ID.Trim().Length == 0)
            {
                ID = "Тег <id> в этих книгах \"пустой\"";
            }

            // данные о книге
            BookData fb2BookData = new BookData(
                fb2.TIBookTitle, fb2.TIAuthors, fb2.TIGenres, fb2.TILang, ID, fb2.DIVersion, fb2.DIAuthors, SrcPath, Encoding
                );

            if (ZipPath != null)
            {
                fb2BookData.Path = ZipPath;
            }

            if (!htFB2ForMd5.ContainsKey(md5))
            {
                // такой книги в числе дублей еще нет
                FB2FilesDataInGroup fb2f = new FB2FilesDataInGroup(fb2BookData, md5);
                htFB2ForMd5.Add(md5, fb2f);
            }
            else
            {
                // такая книга в числе дублей уже есть
                FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)htFB2ForMd5[md5];
                fb2f.Add(fb2BookData);
                //htFB2ForMd5[md5] = fb2f; //ИЗБЫТОЧНЫЙ КОД
            }
        }
        // сравнение только по названию группы (если они не одинаковые, то и содержимое групп - разное)
        public bool isSameGroup(FB2FilesDataInGroup RightValue)
        {
            if (RightValue == null)
            {
                return(false);
            }

            return(this.Group == RightValue.Group);
        }
        /// <summary>
        /// Заполнение хеш таблицы данными о fb2-книгах в контексте их Названия
        /// </summary>
        /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param>
        /// <param name="SrcPath">путь к fb2-файлу;</param>
        /// <param name="htFB2ForBT">Хеш Таблица с книгами с одинаковыми Названиями</param>
        private void MakeFB2BTHashTable(string ZipPath, string SrcPath, HashtableClass htFB2ForBT)
        {
            FictionBook fb2 = null;

            try {
                fb2 = new FictionBook(SrcPath);
            }
            catch (Exception ex) {
                Debug.DebugMessage(
                    SrcPath, ex, "Дубликатор.CompareForm.MakeFB2BTHashTable(): Заполнение хеш таблицы данными о fb2-книгах в контексте их Названия."
                    );
                _nonOpenedFileList = _compComm.collectBadFB2(!string.IsNullOrEmpty(ZipPath) ? ZipPath : SrcPath);
                return;
            }

            string Encoding = fb2.getEncoding();

            if (string.IsNullOrWhiteSpace(Encoding))
            {
                Encoding = "?";
            }

            BookTitle bookTitle = fb2.TIBookTitle;
            string    BT        = "<Название книги отсутствует>";

            if (bookTitle != null && !string.IsNullOrWhiteSpace(bookTitle.Value))
            {
                BT = bookTitle.Value.Trim();
            }

            // данные о книге
            BookData fb2BookData = new BookData(
                bookTitle, fb2.TIAuthors, fb2.TIGenres, fb2.TILang, fb2.DIID, fb2.DIVersion, fb2.DIAuthors, SrcPath, Encoding
                );

            if (ZipPath != null)
            {
                fb2BookData.Path = ZipPath;
            }

            if (!htFB2ForBT.ContainsKey(BT))
            {
                // такой книги в числе дублей еще нет
                FB2FilesDataInGroup fb2f = new FB2FilesDataInGroup(fb2BookData, BT);
                htFB2ForBT.Add(BT, fb2f);
            }
            else
            {
                // такая книга в числе дублей уже есть
                FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)htFB2ForBT[BT];
                fb2f.Add(fb2BookData);
                //htFB2ForBT[sBT] = fb2f; //ИЗБЫТОЧНЫЙ КОД
            }
        }
示例#5
0
        /// <summary>
        /// Заполнение хеш таблицы данными о fb2-книгах в контексте их ID
        /// </summary>
        /// <param name="ZipPath">путь к zip-архиву. Если книга - не запакована в zip, то ZipPath = null</param>
        /// <param name="SrcPath">путь к fb2-файлу;</param>
        /// <param name="htFB2ForID">Хеш Таблица с книгами с одинаковыми ID</param>
        private void MakeFB2IDHashTable(string ZipPath, string SrcPath, ref HashtableClass htFB2ForID)
        {
            FictionBook fb2 = null;

            try {
                fb2 = new FictionBook(SrcPath);
            }
            catch (Exception ex) {
                Debug.DebugMessage(
                    SrcPath, ex, "Дубликатор.CompareForm.MakeFB2IDHashTable(): Заполнение хеш таблицы данными о fb2-книгах в контексте их ID."
                    );
                _nonOpenedFileList = _compComm.collectBadFB2(!string.IsNullOrEmpty(ZipPath) ? ZipPath : SrcPath);
                return;
            }

            string Encoding = fb2.getEncoding();

            if (string.IsNullOrWhiteSpace(Encoding))
            {
                Encoding = "?";
            }
            string ID = fb2.DIID;

            if (string.IsNullOrEmpty(ID) || string.IsNullOrWhiteSpace(ID))
            {
                ID = _compComm.NoOrEmptyBookIDString;
            }

            // данные о книге
            BookData fb2BookData = new BookData(
                fb2.TIBookTitle, fb2.TIAuthors, fb2.TIGenres, fb2.TILang, ID, fb2.DIVersion, fb2.DIAuthors, SrcPath, Encoding
                );

            if (ZipPath != null)
            {
                fb2BookData.Path = ZipPath;
            }

            if (!htFB2ForID.ContainsKey(ID))
            {
                // такой книги в числе дублей еще нет
                FB2FilesDataInGroup fb2f = new FB2FilesDataInGroup(fb2BookData, ID);
                htFB2ForID.Add(ID, fb2f);
            }
            else
            {
                // такая книга в числе дублей уже есть
                FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)htFB2ForID[ID];
                fb2f.Add(fb2BookData);
                //htFB2ForID[sID] = fb2f; //ИЗБЫТОЧНЫЙ КОД
            }
        }
示例#6
0
        /// <summary>
        /// Формирование представления Групп с их книгами
        /// </summary>
        private void makeBookCopiesView(FB2FilesDataInGroup fb2BookList, ListView listViewFB2Files, ref StatusView sv)
        {
            Hashtable     htBookGroups = new Hashtable(new FB2CultureComparer()); // хеш-таблица групп одинаковых книг
            ListViewGroup lvGroup      = null;                                    // группа одинаковых книг
            string        Valid        = string.Empty;

            foreach (BookData bd in fb2BookList)
            {
                ++sv.AllFB2InGroups; // число книг во всех группах одинаковых книг
                lvGroup = new ListViewGroup(fb2BookList.Group);
                ListViewItem lvi = new ListViewItem(bd.Path);
                if (FilesWorker.isFB2Archive(bd.Path))
                {
                    lvi.ForeColor = Colors.ZipFB2ForeColor;
                }
                lvi.SubItems.Add(MakeBookTitleString(bd.BookTitle));
                lvi.SubItems.Add(MakeAuthorsString(bd.Authors));
                lvi.SubItems.Add(MakeGenresString(bd.Genres));
                lvi.SubItems.Add(bd.Lang);
                lvi.SubItems.Add(bd.Id);
                lvi.SubItems.Add(bd.Version);
                lvi.SubItems.Add(bd.Encoding);

                Valid = _fv2Validator.ValidatingFB2File(bd.Path);
                if (string.IsNullOrEmpty(Valid))
                {
                    Valid         = "Да";
                    lvi.ForeColor = FilesWorker.isFB2File(bd.Path) ? Color.FromName("WindowText") : Colors.ZipFB2ForeColor;
                }
                else
                {
                    Valid         = "Нет";
                    lvi.ForeColor = Colors.FB2NotValidForeColor;
                }

                lvi.SubItems.Add(Valid);
                lvi.SubItems.Add(GetFileLength(bd.Path));
                lvi.SubItems.Add(GetFileCreationTime(bd.Path));
                lvi.SubItems.Add(FileLastWriteTime(bd.Path));
                // заносим группу в хеш, если она там отсутствует
                AddBookGroupInHashTable(htBookGroups, lvGroup);
                // присваиваем группу книге
                listViewFB2Files.Groups.Add((ListViewGroup)htBookGroups[fb2BookList.Group]);
                lvi.Group = (ListViewGroup)htBookGroups[fb2BookList.Group];
                listViewFB2Files.Items.Add(lvi);
            }
        }
示例#7
0
        /// <summary>
        /// Удаление элементов таблицы, value (списки) которых состоят из 1-го элемента (это не копии)
        /// </summary>
        /// <param name="ht">Хеш Таблица, в которой производится удаление элементов по заданному алгоритму</param>
        public void removeNotCopiesEntryInHashTable(HashtableClass ht)
        {
            List <DictionaryEntry> notCopies = new List <DictionaryEntry>();

            foreach (DictionaryEntry entry in ht)
            {
                FB2FilesDataInGroup fb2f = (FB2FilesDataInGroup)entry.Value;
                if (fb2f.Count == 1)
                {
                    notCopies.Add(entry);
                }
            }
            foreach (var ent in notCopies)
            {
                ht.Remove(ent.Key);
            }
        }
示例#8
0
        /// <summary>
        /// Хэширование по одинаковым Авторам в пределах сгенерированных групп книг по одинаковым названиям
        /// </summary
        /// <param name="bw">Экземплар фонового обработчика класса BackgroundWorker</param>
        /// <param name="e">Экземпляр класса DoWorkEventArgs</param>
        /// <param name="htFB2ForBT">Заполненная хеш-таблица списками книг по критерию одинакового Названия книг</param>
        /// <param name="htBookTitleAuthors">Заполняемая хеш-таблица списками книг по критерию ( Название книги (Авторы) )</param>
        /// <param name="WithMiddleName">Учитывать ли отчество Авторов (true) или нет (false) при поиске</param>
        /// <returns>Признак непрерывности обработки файлов</returns>
        public bool FilesHashForAuthorsParser(BackgroundWorker bw, DoWorkEventArgs e,
                                              Label StatusLabel, ProgressBar ProgressBar,
                                              HashtableClass htFB2ForBT, HashtableClass htBookTitleAuthors,
                                              bool WithMiddleName)
        {
            StatusLabel.Text   += "Хеширование по Авторам книг...\r";
            ProgressBar.Maximum = htFB2ForBT.Values.Count;
            ProgressBar.Value   = 0;
            // генерация списка ключей хеш-таблицы (для удаления обработанного элемента таблицы)
            List <string> keyList = _compComm.makeSortedKeysForGroups(htFB2ForBT);
            // группировка книг по одинаковым Авторам в пределах сгенерированных Групп книг по одинаковым Названиям
            int i = 0;

            foreach (string key in keyList)
            {
                // разбивка на группы для одинакового Названия по Авторам
                Hashtable htGroupAuthors = FindDupForAuthors((FB2FilesDataInGroup)htFB2ForBT[key], WithMiddleName);
                foreach (FB2FilesDataInGroup fb2List in htGroupAuthors.Values)
                {
                    if (!htBookTitleAuthors.ContainsKey(fb2List.Group))
                    {
                        htBookTitleAuthors.Add(fb2List.Group, fb2List);
                    }
                    else
                    {
                        FB2FilesDataInGroup fb2ListInGroup = (FB2FilesDataInGroup)htBookTitleAuthors[fb2List.Group];
                        fb2ListInGroup.AddRange(fb2List);
                    }
                }

                // удаление обработанной группы книг, сгруппированных по одинаковому названию
                htFB2ForBT.Remove(key);
                bw.ReportProgress(++i);

                if (bw.CancellationPending)
                {
                    e.Cancel = true;
                    return(false);
                }
            }
            return(true);
        }
        /// <summary>
        /// Разбивка на группы для одинакового Id книги по Авторам
        /// </summary
        /// <param name="bw">Экземпляр фонового обработчика класса BackgroundWorker</param>
        /// <param name="e">Экземпляр класса DoWorkEventArgs</param>
        /// <param name="fb2Group">Экземпляр класса для хранения информации по одинаковым книгам в одной группе</param>
        private Hashtable FindDupForAuthorsID(FB2FilesDataInGroup fb2Group)
        {
            // в fb2Group.Group - название группы (название книги у всех книг одинаковое, а пути - разные )
            // внутри fb2Group в BookData - данные на каждую книгу группы
            Hashtable ht = new Hashtable(new FB2CultureComparer());

            // 2 итератора для перебора всех книг группы. 1-й - только на текущий элемент группы, 2-й - скользящий на все последующие. т.е. iter2 = iter1+1
            for (int iter1 = 0; iter1 != fb2Group.Count; ++iter1)
            {
                BookData            bd1         = fb2Group[iter1]; // текущая книга
                FB2FilesDataInGroup fb2NewGroup = new FB2FilesDataInGroup();
                // перебор всех книг в группе, за исключением текущей
                for (int iter2 = iter1 + 1; iter2 != fb2Group.Count; ++iter2)
                {
                    // сравнение текущей книги со всеми последующими
                    BookData bd2 = fb2Group[iter2];
                    // Проверка ID книги на наличие и/или пустоту
                    _compComm.VerifyBookID(bd1);
                    _compComm.VerifyBookID(bd2);
                    if (bd1.Id.ToLower().Equals(bd2.Id.ToLower()))
                    {
                        if (!fb2NewGroup.isBookExists(bd2.Path))
                        {
                            fb2NewGroup.Add(bd2);
                        }
                    }
                }
                if (fb2NewGroup.Count >= 1)
                {
                    // только для копий, а не для единичных книг
                    fb2NewGroup.Group = fb2Group.Group + " { " + bd1.Id.ToString() + " }";
                    fb2NewGroup.Insert(0, bd1);
                    if (!ht.ContainsKey(fb2NewGroup.Group))
                    {
                        ht.Add(fb2NewGroup.Group, fb2NewGroup);
                    }
                }
            }
            return(ht);
        }
        /// <summary>
        /// Хэширование fb2-файлов по ID книги в пределах одинаковых Авторов Книги
        /// 10. Автор(ы), Одинаковый Id Книги
        /// </summary
        /// <param name="bw">Экземплар фонового обработчика класса BackgroundWorker</param>
        /// <param name="e">Экземпляр класса DoWorkEventArgs</param>
        /// <param name="htAuthors">Хэш Таблица с книгами по критерию одинаковости их Авторов</param>
        /// <param name="htWorkingBook">Хэш Таблица с книгами по критерию одинаковости их ID</param>
        /// <returns>Признак непрерывности обработки файлов</returns>
        public bool FilesHashForAuthorsBookIDParser(ref BackgroundWorker bw, ref DoWorkEventArgs e,
                                                    Label StatusLabel, ProgressBar ProgressBar,
                                                    ref HashtableClass htBookTitleAuthors, ref HashtableClass htWorkingBook)
        {
            StatusLabel.Text   += "Хэширование по ID книги в пределах одинаковых Авторов...\r";
            ProgressBar.Maximum = htBookTitleAuthors.Count;
            ProgressBar.Value   = 0;
            // генерация списка ключей хеш-таблицы (для удаления обработанного элемента таблицы)
            List <string> keyList = _compComm.makeSortedKeysForGroups(htBookTitleAuthors);
            // группировка книг по одинаковым Id Книги в пределах сгенерированных Групп книг одинаковых Авторов
            int i = 0;

            foreach (string key in keyList)
            {
                // разбивка на группы для одинакового Id книги по Названию и по Авторам
                Hashtable AuthorsTitleBookID = FindDupForAuthorsID((FB2FilesDataInGroup)htBookTitleAuthors[key]);
                foreach (FB2FilesDataInGroup fb2List in AuthorsTitleBookID.Values)
                {
                    if (!htBookTitleAuthors.ContainsKey(fb2List.Group))
                    {
                        htWorkingBook.Add(fb2List.Group, fb2List);
                    }
                    else
                    {
                        FB2FilesDataInGroup fb2ListInGroup = (FB2FilesDataInGroup)htBookTitleAuthors[fb2List.Group];
                        fb2ListInGroup.AddRange(fb2List);
                    }
                }
                // удаление обработанной группы книг, сгруппированных по одинаковому Автору
                htBookTitleAuthors.Remove(key);
                bw.ReportProgress(++i);

                if (bw.CancellationPending)
                {
                    e.Cancel = true;
                    return(false);
                }
            }
            return(true);
        }
示例#11
0
        /// <summary>
        /// Cоздание групп копий по Авторам, относительно найденного Названия Книги
        /// </summary
        /// <param name="fb2Group">Экземпляр класса для хранения информации по одинаковым книгам в одной группе</param>
        /// <param name="WithMiddleName">Учитывать ли отчество Авторов (true) или нет (false) при поиске</param>
        private Hashtable FindDupForAuthors(FB2FilesDataInGroup fb2Group, bool WithMiddleName)
        {
            // в fb2Group.Group - название группы (название книги у всех книг одинаковое, а пути - разные )
            // внутри fb2Group в BookData - данные на каждую книгу группы
            Hashtable ht = new Hashtable(new FB2CultureComparer());

            // 2 итератора для перебора всех книг группы. 1-й - только на текущий элемент группы, 2-й - скользящий на все последующие. т.е. iter2 = iter1+1
            for (int iter1 = 0; iter1 != fb2Group.Count; ++iter1)
            {
                BookData            bd1         = fb2Group[iter1]; // текущая книга
                FB2FilesDataInGroup fb2NewGroup = new FB2FilesDataInGroup();
                // перебор всех книг в группе, за исключением текущей
                for (int iter2 = iter1 + 1; iter2 != fb2Group.Count; ++iter2)
                {
                    // сравнение текущей книги со всеми последующими
                    BookData bd2 = fb2Group[iter2];
                    if (bd1.isSameBook(bd2, WithMiddleName, false))
                    {
                        if (!fb2NewGroup.isBookExists(bd2.Path))
                        {
                            fb2NewGroup.Add(bd2);
                        }
                    }
                }
                if (fb2NewGroup.Count >= 1)
                {
                    // только для копий, а не для единичных книг
                    fb2NewGroup.Group = fb2Group.Group + " ( " + fb2NewGroup.makeAuthorsString(WithMiddleName, false) + " )";
                    fb2NewGroup.Insert(0, bd1);
                    if (!ht.ContainsKey(fb2NewGroup.Group))
                    {
                        ht.Add(fb2NewGroup.Group, fb2NewGroup);
                    }
                }
            }
            return(ht);
        }
示例#12
0
        /// <summary>
        /// Добавление Группы в Список Групп
        /// </summary>
        /// <param name="bw">BackgroundWorker</param>
        /// <param name="e">DoWorkEventArgs</param>
        /// <param name="doc">xml документ - объект класса XDocument, в который заносятся данные на книги Групп</param>
        /// <param name="fb2BookList">Список данных fb2 книг для конкретной Группы</param>
        /// <param name="BookInGroups">Число книг в Группе</param>
        /// <param name="GroupCountInGroups">Счетчик числа Групп</param>
        private void addAllBookInGroup(BackgroundWorker bw, DoWorkEventArgs e,
                                       XDocument doc, FB2FilesDataInGroup fb2BookList,
                                       ref int BookInGroups, ref int GroupCountInGroups,
                                       ref StatusView sv)
        {
            BookInGroups += fb2BookList.Count;

            // Добавление Группы в Список Групп
            XElement xeGroup = null;

            doc.Root.Element("Groups").Add(
                xeGroup = new XElement(
                    "Group", new XAttribute("number", 0),
                    new XAttribute("count", fb2BookList.Count),
                    new XAttribute("name", fb2BookList.Group)
                    )
                );

            int BookNumber       = 0;   // номер Книги (Book number) В Группе (Group)
            int BookCountInGroup = 0;   // число Книг (Group count) в Группе (Group)

            foreach (BookData bd in fb2BookList)
            {
                if (bw.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                ++sv.AllFB2InGroups; // число книг во всех группах одинаковых книг
                string sForeColor = "WindowText";
                if (FilesWorker.isFB2Archive(bd.Path))
                {
                    sForeColor = Colors.ZipFB2ForeColor.Name;
                }
                string Validation = _fv2Validator.ValidatingFB2File(bd.Path);
                if (string.IsNullOrEmpty(Validation))
                {
                    Validation = "Да";
                    sForeColor = FilesWorker.isFB2File(bd.Path) ? "WindowText" : Colors.ZipFB2ForeColor.Name;
                }
                else
                {
                    Validation = "Нет";
                    sForeColor = Colors.FB2NotValidForeColor.Name;
                }
                // Добавление Книги в Группу
                xeGroup.Add(
                    new XElement("Book", new XAttribute("number", ++BookNumber),
                                 new XElement("Group", fb2BookList.Group),
                                 new XElement("Path", bd.Path),
                                 new XElement("BookTitle", MakeBookTitleString(bd.BookTitle)),
                                 new XElement("Authors", MakeAuthorsString(bd.Authors)),
                                 new XElement("Genres", MakeGenresString(bd.Genres)),
                                 new XElement("BookLang", bd.Lang),
                                 new XElement("BookID", bd.Id),
                                 new XElement("Version", bd.Version),
                                 new XElement("FB2Authors", MakeAuthorsString(bd.FB2Authors)),
                                 new XElement("Encoding", bd.Encoding),
                                 new XElement("Validation", Validation),
                                 new XElement("FileLength", GetFileLength(bd.Path)),
                                 new XElement("FileCreationTime", GetFileCreationTime(bd.Path)),
                                 new XElement("FileLastWriteTime", FileLastWriteTime(bd.Path)),
                                 new XElement("ForeColor", sForeColor),
                                 new XElement("BackColor", "Window"),
                                 new XElement("IsChecked", false)
                                 )
                    );

                xeGroup.SetAttributeValue("count", ++BookCountInGroup);
                if (!xeGroup.HasElements)
                {
                    xeGroup.Remove();
                }
            } // по всем книгам Группы
            ++GroupCountInGroups;
        }