Files
Umbraco-CMS/src/Umbraco.Core/Services/EntityXmlSerializer.cs

220 lines
10 KiB
C#

using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Strings;
using umbraco.interfaces;
namespace Umbraco.Core.Services
{
//TODO: Move the rest of the logic for the PackageService.Export methods to here!
/// <summary>
/// A helper class to serialize entities to XML
/// </summary>
internal class EntityXmlSerializer
{
/// <summary>
/// Exports an <see cref="IContent"/> item to xml as an <see cref="XElement"/>
/// </summary>
/// <param name="contentService"></param>
/// <param name="dataTypeService"></param>
/// <param name="content">Content to export</param>
/// <param name="deep">Optional parameter indicating whether to include descendents</param>
/// <returns><see cref="XElement"/> containing the xml representation of the Content object</returns>
public XElement Serialize(IContentService contentService, IDataTypeService dataTypeService, IContent content, bool deep = false)
{
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : content.ContentType.Alias.ToSafeAliasWithForcingCheck();
var xml = Serialize(dataTypeService, content, nodeName);
xml.Add(new XAttribute("nodeType", content.ContentType.Id));
xml.Add(new XAttribute("creatorName", content.GetCreatorProfile().Name));
xml.Add(new XAttribute("writerName", content.GetWriterProfile().Name));
xml.Add(new XAttribute("writerID", content.WriterId));
xml.Add(new XAttribute("template", content.Template == null ? "0" : content.Template.Id.ToString(CultureInfo.InvariantCulture)));
xml.Add(new XAttribute("nodeTypeAlias", content.ContentType.Alias));
if (deep)
{
var descendants = contentService.GetDescendants(content).ToArray();
var currentChildren = descendants.Where(x => x.ParentId == content.Id);
AddChildXml(contentService, dataTypeService, descendants, currentChildren, xml);
}
return xml;
}
/// <summary>
/// Exports an <see cref="IMedia"/> item to xml as an <see cref="XElement"/>
/// </summary>
/// <param name="mediaService"></param>
/// <param name="dataTypeService"></param>
/// <param name="media">Media to export</param>
/// <param name="deep">Optional parameter indicating whether to include descendents</param>
/// <returns><see cref="XElement"/> containing the xml representation of the Media object</returns>
public XElement Serialize(IMediaService mediaService, IDataTypeService dataTypeService, IMedia media, bool deep = false)
{
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : media.ContentType.Alias.ToSafeAliasWithForcingCheck();
var xml = Serialize(dataTypeService, media, nodeName);
xml.Add(new XAttribute("nodeType", media.ContentType.Id));
xml.Add(new XAttribute("writerName", media.GetCreatorProfile().Name));
xml.Add(new XAttribute("writerID", media.CreatorId));
xml.Add(new XAttribute("version", media.Version));
xml.Add(new XAttribute("template", 0));
xml.Add(new XAttribute("nodeTypeAlias", media.ContentType.Alias));
if (deep)
{
var descendants = mediaService.GetDescendants(media).ToArray();
var currentChildren = descendants.Where(x => x.ParentId == media.Id);
AddChildXml(mediaService, dataTypeService, descendants, currentChildren, xml);
}
return xml;
}
/// <summary>
/// Exports an <see cref="IMedia"/> item to xml as an <see cref="XElement"/>
/// </summary>
/// <param name="dataTypeService"></param>
/// <param name="member">Member to export</param>
/// <returns><see cref="XElement"/> containing the xml representation of the Member object</returns>
public XElement Serialize(IDataTypeService dataTypeService, IMember member)
{
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : member.ContentType.Alias.ToSafeAliasWithForcingCheck();
var xml = Serialize(dataTypeService, member, nodeName);
xml.Add(new XAttribute("nodeType", member.ContentType.Id));
xml.Add(new XAttribute("nodeTypeAlias", member.ContentType.Alias));
xml.Add(new XAttribute("loginName", member.Username));
xml.Add(new XAttribute("email", member.Email));
xml.Add(new XAttribute("key", member.Key));
return xml;
}
public XElement Serialize(IDataTypeService dataTypeService, Property property)
{
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "data" : property.Alias.ToSafeAlias();
var xd = new XmlDocument();
var xmlNode = xd.CreateNode(XmlNodeType.Element, nodeName, "");
//Add the property alias to the legacy schema
if (UmbracoSettings.UseLegacyXmlSchema)
{
var alias = xd.CreateAttribute("alias");
alias.Value = property.Alias.ToSafeAlias();
xmlNode.Attributes.Append(alias);
}
//This seems to fail during testing
//SD: With the new null checks below, this shouldn't fail anymore.
var dt = property.PropertyType.DataType(property.Id, dataTypeService);
if (dt != null && dt.Data != null)
{
//We've already got the value for the property so we're going to give it to the
// data type's data property so it doesn't go re-look up the value from the db again.
var defaultData = dt.Data as IDataValueSetter;
if (defaultData != null)
{
defaultData.SetValue(property.Value, property.PropertyType.DataTypeDatabaseType.ToString());
}
xmlNode.AppendChild(dt.Data.ToXMl(xd));
}
var element = xmlNode.GetXElement();
return element;
}
/// <summary>
/// Used by Media Export to recursively add children
/// </summary>
/// <param name="mediaService"></param>
/// <param name="dataTypeService"></param>
/// <param name="originalDescendants"></param>
/// <param name="currentChildren"></param>
/// <param name="currentXml"></param>
private void AddChildXml(IMediaService mediaService, IDataTypeService dataTypeService, IMedia[] originalDescendants, IEnumerable<IMedia> currentChildren, XElement currentXml)
{
foreach (var child in currentChildren)
{
//add the child's xml
var childXml = Serialize(mediaService, dataTypeService, child);
currentXml.Add(childXml);
//copy local (out of closure)
var c = child;
//get this item's children
var children = originalDescendants.Where(x => x.ParentId == c.Id);
//recurse and add it's children to the child xml element
AddChildXml(mediaService, dataTypeService, originalDescendants, children, childXml);
}
}
/// <summary>
/// Part of the export of IContent and IMedia and IMember which is shared
/// </summary>
/// <param name="dataTypeService"></param>
/// <param name="contentBase">Base Content or Media to export</param>
/// <param name="nodeName">Name of the node</param>
/// <returns><see cref="XElement"/></returns>
private XElement Serialize(IDataTypeService dataTypeService, IContentBase contentBase, string nodeName)
{
//NOTE: that one will take care of umbracoUrlName
var url = contentBase.GetUrlSegment();
var xml = new XElement(nodeName,
new XAttribute("id", contentBase.Id),
new XAttribute("parentID", contentBase.Level > 1 ? contentBase.ParentId : -1),
new XAttribute("level", contentBase.Level),
new XAttribute("creatorID", contentBase.CreatorId),
new XAttribute("sortOrder", contentBase.SortOrder),
new XAttribute("createDate", contentBase.CreateDate.ToString("s")),
new XAttribute("updateDate", contentBase.UpdateDate.ToString("s")),
new XAttribute("nodeName", contentBase.Name),
new XAttribute("urlName", url),
new XAttribute("path", contentBase.Path),
new XAttribute("isDoc", ""));
foreach (var property in contentBase.Properties.Where(p => p != null && p.Value != null && p.Value.ToString().IsNullOrWhiteSpace() == false))
{
xml.Add(Serialize(dataTypeService, property));
}
return xml;
}
/// <summary>
/// Used by Content Export to recursively add children
/// </summary>
/// <param name="contentService"></param>
/// <param name="dataTypeService"></param>
/// <param name="originalDescendants"></param>
/// <param name="currentChildren"></param>
/// <param name="currentXml"></param>
private void AddChildXml(IContentService contentService, IDataTypeService dataTypeService, IContent[] originalDescendants, IEnumerable<IContent> currentChildren, XElement currentXml)
{
foreach (var child in currentChildren)
{
//add the child's xml
var childXml = Serialize(contentService, dataTypeService, child);
currentXml.Add(childXml);
//copy local (out of closure)
var c = child;
//get this item's children
var children = originalDescendants.Where(x => x.ParentId == c.Id);
//recurse and add it's children to the child xml element
AddChildXml(contentService, dataTypeService, originalDescendants, children, childXml);
}
}
}
}