changeset 495:55b39514cbf8

Fixes #424: Basic HTML export is broken on Windows * Update to use new triple-valued AddMapping call for relative URIs Also: * Fix up double indents
author IBBoard <dev@ibboard.co.uk>
date Sat, 01 Sep 2012 12:04:03 +0100
parents 4f01fdc3bb41
children 00d6cf940c3c
files API/Exporters/WarFoundryHtmlExporter.cs
diffstat 1 files changed, 328 insertions(+), 325 deletions(-) [+]
line wrap: on
line diff
--- a/API/Exporters/WarFoundryHtmlExporter.cs	Mon Aug 06 20:50:59 2012 +0100
+++ b/API/Exporters/WarFoundryHtmlExporter.cs	Sat Sep 01 12:04:03 2012 +0100
@@ -1,7 +1,6 @@
 // This file (WarFoundryHtmlExporter.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard
 // 
 // The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license.
-
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -16,376 +15,380 @@
 
 namespace IBBoard.WarFoundry.API.Exporters
 {
-		/// <summary>
-		/// Custom exporter that exports an army as a basic HTML file
-		/// </summary>
-		public class WarFoundryHtmlExporter : IWarFoundryExporter
+	/// <summary>
+	/// Custom exporter that exports an army as a basic HTML file
+	/// </summary>
+	public class WarFoundryHtmlExporter : IWarFoundryExporter
+	{
+		private static WarFoundryHtmlExporter exporter;
+		private delegate string GetStatCellTextDelegate(Stat stat);
+		
+		public static WarFoundryHtmlExporter GetDefault()
 		{
-				private static WarFoundryHtmlExporter exporter;
-				private delegate string GetStatCellTextDelegate(Stat stat);
+			if (exporter == null)
+			{
+				exporter = new WarFoundryHtmlExporter();
+			}
+			
+			return exporter;
+		}
+		
+		private WarFoundryHtmlExporter()
+		{
+			//Hide constructor
+		}
 		
-				public static WarFoundryHtmlExporter GetDefault()
-				{
-						if (exporter == null)
-						{
-								exporter = new WarFoundryHtmlExporter();
-						}
+		public void ExportArmy(Army army, string path)
+		{
+			XmlDocument doc = new XmlDocument();
+			XmlResourceResolver resolver = new XmlResourceResolver(Assembly.GetExecutingAssembly());
+			string uriPre = "http://www.w3.org/TR/xhtml1/DTD/";
+			string resPre = "IBBoard.WarFoundry.schemas.";
+			resolver.AddMapping("-//W3C//ENTITIES Latin 1 for XHTML//EN", uriPre + "xhtml-lat1.ent", resPre + "xhtml-lat1.ent");
+			resolver.AddMapping("-//W3C//ENTITIES Symbols for XHTML//EN", uriPre + "xhtml-symbol.ent", resPre + "xhtml-symbol.ent");
+			resolver.AddMapping("-//W3C//ENTITIES Special for XHTML//EN", uriPre + "xhtml-special.ent", resPre + "xhtml-special.ent");
+			resolver.AddMapping("-//W3C//DTD XHTML 1.0 Strict//EN", uriPre + "xhtml1-strict.dtd", resPre + "xhtml1-strict.dtd");
+			doc.XmlResolver = resolver;
+			doc.AppendChild(doc.CreateDocumentType("html", "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", null));
+			XmlElement html = doc.CreateElement("html");
+			doc.AppendChild(html);
+			XmlElement head = doc.CreateElement("head");
+			html.AppendChild(head);
+			XmlElement title = doc.CreateElement("title");
+			title.InnerXml = army.Name;
+			head.AppendChild(title);
+			XmlElement metaCharset = doc.CreateElement("meta");
+			metaCharset.SetAttribute("http-equiv", "Content-Type");
+			metaCharset.SetAttribute("content", "text/html;charset=UTF-8");
+			head.AppendChild(metaCharset);
+			XmlElement style = doc.CreateElement("style");
+			style.InnerText = "table, th, td { border: 1px solid #000; border-spacing: 0; border-collapse: collapse; margin: 0 }\n"
+				+ "table table { width: 100%; border-width: 0; margin: -2px }\n"
+				+ "table table td { border-width:0 1px }";
+			head.AppendChild(style);
+			XmlElement body = doc.CreateElement("body");
+			html.AppendChild(body);
+			XmlElement header = doc.CreateElement("h1");
+			header.InnerText = Translation.GetTranslation("armyHtmlOutputBodyHeader", "{0} - {1}pts", army.Name, army.Points);
+			body.AppendChild(header);
 			
-						return exporter;
-				}
-		
-				private WarFoundryHtmlExporter()
-				{
-						//Hide constructor
-				}
-		
-				public void ExportArmy(Army army, string path)
+			foreach (XmlElement table in CreateTables(army, doc))
+			{
+				if (!IsTableOnlyHeader(table))
 				{
-						XmlDocument doc = new XmlDocument();
-						XmlResourceResolver resolver = new XmlResourceResolver(Assembly.GetExecutingAssembly());
-						resolver.AddMapping("-//W3C//ENTITIES Latin 1 for XHTML//EN", "IBBoard.API.schemas.xhtml1-lat1.ent");
-						resolver.AddMapping("http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent", "IBBoard.API.schemas.xhtml1-lat1.ent");
-						resolver.AddMapping("-//W3C//ENTITIES Symbols for XHTML//EN", "IBBoard.API.schemas.xhtml1-symbol.ent");
-						resolver.AddMapping("http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent", "IBBoard.API.schemas.xhtml1-symbol.ent");
-						resolver.AddMapping("-//W3C//ENTITIES Special for XHTML//EN", "IBBoard.API.schemas.xhtml1-special.ent");
-						resolver.AddMapping("http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent", "IBBoard.API.schemas.xhtml1-special.ent");
-						resolver.AddMapping("-//W3C//DTD XHTML 1.0 Strict//EN", "IBBoard.WarFoundry.schemas.xhtml1-strict.dtd");
-						resolver.AddMapping("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", "IBBoard.WarFoundry.schemas.xhtml1-strict.dtd");
-						doc.XmlResolver = resolver;
-						doc.AppendChild(doc.CreateDocumentType("html", "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", null));
-						XmlElement html = doc.CreateElement("html");
-						doc.AppendChild(html);
-						XmlElement head = doc.CreateElement("head");
-						html.AppendChild(head);
-						XmlElement title = doc.CreateElement("title");
-						title.InnerXml = army.Name;
-						head.AppendChild(title);
-						XmlElement metaCharset = doc.CreateElement("meta");
-						metaCharset.SetAttribute("http-equiv", "Content-Type");
-						metaCharset.SetAttribute("content", "text/html;charset=UTF-8");
-						head.AppendChild(metaCharset);
-						XmlElement style = doc.CreateElement("style");
-						style.InnerText = "table, th, td { border: 1px solid #000; border-spacing: 0; border-collapse: collapse; margin: 0 }\n"
-								+ "table table { width: 100%; border-width: 0; margin: -2px }\n"
-								+ "table table td { border-width:0 1px }";
-						head.AppendChild(style);
-						XmlElement body = doc.CreateElement("body");
-						html.AppendChild(body);
-						XmlElement header = doc.CreateElement("h1");
-						header.InnerText = Translation.GetTranslation("armyHtmlOutputBodyHeader", "{0} - {1}pts", army.Name, army.Points);
-						body.AppendChild(header);
+					body.AppendChild(table);
+				}
+			}
+
+			File.WriteAllText(path, doc.OuterXml);
+		}
+
+		private bool IsTableOnlyHeader(XmlElement table)
+		{
+			return table.ChildNodes.Count == 1;
+		}
+		
+		private XmlElement[] CreateTables(Army army, XmlDocument doc)
+		{
+			Dictionary<string, XmlElement> tables = new Dictionary<string, XmlElement>();
 			
-						foreach (XmlElement table in CreateTables(army, doc))
-						{
-								if (!IsTableOnlyHeader(table))
-								{
-										body.AppendChild(table);
-								}
-						}
-
-						File.WriteAllText(path, doc.OuterXml);
-				}
-
-				private bool IsTableOnlyHeader(XmlElement table)
-				{
-						return table.ChildNodes.Count == 1;
-				}
-		
-				private XmlElement[] CreateTables(Army army, XmlDocument doc)
-				{
-						Dictionary<string, XmlElement> tables = new Dictionary<string, XmlElement>();
+			foreach (SystemStats statSets in army.GameSystem.SystemStats)
+			{
+				tables[statSets.ID] = CreateTable(statSets, doc);
+			}
 			
-						foreach (SystemStats statSets in army.GameSystem.SystemStats)
-						{
-								tables[statSets.ID] = CreateTable(statSets, doc);
-						}
+			foreach (Unit unit in army.GetUnits())
+			{
+				CreateUnitRow(unit, tables[GetFirstStatType(unit)]);
+			}
 			
-						foreach (Unit unit in army.GetUnits())
-						{
-								CreateUnitRow(unit, tables[GetFirstStatType(unit)]);
-						}
-			
-						return DictionaryUtils.ToArray(tables);
-				}
+			return DictionaryUtils.ToArray(tables);
+		}
 
-				private static string GetFirstStatType(Unit unit)
-				{
-						string[] unitStatIDs = unit.UnitStatsArrayIDs;
-						return GetFirstStatType(unitStatIDs);
-				}
+		private static string GetFirstStatType(Unit unit)
+		{
+			string[] unitStatIDs = unit.UnitStatsArrayIDs;
+			return GetFirstStatType(unitStatIDs);
+		}
+		
+		public static string GetFirstStatType(string[] unitStatIDs)
+		{
+			return unitStatIDs[0];
+		}
 		
-				public static string GetFirstStatType(string[] unitStatIDs)
-				{
-						return unitStatIDs[0];
-				}
-		
-				private XmlElement CreateTable(SystemStats stats, XmlDocument doc)
-				{
-						XmlElement table = doc.CreateElement("table");
-						XmlElement headerRow = doc.CreateElement("tr");
-						table.AppendChild(headerRow);
-						XmlElement name = doc.CreateElement("th");
-						name.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitName", "name");
-						headerRow.AppendChild(name);
+		private XmlElement CreateTable(SystemStats stats, XmlDocument doc)
+		{
+			XmlElement table = doc.CreateElement("table");
+			XmlElement headerRow = doc.CreateElement("tr");
+			table.AppendChild(headerRow);
+			XmlElement name = doc.CreateElement("th");
+			name.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitName", "name");
+			headerRow.AppendChild(name);
+			
+			XmlElement unitTypeName = doc.CreateElement("th");
+			unitTypeName.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitTypeName", "type name");
+			headerRow.AppendChild(unitTypeName);
 			
-						XmlElement unitTypeName = doc.CreateElement("th");
-						unitTypeName.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitTypeName", "type name");
-						headerRow.AppendChild(unitTypeName);
+			foreach (StatSlot stat in stats.StatSlots)
+			{
+				XmlElement statHeader = doc.CreateElement("th");
+				statHeader.InnerText = stat.Name;
+				headerRow.AppendChild(statHeader);
+			}
 			
-						foreach (StatSlot stat in stats.StatSlots)
-						{
-								XmlElement statHeader = doc.CreateElement("th");
-								statHeader.InnerText = stat.Name;
-								headerRow.AppendChild(statHeader);
-						}
+			XmlElement notes = doc.CreateElement("th");
+			notes.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitNotes", "name");
+			;
+			headerRow.AppendChild(notes);
+			
+			XmlElement points = doc.CreateElement("th");
+			points.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitPoints", "name");
+			;
+			headerRow.AppendChild(points);
 			
-						XmlElement notes = doc.CreateElement("th");
-						notes.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitNotes", "name");
-						;
-						headerRow.AppendChild(notes);
+			return table;
+		}
+		
+		private XmlElement CreateUnitRow(Unit unit, XmlElement tableElem)
+		{
+			XmlDocument doc = tableElem.OwnerDocument;
+			XmlElement row = doc.CreateElement("tr");
+			tableElem.AppendChild(row);
+			Stat[][] memberStats = unit.UnitStatsArraysWithName;
+			string[] statTypeIDs = unit.UnitStatsArrayIDs;
+			string defaultStatType = GetFirstStatType(statTypeIDs);
+			int statRowCount = 0;
+			bool hasOther = false;
 			
-						XmlElement points = doc.CreateElement("th");
-						points.InnerText = Translation.GetTranslation("armyHtmlOutputTableHeaderUnitPoints", "name");
-						;
-						headerRow.AppendChild(points);
-			
-						return table;
-				}
-		
-				private XmlElement CreateUnitRow(Unit unit, XmlElement tableElem)
+			foreach (string statTypeID in statTypeIDs)
+			{
+				if (statTypeID.Equals(defaultStatType))
 				{
-						XmlDocument doc = tableElem.OwnerDocument;
-						XmlElement row = doc.CreateElement("tr");
-						tableElem.AppendChild(row);
-						Stat[][] memberStats = unit.UnitStatsArraysWithName;
-						string[] statTypeIDs = unit.UnitStatsArrayIDs;
-						string defaultStatType = GetFirstStatType(statTypeIDs);
-						int statRowCount = 0;
-						bool hasOther = false;
+					statRowCount++;
+				}
+				else if (!hasOther)
+				{
+					statRowCount++;
+					hasOther = true;
+				}
+			}
 			
-						foreach (string statTypeID in statTypeIDs)
-						{
-								if (statTypeID.Equals(defaultStatType))
-								{
-										statRowCount++;
-								} else if (!hasOther)
-								{
-										statRowCount++;
-										hasOther = true;
-								}
-						}
+			XmlElement name = doc.CreateElement("td");
+			name.InnerText = unit.Name;
+			SetRowSpan(name, statRowCount);
+			row.AppendChild(name);
+			CreateStatsBlock(row, memberStats, statTypeIDs);
+
+			StringBuilder sb = new StringBuilder();
+			UnitEquipmentItem[] unitEquipment = unit.GetEquipment();
 			
-						XmlElement name = doc.CreateElement("td");
-						name.InnerText = unit.Name;
-						SetRowSpan(name, statRowCount);
-						row.AppendChild(name);
-						CreateStatsBlock(row, memberStats, statTypeIDs);
-
-						StringBuilder sb = new StringBuilder();
-						UnitEquipmentItem[] unitEquipment = unit.GetEquipment();
-			
-						if (unitEquipment.Length > 0)
-						{
-								bool addSeparator = false;
+			if (unitEquipment.Length > 0)
+			{
+				bool addSeparator = false;
 				
-								foreach (UnitEquipmentItem equip in unitEquipment)
-								{
-										if (!addSeparator)
-										{
-												addSeparator = true;
-										} else
-										{
-												sb.Append(", ");
-										}
+				foreach (UnitEquipmentItem equip in unitEquipment)
+				{
+					if (!addSeparator)
+					{
+						addSeparator = true;
+					}
+					else
+					{
+						sb.Append(", ");
+					}
 
-										string amountString;
-										double amount = UnitEquipmentUtil.GetEquipmentAmount(unit, equip);
+					string amountString;
+					double amount = UnitEquipmentUtil.GetEquipmentAmount(unit, equip);
+
+					if (UnitEquipmentUtil.GetEquipmentAmountIsRatio(unit, equip))
+					{
 
-										if (UnitEquipmentUtil.GetEquipmentAmountIsRatio(unit, equip))
-										{
-
-												if (amount == 100)
-												{
-														amountString = GetEquipmentAmountAllTranslation(unit);
-												} else
-												{
-														int number = UnitEquipmentUtil.GetEquipmentAmountTaken(unit, equip);
-														amountString = GetEquipmentAmountRatioTranslation(amount, number);
-												}
-										} else
-										{
-												if (amount == -1)
-												{
-														amountString = GetEquipmentAmountAllTranslation(unit);
-												} else
-												{
-														amountString = GetEquipmentAmountNumberTranslation((int)amount);
-												}
-										}
+						if (amount == 100)
+						{
+							amountString = GetEquipmentAmountAllTranslation(unit);
+						}
+						else
+						{
+							int number = UnitEquipmentUtil.GetEquipmentAmountTaken(unit, equip);
+							amountString = GetEquipmentAmountRatioTranslation(amount, number);
+						}
+					}
+					else
+					{
+						if (amount == -1)
+						{
+							amountString = GetEquipmentAmountAllTranslation(unit);
+						}
+						else
+						{
+							amountString = GetEquipmentAmountNumberTranslation((int)amount);
+						}
+					}
 
-										sb.Append(Translation.GetTranslation("armyHtmlExportEquipAmountRatio", "{0} for {1}", equip.Name, amountString));
-								}
+					sb.Append(Translation.GetTranslation("armyHtmlExportEquipAmountRatio", "{0} for {1}", equip.Name, amountString));
+				}
 				
-								sb.Append(". ");
-						}
+				sb.Append(". ");
+			}
 			
-						ICollection<Ability> abilities = unit.Abilities;
+			ICollection<Ability> abilities = unit.Abilities;
 			
-						if (abilities.Count > 0)
-						{
-								bool addSeparator = false;
+			if (abilities.Count > 0)
+			{
+				bool addSeparator = false;
 				
-								foreach (Ability ability in abilities)
-								{
-										if (!addSeparator)
-										{
-												addSeparator = true;
-										} else
-										{
-												sb.Append(", ");
-										}
+				foreach (Ability ability in abilities)
+				{
+					if (!addSeparator)
+					{
+						addSeparator = true;
+					}
+					else
+					{
+						sb.Append(", ");
+					}
 					
-										sb.Append(ability.Name);
-								}
+					sb.Append(ability.Name);
+				}
 				
-								sb.Append(". ");
-						}
+				sb.Append(". ");
+			}
 			
-						XmlElement notes = doc.CreateElement("td");
-						notes.InnerText = sb.ToString();
-						SetRowSpan(notes, statRowCount);
-						row.AppendChild(notes);
+			XmlElement notes = doc.CreateElement("td");
+			notes.InnerText = sb.ToString();
+			SetRowSpan(notes, statRowCount);
+			row.AppendChild(notes);
 			
-						XmlElement points = doc.CreateElement("td");
-						points.InnerText = unit.Points.ToString();
-						SetRowSpan(points, statRowCount);
-						row.AppendChild(points);
+			XmlElement points = doc.CreateElement("td");
+			points.InnerText = unit.Points.ToString();
+			SetRowSpan(points, statRowCount);
+			row.AppendChild(points);
 			
-						return row;
-				}
+			return row;
+		}
 		
