XmlWriterHelper.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // ******************************************************************
  2. // Copyright (c) Microsoft. All rights reserved.
  3. // This code is licensed under the MIT License (MIT).
  4. // THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  5. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  6. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  7. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  8. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  9. // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
  10. // THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
  11. // ******************************************************************
  12. using System;
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Reflection;
  17. #if WINDOWS_UWP
  18. #endif
  19. namespace Microsoft.Toolkit.Uwp.Notifications
  20. {
  21. internal static class XmlWriterHelper
  22. {
  23. public static void Write(System.Xml.XmlWriter writer, object element)
  24. {
  25. NotificationXmlElementAttribute elAttr = GetElementAttribute(element.GetType());
  26. // If it isn't an element attribute, don't write anything
  27. if (elAttr == null)
  28. {
  29. return;
  30. }
  31. writer.WriteStartElement(elAttr.Name);
  32. IEnumerable<PropertyInfo> properties = GetProperties(element.GetType());
  33. List<object> elements = new List<object>();
  34. object content = null;
  35. // Write the attributes first
  36. foreach (PropertyInfo p in properties)
  37. {
  38. IEnumerable<Attribute> attributes = GetCustomAttributes(p);
  39. NotificationXmlAttributeAttribute attr = attributes.OfType<NotificationXmlAttributeAttribute>().FirstOrDefault();
  40. object propertyValue = GetPropertyValue(p, element);
  41. // If it's an attribute
  42. if (attr != null)
  43. {
  44. object defaultValue = attr.DefaultValue;
  45. // If the value is not the default value (and it's not null) we'll write it
  46. if (!object.Equals(propertyValue, defaultValue) && propertyValue != null)
  47. {
  48. writer.WriteAttributeString(attr.Name, PropertyValueToString(propertyValue));
  49. }
  50. }
  51. // If it's a content attribute
  52. else if (attributes.OfType<NotificationXmlContentAttribute>().Any())
  53. {
  54. content = propertyValue;
  55. }
  56. // Otherwise it's an element or collection of elements
  57. else
  58. {
  59. if (propertyValue != null)
  60. {
  61. elements.Add(propertyValue);
  62. }
  63. }
  64. }
  65. // Then write children
  66. foreach (object el in elements)
  67. {
  68. // If it's a collection of children
  69. if (el is IEnumerable)
  70. {
  71. foreach (object child in el as IEnumerable)
  72. {
  73. Write(writer, child);
  74. }
  75. continue;
  76. }
  77. // Otherwise just write the single element
  78. Write(writer, el);
  79. }
  80. // Then write any content if there is content
  81. if (content != null)
  82. {
  83. string contentString = content.ToString();
  84. if (!string.IsNullOrWhiteSpace(contentString))
  85. {
  86. writer.WriteString(contentString);
  87. }
  88. }
  89. writer.WriteEndElement();
  90. }
  91. private static object GetPropertyValue(PropertyInfo propertyInfo, object obj)
  92. {
  93. #if NETFX_CORE
  94. return propertyInfo.GetValue(obj);
  95. #else
  96. return propertyInfo.GetValue(obj, null);
  97. #endif
  98. }
  99. private static string PropertyValueToString(object propertyValue)
  100. {
  101. Type type = propertyValue.GetType();
  102. if (IsEnum(type))
  103. {
  104. EnumStringAttribute enumStringAttr = GetEnumStringAttribute(propertyValue as Enum);
  105. if (enumStringAttr != null)
  106. {
  107. return enumStringAttr.String;
  108. }
  109. }
  110. else if (propertyValue is bool)
  111. {
  112. if ((bool)propertyValue)
  113. {
  114. return "true";
  115. }
  116. return "false";
  117. }
  118. else if (propertyValue is DateTimeOffset?)
  119. {
  120. DateTimeOffset? dateTime = propertyValue as DateTimeOffset?;
  121. if (dateTime.HasValue)
  122. {
  123. // ISO 8601 format
  124. return System.Xml.XmlConvert.ToString(dateTime.Value);
  125. }
  126. else
  127. {
  128. return null;
  129. }
  130. }
  131. return propertyValue.ToString();
  132. }
  133. private static EnumStringAttribute GetEnumStringAttribute(Enum enumValue)
  134. {
  135. #if NETFX_CORE
  136. return enumValue.GetType().GetTypeInfo().GetDeclaredField(enumValue.ToString()).GetCustomAttribute<EnumStringAttribute>();
  137. #else
  138. MemberInfo[] memberInfo = enumValue.GetType().GetMember(enumValue.ToString());
  139. if (memberInfo != null && memberInfo.Length > 0)
  140. {
  141. object[] attrs = memberInfo[0].GetCustomAttributes(typeof(EnumStringAttribute), false);
  142. if (attrs != null && attrs.Length > 0)
  143. return attrs[0] as EnumStringAttribute;
  144. }
  145. return null;
  146. #endif
  147. }
  148. private static bool IsEnum(Type type)
  149. {
  150. #if NETFX_CORE
  151. return type.GetTypeInfo().IsEnum;
  152. #else
  153. return type.IsEnum;
  154. #endif
  155. }
  156. private static IEnumerable<PropertyInfo> GetProperties(Type type)
  157. {
  158. #if NETFX_CORE
  159. return type.GetTypeInfo().DeclaredProperties;
  160. #else
  161. return type.GetProperties();
  162. #endif
  163. }
  164. private static NotificationXmlElementAttribute GetElementAttribute(Type type)
  165. {
  166. return GetCustomAttributes(type).OfType<NotificationXmlElementAttribute>().FirstOrDefault();
  167. }
  168. private static IEnumerable<Attribute> GetCustomAttributes(Type type)
  169. {
  170. #if NETFX_CORE
  171. return type.GetTypeInfo().GetCustomAttributes();
  172. #else
  173. return type.GetCustomAttributes(true).OfType<Attribute>();
  174. #endif
  175. }
  176. private static IEnumerable<Attribute> GetCustomAttributes(PropertyInfo propertyInfo)
  177. {
  178. #if NETFX_CORE
  179. return propertyInfo.GetCustomAttributes();
  180. #else
  181. return propertyInfo.GetCustomAttributes(true).OfType<Attribute>();
  182. #endif
  183. }
  184. /// <summary>
  185. /// Gets the provided binding value, if it exists. Otherwise, falls back to the absolute value.
  186. /// </summary>
  187. /// <typeparam name="T">The type of the enum of the class properties.</typeparam>
  188. /// <param name="bindings">The collection of data-bound values.</param>
  189. /// <param name="bindableProperty">The property to obtain.</param>
  190. /// <param name="absoluteValue">The absolute value, if any.</param>
  191. /// <returns>The provided binding value, if it exists. Otherwise, falls back to the absolute value.</returns>
  192. internal static string GetBindingOrAbsoluteXmlValue<T>(IDictionary<T, string> bindings, T bindableProperty, string absoluteValue)
  193. {
  194. // If a binding is provided, use the binding value
  195. string bindingValue;
  196. if (bindings.TryGetValue(bindableProperty, out bindingValue))
  197. {
  198. return "{" + bindingValue + "}";
  199. }
  200. // Otherwise fallback to the absolute value
  201. return absoluteValue;
  202. }
  203. }
  204. }