summaryrefslogtreecommitdiffstats
path: root/tools/Sandcastle/Source/XmlCat/Program.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/Sandcastle/Source/XmlCat/Program.cs')
-rw-r--r--tools/Sandcastle/Source/XmlCat/Program.cs166
1 files changed, 166 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/XmlCat/Program.cs b/tools/Sandcastle/Source/XmlCat/Program.cs
new file mode 100644
index 0000000..7b0ab64
--- /dev/null
+++ b/tools/Sandcastle/Source/XmlCat/Program.cs
@@ -0,0 +1,166 @@
+// Copyright © Microsoft Corporation.
+// This source file is subject to the Microsoft Permissive License.
+// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
+// All other rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Xml;
+using System.Xml.XPath;
+using Microsoft.Ddue.Tools.CommandLine;
+
+namespace MergeXml
+{
+ class Program
+ {
+ static int Main(string[] args)
+ {
+ ConsoleApplication.WriteBanner();
+
+ // get and validate args
+ OptionCollection programOptions = new OptionCollection();
+ programOptions.Add(new SwitchOption("?", "Show this help page."));
+ programOptions.Add(new StringOption("out", "(String) Path to the file that the input files should be merged in to. Required."));
+ programOptions.Add(new StringOption("position", "(String) The name of the element or elements to which the input elements will be appended. Required."));
+ programOptions.Add(new StringOption("include", @"(String) An xpath expression indicating which elements from the source files should be introduced in to the output file. The default is '/'"));
+ ParseArgumentsResult options = programOptions.ParseArguments(args);
+ if (options.Options["?"].IsPresent || !options.Options["out"].IsPresent || !options.Options["position"].IsPresent)
+ {
+ programOptions.WriteOptionSummary(Console.Error);
+ Console.WriteLine();
+ Console.WriteLine("file1 file2 ...");
+ Console.WriteLine("The input files to operate on.");
+ return 0;
+ }
+ // ensure output file exists
+ string outputPath = options.Options["out"].Value.ToString();
+ if (!File.Exists(outputPath))
+ {
+ ConsoleApplication.WriteMessage(LogLevel.Error, "The specified output file, which the input files are to be merged in to, doesn't exist.");
+ return 1;
+ }
+
+ // ensure a postition element name was passed
+ if (String.IsNullOrEmpty(options.Options["position"].Value.ToString()))
+ {
+ ConsoleApplication.WriteMessage(LogLevel.Error, "No position element name was provided.");
+ return 1;
+ }
+ string positionName = options.Options["position"].Value.ToString();
+
+ // validate xpaths ("include" switch)
+ string xpath;
+ if (options.Options["include"].IsPresent)
+ xpath = options.Options["include"].Value.ToString();
+ else
+ xpath = @"/";
+ XPathExpression includeExpression;
+ try
+ {
+ includeExpression = XPathExpression.Compile(xpath);
+ }
+ catch (XPathException)
+ {
+ ConsoleApplication.WriteMessage(LogLevel.Error, "The xpath expression provided by the include switch, '" + xpath + "', is invalid.");
+ return 1;
+ }
+
+ // get list of input files to operate on
+ if (options.UnusedArguments.Count == 0)
+ {
+ ConsoleApplication.WriteMessage(LogLevel.Error, "No input files were provided.");
+ return 1;
+ }
+ string[] inputFiles = new string[options.UnusedArguments.Count];
+ options.UnusedArguments.CopyTo(inputFiles, 0);
+
+ // ensure all input files exist
+ foreach (string path in inputFiles)
+ {
+ if (!File.Exists(path))
+ {
+ ConsoleApplication.WriteMessage(LogLevel.Error, "Specified input file '" + path + "' doesn't exist.");
+ return 1;
+ }
+ }
+
+
+ // open the output file and move to the position
+ XmlWriterSettings outputSettings = new XmlWriterSettings();
+ outputSettings.Indent = true;
+ outputSettings.Encoding = Encoding.UTF8;
+ using (XmlWriter output = XmlWriter.Create(outputPath + ".tmp", outputSettings))
+ {
+ // start printing output doc string until the selected node is matched
+ using (XmlReader source = XmlReader.Create(outputPath))
+ {
+ while (!source.EOF)
+ {
+ source.Read();
+
+ switch (source.NodeType)
+ {
+ case XmlNodeType.Element:
+ output.WriteStartElement(source.Prefix, source.LocalName, source.NamespaceURI);
+ output.WriteAttributes(source, true);
+ if (source.IsEmptyElement)
+ {
+ output.WriteEndElement();
+ }
+ if (String.Equals(source.Name, positionName, StringComparison.OrdinalIgnoreCase))
+ {
+ // start introducing the elements from the input files
+ foreach (string path in inputFiles)
+ {
+ XPathDocument inputDoc = new XPathDocument(path);
+ XPathNavigator inputNav = inputDoc.CreateNavigator();
+ XPathNodeIterator inputNodesIterator = inputNav.Select(includeExpression);
+ while (inputNodesIterator.MoveNext())
+ {
+ output.WriteNode(inputNodesIterator.Current, true);
+ }
+ }
+ }
+ break;
+ case XmlNodeType.Text:
+ output.WriteString(source.Value);
+ break;
+ case XmlNodeType.Whitespace:
+ case XmlNodeType.SignificantWhitespace:
+ output.WriteWhitespace(source.Value);
+ break;
+ case XmlNodeType.CDATA:
+ output.WriteCData(source.Value);
+ break;
+ case XmlNodeType.EntityReference:
+ output.WriteEntityRef(source.Name);
+ break;
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.ProcessingInstruction:
+ output.WriteProcessingInstruction(source.Name, source.Value);
+ break;
+ case XmlNodeType.DocumentType:
+ output.WriteDocType(source.Name, source.GetAttribute("PUBLIC"), source.GetAttribute("SYSTEM"), source.Value);
+ break;
+ case XmlNodeType.Comment:
+ output.WriteComment(source.Value);
+ break;
+ case XmlNodeType.EndElement:
+ output.WriteFullEndElement();
+ break;
+ }
+ }
+ }
+ output.WriteEndDocument();
+ output.Close();
+ }
+
+ File.Delete(outputPath);
+ File.Move(outputPath + ".tmp", outputPath);
+
+ return 0; // pau
+ }
+ }
+} \ No newline at end of file