-				private static void SetRowSpan(XmlElement xmlElement, int statRowCount)
-				{
-						if (statRowCount > 1)
-						{
-								xmlElement.SetAttribute("rowspan", statRowCount.ToString());
-						}
-				}
+		private static void SetRowSpan(XmlElement xmlElement, int statRowCount)
+		{
+			if (statRowCount > 1)
+			{
+				xmlElement.SetAttribute("rowspan", statRowCount.ToString());
+			}
+		}
 		
-				private void CreateStatsBlock(XmlElement unitRow, Stat[][] memberStats, string[] statTypeIDs)
-				{
-						XmlDocument doc = unitRow.OwnerDocument;
-						string defaultStatType = GetFirstStatType(statTypeIDs);
+		private void CreateStatsBlock(XmlElement unitRow, Stat[][] memberStats, string[] statTypeIDs)
+		{
+			XmlDocument doc = unitRow.OwnerDocument;
+			string defaultStatType = GetFirstStatType(statTypeIDs);
 			
-						Stat[] defaultStatLine = memberStats[0];
-						int defaultStatLineCount = defaultStatLine.Length;
-						AddStatCell(defaultStatLine[0].SlotValueString, unitRow);
+			Stat[] defaultStatLine = memberStats[0];
+			int defaultStatLineCount = defaultStatLine.Length;
+			AddStatCell(defaultStatLine[0].SlotValueString, unitRow);
 			
-						for (int i = 1; i < defaultStatLineCount; i++)
-						{
-								string statText = GetDefaultStatCellText(defaultStatLine[i]);
-								AddStatCell(statText, unitRow);
-						}
+			for (int i = 1; i < defaultStatLineCount; i++)
+			{
+				string statText = GetDefaultStatCellText(defaultStatLine[i]);
+				AddStatCell(statText, unitRow);
+			}
 			
-						int statCount = statTypeIDs.Length;
+			int statCount = statTypeIDs.Length;
 			
-						if (statCount > 1)
-						{
-								XmlElement unitTable = (XmlElement)unitRow.ParentNode;
-								Dictionary<string, XmlElement> statParents = CreateStatsParentElements(statTypeIDs, unitTable);
+			if (statCount > 1)
+			{
+				XmlElement unitTable = (XmlElement)unitRow.ParentNode;
+				Dictionary<string, XmlElement> statParents = CreateStatsParentElements(statTypeIDs, unitTable);
 				
-								for (int i = 1; i < statCount; i++)
-								{
-										Stat[] statLine = memberStats[i];
-										string statTypeID = statTypeIDs[i];
-										XmlElement tableElement = DictionaryUtils.GetValue(statParents, statTypeID);
-										int statLineCount = statLine.Length;
-										XmlElement statRow = doc.CreateElement("tr");
-										tableElement.AppendChild(statRow);
-										GetStatCellTextDelegate statCellTextDelegate = (statTypeID.Equals(defaultStatType) ? new GetStatCellTextDelegate(GetDefaultStatCellText) : new GetStatCellTextDelegate(GetOtherStatCellText));
-										AddStatCell(statLine[0].SlotValueString, statRow);
+				for (int i = 1; i < statCount; i++)
+				{
+					Stat[] statLine = memberStats[i];
+					string statTypeID = statTypeIDs[i];
+					XmlElement tableElement = DictionaryUtils.GetValue(statParents, statTypeID);
+					int statLineCount = statLine.Length;
+					XmlElement statRow = doc.CreateElement("tr");
+					tableElement.AppendChild(statRow);
+					GetStatCellTextDelegate statCellTextDelegate = (statTypeID.Equals(defaultStatType) ? new GetStatCellTextDelegate(GetDefaultStatCellText) : new GetStatCellTextDelegate(GetOtherStatCellText));
+					AddStatCell(statLine[0].SlotValueString, statRow);
 				
-										for (int j = 1; j < statLineCount; j++)
-										{
-												string statText = statCellTextDelegate(statLine[j]);
-												AddStatCell(statText, statRow);
-										}
-								}
+					for (int j = 1; j < statLineCount; j++)
+					{
+						string statText = statCellTextDelegate(statLine[j]);
+						AddStatCell(statText, statRow);
+					}
+				}
 				
-								if (statParents.Count > 1)
-								{
-										AddOtherUnitStatTables(statParents, unitTable, defaultStatLineCount);
-								}
-						}
-				}
-		
-				private static void AddOtherUnitStatTables(Dictionary<string, XmlElement> statParents, XmlElement unitTable, int defaultStatLineCount)
+				if (statParents.Count > 1)
 				{
-						XmlDocument doc = unitTable.OwnerDocument;
-						XmlElement otherStatsRow = doc.CreateElement("tr");
-						unitTable.AppendChild(otherStatsRow);
-						XmlElement otherStatsCell = doc.CreateElement("td");
-						otherStatsCell.SetAttribute("colspan", defaultStatLineCount.ToString());
-						otherStatsRow.AppendChild(otherStatsCell);
+					AddOtherUnitStatTables(statParents, unitTable, defaultStatLineCount);
+				}
+			}
+		}
+		
+		private static void AddOtherUnitStatTables(Dictionary<string, XmlElement> statParents, XmlElement unitTable, int defaultStatLineCount)
+		{
+			XmlDocument doc = unitTable.OwnerDocument;
+			XmlElement otherStatsRow = doc.CreateElement("tr");
+			unitTable.AppendChild(otherStatsRow);
+			XmlElement otherStatsCell = doc.CreateElement("td");
+			otherStatsCell.SetAttribute("colspan", defaultStatLineCount.ToString());
+			otherStatsRow.AppendChild(otherStatsCell);
 			
-						foreach (XmlElement tableElem in statParents.Values)
-						{
-								if (tableElem != unitTable)
-								{
-										otherStatsCell.AppendChild(tableElem);
-								}
-						}
-				}
-
-				private Dictionary<string, XmlElement> CreateStatsParentElements(string[] statTypeIDs, XmlElement parentTable)
+			foreach (XmlElement tableElem in statParents.Values)
+			{
+				if (tableElem != unitTable)
 				{
-						Dictionary<string, XmlElement> statParents = new Dictionary<string, XmlElement>();
-						XmlDocument doc = parentTable.OwnerDocument;
-						string defaultStatTypeID = GetFirstStatType(statTypeIDs);
-						statParents[defaultStatTypeID] = parentTable;
+					otherStatsCell.AppendChild(tableElem);
+				}
+			}
+		}
+
+		private Dictionary<string, XmlElement> CreateStatsParentElements(string[] statTypeIDs, XmlElement parentTable)
+		{
+			Dictionary<string, XmlElement> statParents = new Dictionary<string, XmlElement>();
+			XmlDocument doc = parentTable.OwnerDocument;
+			string defaultStatTypeID = GetFirstStatType(statTypeIDs);
+			statParents[defaultStatTypeID] = parentTable;
 			
-						foreach (string statTypeID in statTypeIDs)
-						{
-								if (!statParents.ContainsKey(statTypeID))
-								{
-										XmlElement tableElement = doc.CreateElement("table");
-										statParents[statTypeID] = tableElement;
-								}
-						}
-			
-						return statParents;
-				}
-
-				private string GetDefaultStatCellText(Stat stat)
-				{
-						return Translation.GetTranslation("armyHtmlExportDefaultStatCellText", "{0}", stat.SlotValueString, stat.ParentSlotName);
-				}
-
-				private string GetOtherStatCellText(Stat stat)
+			foreach (string statTypeID in statTypeIDs)
+			{
+				if (!statParents.ContainsKey(statTypeID))
 				{
-						return Translation.GetTranslation("armyHtmlExportOtherStatCellText", "{1}: {0}", stat.SlotValueString, stat.ParentSlotName);
+					XmlElement tableElement = doc.CreateElement("table");
+					statParents[statTypeID] = tableElement;
 				}
-		
-				private static void AddStatCell(string statValue, XmlElement row)
-				{
-						XmlElement statCell = row.OwnerDocument.CreateElement("td");
-						statCell.InnerText = statValue;
-						row.AppendChild(statCell);
-				}
+			}
+			
+			return statParents;
+		}
+
+		private string GetDefaultStatCellText(Stat stat)
+		{
+			return Translation.GetTranslation("armyHtmlExportDefaultStatCellText", "{0}", stat.SlotValueString, stat.ParentSlotName);
+		}
+
+		private string GetOtherStatCellText(Stat stat)
+		{
+			return Translation.GetTranslation("armyHtmlExportOtherStatCellText", "{1}: {0}", stat.SlotValueString, stat.ParentSlotName);
+		}
 		
