aboutsummaryrefslogtreecommitdiff
path: root/src/wixcop/Converter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/wixcop/Converter.cs')
-rw-r--r--src/wixcop/Converter.cs633
1 files changed, 633 insertions, 0 deletions
diff --git a/src/wixcop/Converter.cs b/src/wixcop/Converter.cs
new file mode 100644
index 00000000..a204ebe0
--- /dev/null
+++ b/src/wixcop/Converter.cs
@@ -0,0 +1,633 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixCop
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Globalization;
8 using System.IO;
9 using System.Linq;
10 using System.Xml;
11 using System.Xml.Linq;
12 using WixToolset.Data;
13 using WixToolset.Extensibility.Services;
14 using WixToolset.Tools.Core;
15
16 /// <summary>
17 /// WiX source code converter.
18 /// </summary>
19 public class Converter
20 {
21 private const string XDocumentNewLine = "\n"; // XDocument normlizes "\r\n" to just "\n".
22 private static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs";
23
24 private static readonly XName FileElementName = WixNamespace + "File";
25 private static readonly XName ExePackageElementName = WixNamespace + "ExePackage";
26 private static readonly XName MsiPackageElementName = WixNamespace + "MsiPackage";
27 private static readonly XName MspPackageElementName = WixNamespace + "MspPackage";
28 private static readonly XName MsuPackageElementName = WixNamespace + "MsuPackage";
29 private static readonly XName PayloadElementName = WixNamespace + "Payload";
30 private static readonly XName WixElementWithoutNamespaceName = XNamespace.None + "Wix";
31
32 private static readonly Dictionary<string, XNamespace> OldToNewNamespaceMapping = new Dictionary<string, XNamespace>()
33 {
34 { "http://schemas.microsoft.com/wix/BalExtension", "http://wixtoolset.org/schemas/v4/wxs/bal" },
35 { "http://schemas.microsoft.com/wix/ComPlusExtension", "http://wixtoolset.org/schemas/v4/wxs/complus" },
36 { "http://schemas.microsoft.com/wix/DependencyExtension", "http://wixtoolset.org/schemas/v4/wxs/dependency" },
37 { "http://schemas.microsoft.com/wix/DifxAppExtension", "http://wixtoolset.org/schemas/v4/wxs/difxapp" },
38 { "http://schemas.microsoft.com/wix/FirewallExtension", "http://wixtoolset.org/schemas/v4/wxs/firewall" },
39 { "http://schemas.microsoft.com/wix/GamingExtension", "http://wixtoolset.org/schemas/v4/wxs/gaming" },
40 { "http://schemas.microsoft.com/wix/IIsExtension", "http://wixtoolset.org/schemas/v4/wxs/iis" },
41 { "http://schemas.microsoft.com/wix/MsmqExtension", "http://wixtoolset.org/schemas/v4/wxs/msmq" },
42 { "http://schemas.microsoft.com/wix/NetFxExtension", "http://wixtoolset.org/schemas/v4/wxs/netfx" },
43 { "http://schemas.microsoft.com/wix/PSExtension", "http://wixtoolset.org/schemas/v4/wxs/powershell" },
44 { "http://schemas.microsoft.com/wix/SqlExtension", "http://wixtoolset.org/schemas/v4/wxs/sql" },
45 { "http://schemas.microsoft.com/wix/TagExtension", "http://wixtoolset.org/schemas/v4/wxs/tag" },
46 { "http://schemas.microsoft.com/wix/UtilExtension", "http://wixtoolset.org/schemas/v4/wxs/util" },
47 { "http://schemas.microsoft.com/wix/VSExtension", "http://wixtoolset.org/schemas/v4/wxs/vs" },
48 { "http://wixtoolset.org/schemas/thmutil/2010", "http://wixtoolset.org/schemas/v4/thmutil" },
49 { "http://schemas.microsoft.com/wix/2009/Lux", "http://wixtoolset.org/schemas/v4/lux" },
50 { "http://schemas.microsoft.com/wix/2006/wi", "http://wixtoolset.org/schemas/v4/wxs" },
51 { "http://schemas.microsoft.com/wix/2006/localization", "http://wixtoolset.org/schemas/v4/wxl" },
52 { "http://schemas.microsoft.com/wix/2006/libraries", "http://wixtoolset.org/schemas/v4/wixlib" },
53 { "http://schemas.microsoft.com/wix/2006/objects", "http://wixtoolset.org/schemas/v4/wixobj" },
54 { "http://schemas.microsoft.com/wix/2006/outputs", "http://wixtoolset.org/schemas/v4/wixout" },
55 { "http://schemas.microsoft.com/wix/2007/pdbs", "http://wixtoolset.org/schemas/v4/wixpdb" },
56 { "http://schemas.microsoft.com/wix/2003/04/actions", "http://wixtoolset.org/schemas/v4/wi/actions" },
57 { "http://schemas.microsoft.com/wix/2006/tables", "http://wixtoolset.org/schemas/v4/wi/tables" },
58 { "http://schemas.microsoft.com/wix/2006/WixUnit", "http://wixtoolset.org/schemas/v4/wixunit" },
59 };
60
61 private Dictionary<XName, Action<XElement>> ConvertElementMapping;
62
63 /// <summary>
64 /// Instantiate a new Converter class.
65 /// </summary>
66 /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
67 /// <param name="errorsAsWarnings">Test errors to display as warnings.</param>
68 /// <param name="ignoreErrors">Test errors to ignore.</param>
69 public Converter(IMessaging messaging, int indentationAmount, IEnumerable<string> errorsAsWarnings = null, IEnumerable<string> ignoreErrors = null)
70 {
71 // workaround IDE0009 bug
72 /*this.ConvertElementMapping = new Dictionary<XName, Action<XElement>>()
73 {
74 { Converter.FileElementName, this.ConvertFileElement },
75 { Converter.ExePackageElementName, this.ConvertSuppressSignatureValidation },
76 { Converter.MsiPackageElementName, this.ConvertSuppressSignatureValidation },
77 { Converter.MspPackageElementName, this.ConvertSuppressSignatureValidation },
78 { Converter.MsuPackageElementName, this.ConvertSuppressSignatureValidation },
79 { Converter.PayloadElementName, this.ConvertSuppressSignatureValidation },
80 { Converter.WixElementWithoutNamespaceName, this.ConvertWixElementWithoutNamespace },
81 };*/
82 this.ConvertElementMapping = new Dictionary<XName, Action<XElement>>();
83 this.ConvertElementMapping.Add(Converter.FileElementName, this.ConvertFileElement);
84 this.ConvertElementMapping.Add(Converter.ExePackageElementName, this.ConvertSuppressSignatureValidation);
85 this.ConvertElementMapping.Add(Converter.MsiPackageElementName, this.ConvertSuppressSignatureValidation);
86 this.ConvertElementMapping.Add(Converter.MspPackageElementName, this.ConvertSuppressSignatureValidation);
87 this.ConvertElementMapping.Add(Converter.MsuPackageElementName, this.ConvertSuppressSignatureValidation);
88 this.ConvertElementMapping.Add(Converter.PayloadElementName, this.ConvertSuppressSignatureValidation);
89 this.ConvertElementMapping.Add(Converter.WixElementWithoutNamespaceName, this.ConvertWixElementWithoutNamespace);
90
91 this.Messaging = messaging;
92
93 this.IndentationAmount = indentationAmount;
94
95 this.ErrorsAsWarnings = new HashSet<ConverterTestType>(this.YieldConverterTypes(errorsAsWarnings));
96
97 this.IgnoreErrors = new HashSet<ConverterTestType>(this.YieldConverterTypes(ignoreErrors));
98 }
99
100 private int Errors { get; set; }
101
102 private HashSet<ConverterTestType> ErrorsAsWarnings { get; set; }
103
104 private HashSet<ConverterTestType> IgnoreErrors { get; set; }
105
106 private IMessaging Messaging { get; }
107
108 private int IndentationAmount { get; set; }
109
110 private string SourceFile { get; set; }
111
112 /// <summary>
113 /// Convert a file.
114 /// </summary>
115 /// <param name="sourceFile">The file to convert.</param>
116 /// <param name="saveConvertedFile">Option to save the converted errors that are found.</param>
117 /// <returns>The number of errors found.</returns>
118 public int ConvertFile(string sourceFile, bool saveConvertedFile)
119 {
120 XDocument document;
121
122 // Set the instance info.
123 this.Errors = 0;
124 this.SourceFile = sourceFile;
125
126 try
127 {
128 document = XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
129 }
130 catch (XmlException e)
131 {
132 this.OnError(ConverterTestType.XmlException, (XObject)null, "The xml is invalid. Detail: '{0}'", e.Message);
133
134 return this.Errors;
135 }
136
137 this.ConvertDocument(document);
138
139 // Fix errors if requested and necessary.
140 if (saveConvertedFile && 0 < this.Errors)
141 {
142 try
143 {
144 using (StreamWriter writer = File.CreateText(this.SourceFile))
145 {
146 document.Save(writer, SaveOptions.DisableFormatting | SaveOptions.OmitDuplicateNamespaces);
147 }
148 }
149 catch (UnauthorizedAccessException)
150 {
151 this.OnError(ConverterTestType.UnauthorizedAccessException, (XObject)null, "Could not write to file.");
152 }
153 }
154
155 return this.Errors;
156 }
157
158 /// <summary>
159 /// Convert a document.
160 /// </summary>
161 /// <param name="document">The document to convert.</param>
162 /// <returns>The number of errors found.</returns>
163 public int ConvertDocument(XDocument document)
164 {
165 XDeclaration declaration = document.Declaration;
166
167 // Convert the declaration.
168 if (null != declaration)
169 {
170 if (!String.Equals("utf-8", declaration.Encoding, StringComparison.OrdinalIgnoreCase))
171 {
172 if (this.OnError(ConverterTestType.DeclarationEncodingWrong, document.Root, "The XML declaration encoding is not properly set to 'utf-8'."))
173 {
174 declaration.Encoding = "utf-8";
175 }
176 }
177 }
178 else // missing declaration
179 {
180 if (this.OnError(ConverterTestType.DeclarationMissing, (XNode)null, "This file is missing an XML declaration on the first line."))
181 {
182 document.Declaration = new XDeclaration("1.0", "utf-8", null);
183 document.Root.AddBeforeSelf(new XText(XDocumentNewLine));
184 }
185 }
186
187 // Start converting the nodes at the top.
188 this.ConvertNode(document.Root, 0);
189
190 return this.Errors;
191 }
192
193 /// <summary>
194 /// Convert a single xml node.
195 /// </summary>
196 /// <param name="node">The node to convert.</param>
197 /// <param name="level">The depth level of the node.</param>
198 /// <returns>The converted node.</returns>
199 private void ConvertNode(XNode node, int level)
200 {
201 // Convert this node's whitespace.
202 if ((XmlNodeType.Comment == node.NodeType && 0 > ((XComment)node).Value.IndexOf(XDocumentNewLine, StringComparison.Ordinal)) ||
203 XmlNodeType.CDATA == node.NodeType || XmlNodeType.Element == node.NodeType || XmlNodeType.ProcessingInstruction == node.NodeType)
204 {
205 this.ConvertWhitespace(node, level);
206 }
207
208 // Convert this node if it is an element.
209 XElement element = node as XElement;
210
211 if (null != element)
212 {
213 this.ConvertElement(element);
214
215 // Convert all children of this element.
216 IEnumerable<XNode> children = element.Nodes().ToList();
217
218 foreach (XNode child in children)
219 {
220 this.ConvertNode(child, level + 1);
221 }
222 }
223 }
224
225 private void ConvertElement(XElement element)
226 {
227 // Gather any deprecated namespaces, then update this element tree based on those deprecations.
228 Dictionary<XNamespace, XNamespace> deprecatedToUpdatedNamespaces = new Dictionary<XNamespace, XNamespace>();
229
230 foreach (XAttribute declaration in element.Attributes().Where(a => a.IsNamespaceDeclaration))
231 {
232 XNamespace ns;
233
234 if (Converter.OldToNewNamespaceMapping.TryGetValue(declaration.Value, out ns))
235 {
236 if (this.OnError(ConverterTestType.XmlnsValueWrong, declaration, "The namespace '{0}' is out of date. It must be '{1}'.", declaration.Value, ns.NamespaceName))
237 {
238 deprecatedToUpdatedNamespaces.Add(declaration.Value, ns);
239 }
240 }
241 }
242
243 if (deprecatedToUpdatedNamespaces.Any())
244 {
245 Converter.UpdateElementsWithDeprecatedNamespaces(element.DescendantsAndSelf(), deprecatedToUpdatedNamespaces);
246 }
247
248 // Convert the node in much greater detail.
249 Action<XElement> convert;
250
251 if (this.ConvertElementMapping.TryGetValue(element.Name, out convert))
252 {
253 convert(element);
254 }
255 }
256
257 private void ConvertFileElement(XElement element)
258 {
259 if (null == element.Attribute("Id"))
260 {
261 XAttribute attribute = element.Attribute("Name");
262
263 if (null == attribute)
264 {
265 attribute = element.Attribute("Source");
266 }
267
268 if (null != attribute)
269 {
270 string name = Path.GetFileName(attribute.Value);
271
272 if (this.OnError(ConverterTestType.AssignAnonymousFileId, element, "The file id is being updated to '{0}' to ensure it remains the same as the default", name))
273 {
274 IEnumerable<XAttribute> attributes = element.Attributes().ToList();
275 element.RemoveAttributes();
276 element.Add(new XAttribute("Id", ToolsCommon.GetIdentifierFromName(name)));
277 element.Add(attributes);
278 }
279 }
280 }
281 }
282
283 private void ConvertSuppressSignatureValidation(XElement element)
284 {
285 XAttribute suppressSignatureValidation = element.Attribute("SuppressSignatureValidation");
286
287 if (null != suppressSignatureValidation)
288 {
289 if (this.OnError(ConverterTestType.SuppressSignatureValidationDeprecated, element, "The chain package element contains deprecated '{0}' attribute. Use the 'EnableSignatureValidation' instead.", suppressSignatureValidation))
290 {
291 if ("no" == suppressSignatureValidation.Value)
292 {
293 element.Add(new XAttribute("EnableSignatureValidation", "yes"));
294 }
295 }
296
297 suppressSignatureValidation.Remove();
298 }
299 }
300
301 /// <summary>
302 /// Converts a Wix element.
303 /// </summary>
304 /// <param name="element">The Wix element to convert.</param>
305 /// <returns>The converted element.</returns>
306 private void ConvertWixElementWithoutNamespace(XElement element)
307 {
308 if (this.OnError(ConverterTestType.XmlnsMissing, element, "The xmlns attribute is missing. It must be present with a value of '{0}'.", WixNamespace.NamespaceName))
309 {
310 element.Name = WixNamespace.GetName(element.Name.LocalName);
311
312 element.Add(new XAttribute("xmlns", WixNamespace.NamespaceName)); // set the default namespace.
313
314 foreach (XElement elementWithoutNamespace in element.Elements().Where(e => XNamespace.None == e.Name.Namespace))
315 {
316 elementWithoutNamespace.Name = WixNamespace.GetName(elementWithoutNamespace.Name.LocalName);
317 }
318 }
319 }
320
321 /// <summary>
322 /// Convert the whitespace adjacent to a node.
323 /// </summary>
324 /// <param name="node">The node to convert.</param>
325 /// <param name="level">The depth level of the node.</param>
326 private void ConvertWhitespace(XNode node, int level)
327 {
328 // Fix the whitespace before this node.
329 XText whitespace = node.PreviousNode as XText;
330
331 if (null != whitespace)
332 {
333 if (XmlNodeType.CDATA == node.NodeType)
334 {
335 if (this.OnError(ConverterTestType.WhitespacePrecedingCDATAWrong, node, "There should be no whitespace preceding a CDATA node."))
336 {
337 whitespace.Remove();
338 }
339 }
340 else
341 {
342 // TODO: this code complains about whitespace even after the file has been fixed.
343 if (!Converter.IsLegalWhitespace(this.IndentationAmount, level, whitespace.Value))
344 {
345 if (this.OnError(ConverterTestType.WhitespacePrecedingNodeWrong, node, "The whitespace preceding this node is incorrect."))
346 {
347 Converter.FixWhitespace(this.IndentationAmount, level, whitespace);
348 }
349 }
350 }
351 }
352
353 // Fix the whitespace after CDATA nodes.
354 XCData cdata = node as XCData;
355
356 if (null != cdata)
357 {
358 whitespace = cdata.NextNode as XText;
359
360 if (null != whitespace)
361 {
362 if (this.OnError(ConverterTestType.WhitespaceFollowingCDATAWrong, node, "There should be no whitespace following a CDATA node."))
363 {
364 whitespace.Remove();
365 }
366 }
367 }
368 else
369 {
370 // Fix the whitespace inside and after this node (except for Error which may contain just whitespace).
371 XElement element = node as XElement;
372
373 if (null != element && "Error" != element.Name.LocalName)
374 {
375 if (!element.HasElements && !element.IsEmpty && String.IsNullOrEmpty(element.Value.Trim()))
376 {
377 if (this.OnError(ConverterTestType.NotEmptyElement, element, "This should be an empty element since it contains nothing but whitespace."))
378 {
379 element.RemoveNodes();
380 }
381 }
382
383 whitespace = node.NextNode as XText;
384
385 if (null != whitespace)
386 {
387 // TODO: this code crashes when level is 0,
388 // complains about whitespace even after the file has been fixed,
389 // and the error text doesn't match the error.
390 if (!Converter.IsLegalWhitespace(this.IndentationAmount, level - 1, whitespace.Value))
391 {
392 if (this.OnError(ConverterTestType.WhitespacePrecedingEndElementWrong, whitespace, "The whitespace preceding this end element is incorrect."))
393 {
394 Converter.FixWhitespace(this.IndentationAmount, level - 1, whitespace);
395 }
396 }
397 }
398 }
399 }
400 }
401
402 private IEnumerable<ConverterTestType> YieldConverterTypes(IEnumerable<string> types)
403 {
404 if (null != types)
405 {
406 foreach (string type in types)
407 {
408 ConverterTestType itt;
409
410 if (Enum.TryParse<ConverterTestType>(type, true, out itt))
411 {
412 yield return itt;
413 }
414 else // not a known ConverterTestType
415 {
416 this.OnError(ConverterTestType.ConverterTestTypeUnknown, (XObject)null, "Unknown error type: '{0}'.", type);
417 }
418 }
419 }
420 }
421
422 private static void UpdateElementsWithDeprecatedNamespaces(IEnumerable<XElement> elements, Dictionary<XNamespace, XNamespace> deprecatedToUpdatedNamespaces)
423 {
424 foreach (XElement element in elements)
425 {
426 XNamespace ns;
427
428 if (deprecatedToUpdatedNamespaces.TryGetValue(element.Name.Namespace, out ns))
429 {
430 element.Name = ns.GetName(element.Name.LocalName);
431 }
432
433 // Remove all the attributes and add them back to with their namespace updated (as necessary).
434 IEnumerable<XAttribute> attributes = element.Attributes().ToList();
435 element.RemoveAttributes();
436
437 foreach (XAttribute attribute in attributes)
438 {
439 XAttribute convertedAttribute = attribute;
440
441 if (attribute.IsNamespaceDeclaration)
442 {
443 if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Value, out ns))
444 {
445 convertedAttribute = ("xmlns" == attribute.Name.LocalName) ? new XAttribute(attribute.Name.LocalName, ns.NamespaceName) : new XAttribute(XNamespace.Xmlns + attribute.Name.LocalName, ns.NamespaceName);
446 }
447 }
448 else if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Name.Namespace, out ns))
449 {
450 convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value);
451 }
452
453 element.Add(convertedAttribute);
454 }
455 }
456 }
457
458 /// <summary>
459 /// Determine if the whitespace preceding a node is appropriate for its depth level.
460 /// </summary>
461 /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
462 /// <param name="level">The depth level that should match this whitespace.</param>
463 /// <param name="whitespace">The whitespace to validate.</param>
464 /// <returns>true if the whitespace is legal; false otherwise.</returns>
465 private static bool IsLegalWhitespace(int indentationAmount, int level, string whitespace)
466 {
467 // strip off leading newlines; there can be an arbitrary number of these
468 while (whitespace.StartsWith(XDocumentNewLine, StringComparison.Ordinal))
469 {
470 whitespace = whitespace.Substring(XDocumentNewLine.Length);
471 }
472
473 // check the length
474 if (whitespace.Length != level * indentationAmount)
475 {
476 return false;
477 }
478
479 // check the spaces
480 foreach (char character in whitespace)
481 {
482 if (' ' != character)
483 {
484 return false;
485 }
486 }
487
488 return true;
489 }
490
491 /// <summary>
492 /// Fix the whitespace in a Whitespace node.
493 /// </summary>
494 /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
495 /// <param name="level">The depth level of the desired whitespace.</param>
496 /// <param name="whitespace">The whitespace node to fix.</param>
497 private static void FixWhitespace(int indentationAmount, int level, XText whitespace)
498 {
499 int newLineCount = 0;
500
501 for (int i = 0; i + 1 < whitespace.Value.Length; ++i)
502 {
503 if (XDocumentNewLine == whitespace.Value.Substring(i, 2))
504 {
505 ++i; // skip an extra character
506 ++newLineCount;
507 }
508 }
509
510 if (0 == newLineCount)
511 {
512 newLineCount = 1;
513 }
514
515 // reset the whitespace value
516 whitespace.Value = String.Empty;
517
518 // add the correct number of newlines
519 for (int i = 0; i < newLineCount; ++i)
520 {
521 whitespace.Value = String.Concat(whitespace.Value, XDocumentNewLine);
522 }
523
524 // add the correct number of spaces based on configured indentation amount
525 whitespace.Value = String.Concat(whitespace.Value, new string(' ', level * indentationAmount));
526 }
527
528 /// <summary>
529 /// Output an error message to the console.
530 /// </summary>
531 /// <param name="converterTestType">The type of converter test.</param>
532 /// <param name="node">The node that caused the error.</param>
533 /// <param name="message">Detailed error message.</param>
534 /// <param name="args">Additional formatted string arguments.</param>
535 /// <returns>Returns true indicating that action should be taken on this error, and false if it should be ignored.</returns>
536 private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args)
537 {
538 if (this.IgnoreErrors.Contains(converterTestType)) // ignore the error
539 {
540 return false;
541 }
542
543 // Increase the error count.
544 this.Errors++;
545
546 SourceLineNumber sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wixcop.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber);
547 bool warning = this.ErrorsAsWarnings.Contains(converterTestType);
548 string display = String.Format(CultureInfo.CurrentCulture, message, args);
549
550 var msg = new Message(sourceLine, warning ? MessageLevel.Warning : MessageLevel.Error, (int)converterTestType, "{0} ({1})", display, converterTestType.ToString());
551
552 this.Messaging.Write(msg);
553
554 return true;
555 }
556
557 /// <summary>
558 /// Converter test types. These are used to condition error messages down to warnings.
559 /// </summary>
560 private enum ConverterTestType
561 {
562 /// <summary>
563 /// Internal-only: displayed when a string cannot be converted to an ConverterTestType.
564 /// </summary>
565 ConverterTestTypeUnknown,
566
567 /// <summary>
568 /// Displayed when an XML loading exception has occurred.
569 /// </summary>
570 XmlException,
571
572 /// <summary>
573 /// Displayed when a file cannot be accessed; typically when trying to save back a fixed file.
574 /// </summary>
575 UnauthorizedAccessException,
576
577 /// <summary>
578 /// Displayed when the encoding attribute in the XML declaration is not 'UTF-8'.
579 /// </summary>
580 DeclarationEncodingWrong,
581
582 /// <summary>
583 /// Displayed when the XML declaration is missing from the source file.
584 /// </summary>
585 DeclarationMissing,
586
587 /// <summary>
588 /// Displayed when the whitespace preceding a CDATA node is wrong.
589 /// </summary>
590 WhitespacePrecedingCDATAWrong,
591
592 /// <summary>
593 /// Displayed when the whitespace preceding a node is wrong.
594 /// </summary>
595 WhitespacePrecedingNodeWrong,
596
597 /// <summary>
598 /// Displayed when an element is not empty as it should be.
599 /// </summary>
600 NotEmptyElement,
601
602 /// <summary>
603 /// Displayed when the whitespace following a CDATA node is wrong.
604 /// </summary>
605 WhitespaceFollowingCDATAWrong,
606
607 /// <summary>
608 /// Displayed when the whitespace preceding an end element is wrong.
609 /// </summary>
610 WhitespacePrecedingEndElementWrong,
611
612 /// <summary>
613 /// Displayed when the xmlns attribute is missing from the document element.
614 /// </summary>
615 XmlnsMissing,
616
617 /// <summary>
618 /// Displayed when the xmlns attribute on the document element is wrong.
619 /// </summary>
620 XmlnsValueWrong,
621
622 /// <summary>
623 /// Assign an identifier to a File element when on Id attribute is specified.
624 /// </summary>
625 AssignAnonymousFileId,
626
627 /// <summary>
628 /// SuppressSignatureValidation attribute is deprecated and replaced with EnableSignatureValidation.
629 /// </summary>
630 SuppressSignatureValidationDeprecated,
631 }
632 }
633}