// 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
}
}
}
|