-				private string GetEquipmentAmountRatioTranslation(double amount, int number)
-				{
-						return Translation.GetTranslation("armyHtmlExportEquipAmountPercentage", "{0}% ({1})", amount, number);
-				}
+		private static void AddStatCell(string statValue, XmlElement row)
+		{
+			XmlElement statCell = row.OwnerDocument.CreateElement("td");
+			statCell.InnerText = statValue;
+			row.AppendChild(statCell);
+		}
+		
+		private string GetEquipmentAmountRatioTranslation(double amount, int number)
+		{
+			return Translation.GetTranslation("armyHtmlExportEquipAmountPercentage", "{0}% ({1})", amount, number);
+		}
 		
-				private string GetEquipmentAmountNumberTranslation(int amount)
-				{
-						return Translation.GetTranslation("armyHtmlExportEquipAmountNumber", "{0}", amount);
-				}
+		private string GetEquipmentAmountNumberTranslation(int amount)
+		{
+			return Translation.GetTranslation("armyHtmlExportEquipAmountNumber", "{0}", amount);
+		}
 		
-				private string GetEquipmentAmountAllTranslation(Unit unit)
-				{
-						return Translation.GetTranslation("armyHtmlExportEquipAmountAll", "all ({1})", 100, unit.Size);
-				}
+		private string GetEquipmentAmountAllTranslation(Unit unit)
+		{
+			return Translation.GetTranslation("armyHtmlExportEquipAmountAll", "all ({1})", 100, unit.Size);
 		}
+	}
 }