BaseXmlSaver.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Security;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Xml;
  10. using MediaBrowser.Common.Extensions;
  11. using MediaBrowser.Controller.Configuration;
  12. using MediaBrowser.Controller.Entities;
  13. using MediaBrowser.Controller.Entities.Audio;
  14. using MediaBrowser.Controller.Entities.Movies;
  15. using MediaBrowser.Controller.Entities.TV;
  16. using MediaBrowser.Controller.Library;
  17. using MediaBrowser.Controller.Persistence;
  18. using MediaBrowser.Controller.Playlists;
  19. using MediaBrowser.Model.Configuration;
  20. using MediaBrowser.Model.Entities;
  21. using MediaBrowser.Model.Extensions;
  22. using MediaBrowser.Model.IO;
  23. using MediaBrowser.Model.Logging;
  24. using MediaBrowser.Model.Xml;
  25. namespace MediaBrowser.LocalMetadata.Savers
  26. {
  27. public abstract class BaseXmlSaver : IMetadataFileSaver
  28. {
  29. private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
  30. private static readonly Dictionary<string, string> CommonTags = new[] {
  31. "Added",
  32. "AspectRatio",
  33. "AudioDbAlbumId",
  34. "AudioDbArtistId",
  35. "AwardSummary",
  36. "BirthDate",
  37. "Budget",
  38. // Deprecated. No longer saving in this field.
  39. "certification",
  40. "Chapters",
  41. "ContentRating",
  42. "Countries",
  43. "CustomRating",
  44. "CriticRating",
  45. "CriticRatingSummary",
  46. "DeathDate",
  47. "DisplayOrder",
  48. "EndDate",
  49. "Genres",
  50. "Genre",
  51. "GamesDbId",
  52. // Deprecated. No longer saving in this field.
  53. "IMDB_ID",
  54. "IMDB",
  55. // Deprecated. No longer saving in this field.
  56. "IMDbId",
  57. "Language",
  58. "LocalTitle",
  59. "OriginalTitle",
  60. "LockData",
  61. "LockedFields",
  62. "Format3D",
  63. "Metascore",
  64. // Deprecated. No longer saving in this field.
  65. "MPAARating",
  66. "MPAADescription",
  67. "MusicBrainzArtistId",
  68. "MusicBrainzAlbumArtistId",
  69. "MusicBrainzAlbumId",
  70. "MusicBrainzReleaseGroupId",
  71. // Deprecated. No longer saving in this field.
  72. "MusicbrainzId",
  73. "Overview",
  74. "ShortOverview",
  75. "Persons",
  76. "PlotKeywords",
  77. "PremiereDate",
  78. "ProductionYear",
  79. "Rating",
  80. "Revenue",
  81. "RottenTomatoesId",
  82. "RunningTime",
  83. // Deprecated. No longer saving in this field.
  84. "Runtime",
  85. "SortTitle",
  86. "Studios",
  87. "Tags",
  88. // Deprecated. No longer saving in this field.
  89. "TagLine",
  90. "Taglines",
  91. "TMDbCollectionId",
  92. "TMDbId",
  93. // Deprecated. No longer saving in this field.
  94. "Trailer",
  95. "Trailers",
  96. "TVcomId",
  97. "TvDbId",
  98. "Type",
  99. "TVRageId",
  100. "VoteCount",
  101. "Website",
  102. "Zap2ItId",
  103. "CollectionItems",
  104. "PlaylistItems",
  105. "Shares"
  106. }.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
  107. public BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory)
  108. {
  109. FileSystem = fileSystem;
  110. ConfigurationManager = configurationManager;
  111. LibraryManager = libraryManager;
  112. UserManager = userManager;
  113. UserDataManager = userDataManager;
  114. Logger = logger;
  115. XmlReaderSettingsFactory = xmlReaderSettingsFactory;
  116. }
  117. protected IFileSystem FileSystem { get; private set; }
  118. protected IServerConfigurationManager ConfigurationManager { get; private set; }
  119. protected ILibraryManager LibraryManager { get; private set; }
  120. protected IUserManager UserManager { get; private set; }
  121. protected IUserDataManager UserDataManager { get; private set; }
  122. protected ILogger Logger { get; private set; }
  123. protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; }
  124. protected ItemUpdateType MinimumUpdateType
  125. {
  126. get
  127. {
  128. return ItemUpdateType.MetadataDownload;
  129. }
  130. }
  131. public string Name
  132. {
  133. get
  134. {
  135. return XmlProviderUtils.Name;
  136. }
  137. }
  138. public string GetSavePath(IHasMetadata item)
  139. {
  140. return GetLocalSavePath(item);
  141. }
  142. /// <summary>
  143. /// Gets the save path.
  144. /// </summary>
  145. /// <param name="item">The item.</param>
  146. /// <returns>System.String.</returns>
  147. protected abstract string GetLocalSavePath(IHasMetadata item);
  148. /// <summary>
  149. /// Gets the name of the root element.
  150. /// </summary>
  151. /// <param name="item">The item.</param>
  152. /// <returns>System.String.</returns>
  153. protected virtual string GetRootElementName(IHasMetadata item)
  154. {
  155. return "Item";
  156. }
  157. /// <summary>
  158. /// Determines whether [is enabled for] [the specified item].
  159. /// </summary>
  160. /// <param name="item">The item.</param>
  161. /// <param name="updateType">Type of the update.</param>
  162. /// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns>
  163. public abstract bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType);
  164. protected virtual List<string> GetTagsUsed()
  165. {
  166. return new List<string>();
  167. }
  168. public void Save(IHasMetadata item, CancellationToken cancellationToken)
  169. {
  170. var path = GetSavePath(item);
  171. using (var memoryStream = new MemoryStream())
  172. {
  173. Save(item, memoryStream, path);
  174. memoryStream.Position = 0;
  175. cancellationToken.ThrowIfCancellationRequested();
  176. SaveToFile(memoryStream, path);
  177. }
  178. }
  179. private void SaveToFile(Stream stream, string path)
  180. {
  181. FileSystem.CreateDirectory(Path.GetDirectoryName(path));
  182. var file = FileSystem.GetFileInfo(path);
  183. var wasHidden = false;
  184. // This will fail if the file is hidden
  185. if (file.Exists)
  186. {
  187. if (file.IsHidden)
  188. {
  189. FileSystem.SetHidden(path, false);
  190. wasHidden = true;
  191. }
  192. }
  193. using (var filestream = FileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
  194. {
  195. stream.CopyTo(filestream);
  196. }
  197. if (wasHidden || ConfigurationManager.Configuration.SaveMetadataHidden)
  198. {
  199. FileSystem.SetHidden(path, true);
  200. }
  201. }
  202. private void Save(IHasMetadata item, Stream stream, string xmlPath)
  203. {
  204. var settings = new XmlWriterSettings
  205. {
  206. Indent = true,
  207. Encoding = Encoding.UTF8,
  208. CloseOutput = false
  209. };
  210. using (XmlWriter writer = XmlWriter.Create(stream, settings))
  211. {
  212. var root = GetRootElementName(item);
  213. writer.WriteStartDocument(true);
  214. writer.WriteStartElement(root);
  215. var baseItem = item as BaseItem;
  216. if (baseItem != null)
  217. {
  218. AddCommonNodes(baseItem, writer, LibraryManager, UserManager, UserDataManager, FileSystem, ConfigurationManager);
  219. }
  220. WriteCustomElements(item, writer);
  221. var tagsUsed = GetTagsUsed();
  222. try
  223. {
  224. AddCustomTags(xmlPath, tagsUsed, writer, Logger, FileSystem);
  225. }
  226. catch (FileNotFoundException)
  227. {
  228. }
  229. catch (IOException)
  230. {
  231. }
  232. catch (XmlException ex)
  233. {
  234. Logger.ErrorException("Error reading existng xml", ex);
  235. }
  236. writer.WriteEndElement();
  237. writer.WriteEndDocument();
  238. }
  239. }
  240. protected abstract void WriteCustomElements(IHasMetadata item, XmlWriter writer);
  241. public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss";
  242. /// <summary>
  243. /// Adds the common nodes.
  244. /// </summary>
  245. /// <returns>Task.</returns>
  246. public static void AddCommonNodes(BaseItem item, XmlWriter writer, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataRepo, IFileSystem fileSystem, IServerConfigurationManager config)
  247. {
  248. var writtenProviderIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
  249. if (!string.IsNullOrEmpty(item.OfficialRating))
  250. {
  251. writer.WriteElementString("ContentRating", item.OfficialRating);
  252. }
  253. if (!string.IsNullOrEmpty(item.OfficialRatingDescription))
  254. {
  255. writer.WriteElementString("MPAADescription", item.OfficialRatingDescription);
  256. }
  257. writer.WriteElementString("Added", item.DateCreated.ToLocalTime().ToString("G"));
  258. writer.WriteElementString("LockData", item.IsLocked.ToString().ToLower());
  259. if (item.LockedFields.Count > 0)
  260. {
  261. writer.WriteElementString("LockedFields", string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()));
  262. }
  263. if (!string.IsNullOrEmpty(item.DisplayMediaType))
  264. {
  265. writer.WriteElementString("Type", item.DisplayMediaType);
  266. }
  267. if (item.CriticRating.HasValue)
  268. {
  269. writer.WriteElementString("CriticRating", item.CriticRating.Value.ToString(UsCulture));
  270. }
  271. if (!string.IsNullOrEmpty(item.CriticRatingSummary))
  272. {
  273. writer.WriteElementString("CriticRatingSummary", item.CriticRatingSummary);
  274. }
  275. if (!string.IsNullOrEmpty(item.Overview))
  276. {
  277. writer.WriteElementString("Overview", item.Overview);
  278. }
  279. if (!string.IsNullOrEmpty(item.OriginalTitle))
  280. {
  281. writer.WriteElementString("OriginalTitle", item.OriginalTitle);
  282. }
  283. if (!string.IsNullOrEmpty(item.ShortOverview))
  284. {
  285. writer.WriteElementString("ShortOverview", item.ShortOverview);
  286. }
  287. if (!string.IsNullOrEmpty(item.CustomRating))
  288. {
  289. writer.WriteElementString("CustomRating", item.CustomRating);
  290. }
  291. if (!string.IsNullOrEmpty(item.Name) && !(item is Episode))
  292. {
  293. writer.WriteElementString("LocalTitle", item.Name);
  294. }
  295. if (!string.IsNullOrEmpty(item.ForcedSortName))
  296. {
  297. writer.WriteElementString("SortTitle", item.ForcedSortName);
  298. }
  299. if (item.PremiereDate.HasValue)
  300. {
  301. if (item is Person)
  302. {
  303. writer.WriteElementString("BirthDate", item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd"));
  304. }
  305. else if (!(item is Episode))
  306. {
  307. writer.WriteElementString("PremiereDate", item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd"));
  308. }
  309. }
  310. if (item.EndDate.HasValue)
  311. {
  312. if (item is Person)
  313. {
  314. writer.WriteElementString("DeathDate", item.EndDate.Value.ToLocalTime().ToString("yyyy-MM-dd"));
  315. }
  316. else if (!(item is Episode))
  317. {
  318. writer.WriteElementString("EndDate", item.EndDate.Value.ToLocalTime().ToString("yyyy-MM-dd"));
  319. }
  320. }
  321. var hasTrailers = item as IHasTrailers;
  322. if (hasTrailers != null)
  323. {
  324. if (hasTrailers.RemoteTrailers.Count > 0)
  325. {
  326. writer.WriteStartElement("Trailers");
  327. foreach (var trailer in hasTrailers.RemoteTrailers)
  328. {
  329. writer.WriteElementString("Trailer", trailer.Url);
  330. }
  331. writer.WriteEndElement();
  332. }
  333. }
  334. //if (hasProductionLocations.ProductionLocations.Count > 0)
  335. //{
  336. // builder.Append("<Countries>");
  337. // foreach (var name in hasProductionLocations.ProductionLocations)
  338. // {
  339. // builder.Append("<Country>" + SecurityElement.Escape(name) + "</Country>");
  340. // }
  341. // builder.Append("</Countries>");
  342. //}
  343. var hasDisplayOrder = item as IHasDisplayOrder;
  344. if (hasDisplayOrder != null && !string.IsNullOrEmpty(hasDisplayOrder.DisplayOrder))
  345. {
  346. writer.WriteElementString("DisplayOrder", hasDisplayOrder.DisplayOrder);
  347. }
  348. //var hasMetascore = item as IHasMetascore;
  349. //if (hasMetascore != null && hasMetascore.Metascore.HasValue)
  350. //{
  351. // builder.Append("<Metascore>" + SecurityElement.Escape(hasMetascore.Metascore.Value.ToString(UsCulture)) + "</Metascore>");
  352. //}
  353. //var hasAwards = item as IHasAwards;
  354. //if (hasAwards != null && !string.IsNullOrEmpty(hasAwards.AwardSummary))
  355. //{
  356. // builder.Append("<AwardSummary>" + SecurityElement.Escape(hasAwards.AwardSummary) + "</AwardSummary>");
  357. //}
  358. var hasBudget = item as IHasBudget;
  359. if (hasBudget != null)
  360. {
  361. if (hasBudget.Budget.HasValue)
  362. {
  363. writer.WriteElementString("Budget", hasBudget.Budget.Value.ToString(UsCulture));
  364. }
  365. if (hasBudget.Revenue.HasValue)
  366. {
  367. writer.WriteElementString("Revenue", hasBudget.Revenue.Value.ToString(UsCulture));
  368. }
  369. }
  370. //if (item.CommunityRating.HasValue)
  371. //{
  372. // builder.Append("<Rating>" + SecurityElement.Escape(item.CommunityRating.Value.ToString(UsCulture)) + "</Rating>");
  373. //}
  374. //if (item.VoteCount.HasValue)
  375. //{
  376. // builder.Append("<VoteCount>" + SecurityElement.Escape(item.VoteCount.Value.ToString(UsCulture)) + "</VoteCount>");
  377. //}
  378. if (item.ProductionYear.HasValue && !(item is Person))
  379. {
  380. writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(UsCulture));
  381. }
  382. if (!string.IsNullOrEmpty(item.HomePageUrl))
  383. {
  384. writer.WriteElementString("Website", item.HomePageUrl);
  385. }
  386. //var hasAspectRatio = item as IHasAspectRatio;
  387. //if (hasAspectRatio != null)
  388. //{
  389. // if (!string.IsNullOrEmpty(hasAspectRatio.AspectRatio))
  390. // {
  391. // builder.Append("<AspectRatio>" + SecurityElement.Escape(hasAspectRatio.AspectRatio) + "</AspectRatio>");
  392. // }
  393. //}
  394. //if (!string.IsNullOrEmpty(item.PreferredMetadataLanguage))
  395. //{
  396. // builder.Append("<Language>" + SecurityElement.Escape(item.PreferredMetadataLanguage) + "</Language>");
  397. //}
  398. //if (!string.IsNullOrEmpty(item.PreferredMetadataCountryCode))
  399. //{
  400. // builder.Append("<CountryCode>" + SecurityElement.Escape(item.PreferredMetadataCountryCode) + "</CountryCode>");
  401. //}
  402. //// Use original runtime here, actual file runtime later in MediaInfo
  403. //var runTimeTicks = item.RunTimeTicks;
  404. //if (runTimeTicks.HasValue)
  405. //{
  406. // var timespan = TimeSpan.FromTicks(runTimeTicks.Value);
  407. // builder.Append("<RunningTime>" + Convert.ToInt32(timespan.TotalMinutes).ToString(UsCulture) + "</RunningTime>");
  408. //}
  409. //if (item.ProviderIds != null)
  410. //{
  411. // foreach (var providerKey in item.ProviderIds.Keys)
  412. // {
  413. // var providerId = item.ProviderIds[providerKey];
  414. // if (!string.IsNullOrEmpty(providerId))
  415. // {
  416. // builder.Append(string.Format("<{0}>{1}</{0}>", providerKey + "Id", SecurityElement.Escape(providerId)));
  417. // }
  418. // }
  419. //}
  420. //if (!string.IsNullOrWhiteSpace(item.Tagline))
  421. //{
  422. // builder.Append("<Taglines>");
  423. // builder.Append("<Tagline>" + SecurityElement.Escape(item.Tagline) + "</Tagline>");
  424. // builder.Append("</Taglines>");
  425. //}
  426. //if (item.Genres.Count > 0)
  427. //{
  428. // builder.Append("<Genres>");
  429. // foreach (var genre in item.Genres)
  430. // {
  431. // builder.Append("<Genre>" + SecurityElement.Escape(genre) + "</Genre>");
  432. // }
  433. // builder.Append("</Genres>");
  434. //}
  435. //if (item.Studios.Count > 0)
  436. //{
  437. // builder.Append("<Studios>");
  438. // foreach (var studio in item.Studios)
  439. // {
  440. // builder.Append("<Studio>" + SecurityElement.Escape(studio) + "</Studio>");
  441. // }
  442. // builder.Append("</Studios>");
  443. //}
  444. if (item.Tags.Count > 0)
  445. {
  446. writer.WriteStartElement("Tags");
  447. foreach (var tag in item.Tags)
  448. {
  449. writer.WriteElementString("Tag", tag);
  450. }
  451. writer.WriteEndElement();
  452. }
  453. if (item.Keywords.Count > 0)
  454. {
  455. writer.WriteStartElement("PlotKeywords");
  456. foreach (var tag in item.Keywords)
  457. {
  458. writer.WriteElementString("PlotKeyword", tag);
  459. }
  460. writer.WriteEndElement();
  461. }
  462. //var people = libraryManager.GetPeople(item);
  463. //if (people.Count > 0)
  464. //{
  465. // builder.Append("<Persons>");
  466. // foreach (var person in people)
  467. // {
  468. // builder.Append("<Person>");
  469. // builder.Append("<Name>" + SecurityElement.Escape(person.Name) + "</Name>");
  470. // builder.Append("<Type>" + SecurityElement.Escape(person.Type) + "</Type>");
  471. // builder.Append("<Role>" + SecurityElement.Escape(person.Role) + "</Role>");
  472. // if (person.SortOrder.HasValue)
  473. // {
  474. // builder.Append("<SortOrder>" + SecurityElement.Escape(person.SortOrder.Value.ToString(UsCulture)) + "</SortOrder>");
  475. // }
  476. // builder.Append("</Person>");
  477. // }
  478. // builder.Append("</Persons>");
  479. //}
  480. var boxset = item as BoxSet;
  481. if (boxset != null)
  482. {
  483. AddLinkedChildren(boxset, writer, "CollectionItems", "CollectionItem");
  484. }
  485. var playlist = item as Playlist;
  486. if (playlist != null)
  487. {
  488. AddLinkedChildren(playlist, writer, "PlaylistItems", "PlaylistItem");
  489. }
  490. var hasShares = item as IHasShares;
  491. if (hasShares != null)
  492. {
  493. AddShares(hasShares, writer);
  494. }
  495. AddMediaInfo(item, writer);
  496. }
  497. public static void AddShares(IHasShares item, XmlWriter writer)
  498. {
  499. writer.WriteStartElement("Shares");
  500. foreach (var share in item.Shares)
  501. {
  502. writer.WriteStartElement("Share");
  503. writer.WriteElementString("UserId", share.UserId);
  504. writer.WriteElementString("CanEdit", share.CanEdit.ToString().ToLower());
  505. writer.WriteEndElement();
  506. }
  507. writer.WriteEndElement();
  508. }
  509. /// <summary>
  510. /// Appends the media info.
  511. /// </summary>
  512. /// <typeparam name="T"></typeparam>
  513. public static void AddMediaInfo<T>(T item, XmlWriter writer)
  514. where T : BaseItem
  515. {
  516. var video = item as Video;
  517. if (video != null)
  518. {
  519. if (video.Video3DFormat.HasValue)
  520. {
  521. switch (video.Video3DFormat.Value)
  522. {
  523. case Video3DFormat.FullSideBySide:
  524. writer.WriteElementString("Format3D", "FSBS");
  525. break;
  526. case Video3DFormat.FullTopAndBottom:
  527. writer.WriteElementString("Format3D", "FTAB");
  528. break;
  529. case Video3DFormat.HalfSideBySide:
  530. writer.WriteElementString("Format3D", "HSBS");
  531. break;
  532. case Video3DFormat.HalfTopAndBottom:
  533. writer.WriteElementString("Format3D", "HTAB");
  534. break;
  535. case Video3DFormat.MVC:
  536. writer.WriteElementString("Format3D", "MVC");
  537. break;
  538. }
  539. }
  540. }
  541. }
  542. public static void AddLinkedChildren(Folder item, XmlWriter writer, string pluralNodeName, string singularNodeName)
  543. {
  544. var items = item.LinkedChildren
  545. .Where(i => i.Type == LinkedChildType.Manual)
  546. .ToList();
  547. if (items.Count == 0)
  548. {
  549. return;
  550. }
  551. writer.WriteStartElement(pluralNodeName);
  552. foreach (var link in items)
  553. {
  554. if (!string.IsNullOrWhiteSpace(link.Path))
  555. {
  556. writer.WriteStartElement(singularNodeName);
  557. writer.WriteElementString("Path", link.Path);
  558. writer.WriteEndElement();
  559. }
  560. }
  561. writer.WriteEndElement();
  562. }
  563. private static bool IsPersonType(PersonInfo person, string type)
  564. {
  565. return string.Equals(person.Type, type, StringComparison.OrdinalIgnoreCase) || string.Equals(person.Role, type, StringComparison.OrdinalIgnoreCase);
  566. }
  567. private void AddCustomTags(string path, List<string> xmlTagsUsed, XmlWriter writer, ILogger logger, IFileSystem fileSystem)
  568. {
  569. var settings = XmlReaderSettingsFactory.Create(false);
  570. settings.CheckCharacters = false;
  571. settings.IgnoreProcessingInstructions = true;
  572. settings.IgnoreComments = true;
  573. using (var fileStream = fileSystem.OpenRead(path))
  574. {
  575. using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
  576. {
  577. // Use XmlReader for best performance
  578. using (var reader = XmlReader.Create(streamReader, settings))
  579. {
  580. try
  581. {
  582. reader.MoveToContent();
  583. }
  584. catch (Exception ex)
  585. {
  586. logger.ErrorException("Error reading existing xml tags from {0}.", ex, path);
  587. return;
  588. }
  589. // Loop through each element
  590. while (reader.Read())
  591. {
  592. if (reader.NodeType == XmlNodeType.Element)
  593. {
  594. var name = reader.Name;
  595. if (!CommonTags.ContainsKey(name) && !xmlTagsUsed.Contains(name, StringComparer.OrdinalIgnoreCase))
  596. {
  597. writer.WriteNode(reader, false);
  598. }
  599. else
  600. {
  601. reader.Skip();
  602. }
  603. }
  604. }
  605. }
  606. }
  607. }
  608. }
  609. }
  610. }