changeset 409:dee3dcb72acf

Re #355: Add XML export format that can be transformed with an XSL * Merge Clutch's XML/XSL API changes
author IBBoard <dev@ibboard.co.uk>
date Thu, 25 Aug 2011 21:05:49 +0100
parents cbe69734f48f (current diff) 2c52f0235774 (diff)
children 204e6de93232
files
diffstat 4 files changed, 383 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/API/Exporters/WarFoundryXMLWithXSLExporter.cs	Thu Aug 25 21:05:49 2011 +0100
@@ -0,0 +1,196 @@
+// This file (WarFoundryXmlWithXslExporter.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2011 Dan Kulinski
+// 
+// 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;
+using System.Text;
+using System.Xml;
+using System.Xml.Xsl;
+using System.Xml.XPath;
+using System.Xml.Schema;
+using IBBoard.Lang;
+using IBBoard.Xml;
+using IBBoard.WarFoundry.API.Objects;
+using IBBoard.WarFoundry.API.Util;
+
+namespace IBBoard.WarFoundry.API.Exporters
+{
+	/// <summary>
+	/// Custom exporter that exports an army as an XML file with an XSLT applied
+	/// </summary>
+    public class WarFoundryXmlWithXslExporter : IWarFoundryExporter
+	{
+        private static WarFoundryXmlWithXslExporter exporter;
+
+        // Return the default class associated with this exporter
+        public static WarFoundryXmlWithXslExporter GetDefault()
+        {
+            if (exporter == null)
+            {
+                exporter = new WarFoundryXmlWithXslExporter();
+            }
+
+            return exporter;
+        }
+
+        private WarFoundryXmlWithXslExporter()
+        {
+            // Hide constructor
+        }
+
+        // Write to file
+        public void ExportArmy(Army army, string path)
+        {
+            XmlDocument xmlDoc = BuildXml(army);
+            // Simple XML output settings
+            XmlWriterSettings xmlSettings = new XmlWriterSettings();
+            xmlSettings.Indent = true;
+            xmlSettings.IndentChars = "  ";
+
+            // Write XML to file
+            using (XmlWriter writer = XmlWriter.Create(path, xmlSettings))
+            {
+                xmlDoc.Save(writer);
+                writer.Flush();
+                writer.Close();
+            }
+        }
+
+        // Write to file with transform
+        public void ExportArmyWithTransform(Army army, string savePath, string xslPath)
+        {
+            XmlDocument xmlDoc = BuildXml(army);
+            XslCompiledTransform xslTransform = new XslCompiledTransform();
+
+            xslTransform.Load(xslPath);
+            XmlWriter writer = XmlWriter.Create(savePath, xslTransform.OutputSettings);
+            xslTransform.Transform(xmlDoc, writer);
+            writer.Flush();
+            writer.Close();
+        }
+        
+        // Build the XML document to save or transform
+        private XmlDocument BuildXml(Army army)
+        {
+            XmlDocument armyList = new XmlDocument();
+           
+            // Everything will be a child of the army element
+            XmlElement root = armyList.CreateElement("army");
+
+            // Basic army information
+            XmlElement armyRace = armyList.CreateElement("race");
+            armyRace.InnerText = army.Race.Name;
+            root.AppendChild(armyRace);
+
+            XmlElement armyName = armyList.CreateElement("name");
+            armyName.InnerText = army.Name;
+            root.AppendChild(armyName);
+
+            XmlElement armyAvailablePoints = armyList.CreateElement("pointsAvailable");
+            armyAvailablePoints.InnerText = army.MaxPoints.ToString();
+            root.AppendChild(armyAvailablePoints);
+
+            XmlElement armyUsedPoints = armyList.CreateElement("pointsUsed");
+            armyUsedPoints.InnerText = army.Points.ToString();
+            root.AppendChild(armyUsedPoints);
+
+            // Get Categories and interate through each
+            foreach(ArmyCategory cat in army.Categories)
+            {
+                if (cat.GetUnits().Length == 0)
+                    continue;
+                XmlElement armyCategory = armyList.CreateElement("category");
+                armyCategory.SetAttribute("type", cat.Name);
+                
+
+                // Get units and iterate through each
+                foreach(Unit uni in cat.GetUnits())
+                {
+                    XmlElement armyUnit = armyList.CreateElement("unit");
+                    armyUnit.SetAttribute("name", uni.UnitType.Name);
+
+                    foreach (Stat[] stat in uni.UnitStatsArraysWithName)
+                    {
+                        XmlElement armyStatLine = armyList.CreateElement("statLine");
+                        foreach (Stat singleStat in stat)
+                        {
+                            XmlElement armyStat = armyList.CreateElement("stat");
+                            armyStat.SetAttribute("name", singleStat.ParentSlotName);
+                            armyStat.SetAttribute("value", singleStat.SlotValueString);
+                            armyStatLine.AppendChild(armyStat);
+                        }
+                        armyUnit.AppendChild(armyStatLine);
+                    }
+                    armyUnit.SetAttribute("points", uni.Points.ToString());
+                    armyUnit.SetAttribute("models", uni.Size.ToString());
+
+                    foreach (UnitEquipmentItem equip in uni.GetEquipment())
+                    {
+                        XmlElement armyEquipmentItem = armyList.CreateElement("equipmentItem");
+                        armyEquipmentItem.SetAttribute("name", equip.Name);
+
+                        int armyEquipAmount = 0;
+
+                        if (UnitEquipmentUtil.GetEquipmentAmount(uni, equip) == null)
+                        {
+                            armyEquipAmount = 0;
+                        }
+                        else
+                        {
+                            armyEquipAmount = (int)UnitEquipmentUtil.GetEquipmentAmount(uni, equip);
+                        }
+                        
+                        if (UnitEquipmentUtil.GetEquipmentAmountIsRatio(uni, equip))
+                        {
+                            float fraction = (float)(armyEquipAmount / 100.0);
+                            armyEquipAmount = (int)(fraction * uni.Size);
+                        }
+
+                        armyEquipmentItem.SetAttribute("count", armyEquipAmount.ToString());
+                       
+                        armyUnit.AppendChild(armyEquipmentItem);
+                    }
+
+                    foreach (Ability abil in uni.Abilities)
+                    {
+                        XmlElement armyAbilityItem = armyList.CreateElement("abilityItem");
+
+                        armyAbilityItem.SetAttribute("name", abil.Name);
+                        armyAbilityItem.SetAttribute("description", abil.Description);
+
+                        armyUnit.AppendChild(armyAbilityItem);
+                    }
+
+                    armyCategory.AppendChild(armyUnit);
+                }
+                root.AppendChild(armyCategory);
+            }
+
+           
+           
+
+            // Append all Categories to the XML doc
+
+            // Append tree to document
+            armyList.AppendChild(root);
+
+            return armyList;
+        }
+        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 GetEquipmentAmountAllTranslation(Unit unit)
+        {
+            return Translation.GetTranslation("armyHtmlExportEquipAmountAll", "all ({1})", 100, unit.Size);
+        }
+    }
+}
--- a/IBBoard.WarFoundry.API.csproj	Sun Aug 14 00:58:02 2011 +0000
+++ b/IBBoard.WarFoundry.API.csproj	Thu Aug 25 21:05:49 2011 +0100
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -60,6 +60,7 @@
   <ItemGroup>
     <None Include="app.config" />
     <None Include="COPYING" />
+    <Compile Include="API\Exporters\WarFoundryXMLWithXSLExporter.cs" />
     <Compile Include="AssemblyInfo.cs" />
     <None Include="schemas\army.xsd">
       <Gettext-ScanForTranslations>false</Gettext-ScanForTranslations>
@@ -196,6 +197,14 @@
       <Name>ICSharpCode.SharpZLib</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <Content Include="xsl\default_html.xsl">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="xsl\unitcard.xsl">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
   <ProjectExtensions>
     <MonoDevelop>
       <Properties>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xsl/default_html.xsl	Thu Aug 25 21:05:49 2011 +0100
@@ -0,0 +1,59 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:output doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" method="html" indent="yes" omit-xml-declaration="yes"/>
+<xsl:template match="/">
+  <html>
+    <head>
+      <style>
+        table, th, td { border: 1px solid #000; border-spacing: 0; border-collapse: collapse; margin: 0 }
+        table table { width: 100%; border-width: 0; margin: -2px }
+        table table td { border-width:0 1px }
+      </style>
+      <title>
+        <xsl:value-of select="/army/name"/>
+      </title>
+    </head>
+    <body>
+      <div id="armyInfo">
+        <h1>
+          <xsl:value-of select="/army/name"/> - <xsl:value-of select="/army/pointsUsed"/>pts
+        </h1>
+        <xsl:for-each select="/army/category">
+          <table>
+            <xsl:for-each select="./unit/statLine[1]">
+              <tr>
+                <xsl:for-each select="./stat">
+                  <td>
+                    <xsl:value-of select="./@name"/>
+                  </td>
+                </xsl:for-each>
+                <td>Notes</td>
+                <td>Points</td>
+              </tr>
+            </xsl:for-each>
+            <xsl:for-each select="./unit/statLine">
+              <tr>
+                <xsl:for-each select="./stat">
+                  <td>
+                    <xsl:value-of select="./@value"/>
+                  </td>
+                </xsl:for-each>
+                <td>
+                  <xsl:for-each select="../equipmentItem">
+                    <xsl:value-of select="./@name"/> (<xsl:value-of select="./@count"/>),
+                  </xsl:for-each>
+                  <xsl:for-each select="../abilityItem">
+                    <xsl:value-of select="./@name"/> (<xsl:value-of select="./@description"/>),
+                 </xsl:for-each>
+                </td>
+                <td>
+                  <xsl:value-of select="../@points"/>
+                </td>
+              </tr>
+            </xsl:for-each>
+          </table>
+        </xsl:for-each>
+      </div>
+    </body>
+  </html>
+</xsl:template>
+</xsl:stylesheet>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xsl/unitcard.xsl	Thu Aug 25 21:05:49 2011 +0100
@@ -0,0 +1,118 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:output doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" method="html" indent="yes" omit-xml-declaration="yes"/>
+  <xsl:variable name="lower">abcdefghijklmnopqrstuvwxyz</xsl:variable>
+  <xsl:variable name="upper">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
+  <xsl:template match="/">
+    <html>
+      <head>
+        <title>
+          <xsl:value-of select="/army/name"/> - Created in WarFoundry
+        </title>
+        <style media="all">
+          div#armyInfo { font-size: x-large; width: 100%; margin-bottom: 2em; }
+          div.unitcard { border: 1px solid black; width: 75%; margin-bottom: 2em; }
+          div.unitcard table.title { width: 100%; }
+          div.unitcard table.title th { background-color: #999999; }
+          table.stats { border-collapse: collapse; width: 100%;}
+          table.lists { padding: 0px; margins: 0px; border: 1px solid black; width: 100%}
+          table.lists th { font-size: small; font-variant: small-caps; text-align: left; }
+          table.lists td { width: 45%; }
+          ul.equipmentList { font-size: small; display: inline; list-style-type: none; }
+          ul.abilityList { font-size: small; display: inline; list-style-type: none; }
+        </style>
+        <style media="print">
+          div.unitcard { page-break-inside: avoid; }
+          div.specialrules { page-break-inside: avoid; }
+          div.pagebreak { page-break-after: always; display: none; }
+        </style>
+      </head>
+      <body>
+        <div id="armyInfo">
+          Name: <xsl:value-of select="/army/name"/> <br />
+          Points: <xsl:value-of select="/army/pointsUsed"/> of
+          <xsl:value-of select="/army/pointsAvailable"/>
+        </div>
+        <xsl:for-each select="/army/category">
+          <xsl:for-each select="./unit">
+            <div class="unitcard">
+              <table class="title">
+                <th align="left" width="50%">
+                  <xsl:value-of select="../@type"/>:<xsl:value-of select="./@name"/>
+                </th>
+                <th width="25%">
+                  Models: <xsl:value-of select="sum(.//@models)"/>
+                </th>
+                <th width="25%">
+                  Points: <xsl:value-of select="./@points"/>
+                </th>
+              </table>
+              <table class="stats" border="1">
+                <xsl:for-each select="./statLine[1]">
+                  <tr>
+                    <xsl:for-each select="./stat">
+                      <td>
+                        <b>
+                          <xsl:value-of select="translate(./@name,$lower,$upper)"/>
+                        </b>
+                      </td>
+                    </xsl:for-each>
+                  </tr>
+                </xsl:for-each>
+                <xsl:for-each select="./statLine">
+                  <tr>
+                    <xsl:for-each select="./stat">
+                      <td>
+                        <xsl:value-of select="./@value"/>
+                      </td>
+                    </xsl:for-each>
+                  </tr>
+                </xsl:for-each>
+              </table>
+              <table class="lists">
+                <tr>
+                  <th>
+                    Equipment
+                  </th>
+                  <th>
+                    Abilities
+                  </th>
+                </tr>
+                <tr>
+                  <td>
+                    <ul class="equipmentList">
+                      <xsl:for-each select="./equipmentItem">
+                        <li>
+                          <xsl:value-of select="./@name"/> (<xsl:value-of select="./@count"/>)
+                        </li>
+                      </xsl:for-each>
+                    </ul>
+                  </td>
+                  <td>
+                    <ul class="abilityList">
+                      <xsl:for-each select="./abilityItem">
+                        <li>
+                          <xsl:value-of select="./@name"/>
+                        </li>
+                      </xsl:for-each>
+                    </ul>
+                  </td>
+                </tr>
+              </table>
+            </div>
+          </xsl:for-each>
+        </xsl:for-each>
+        <div class="pagebreak"></div>
+        <div class="specialrules">
+          <h2>Special Rules</h2>
+          <ul class="abilityDescriptions">
+            <xsl:for-each select='//abilityItem[not(@name = preceding::abilityItem/@name)]'>
+              <li>
+                <xsl:value-of select='@name'/> - <xsl:value-of select='@description'/>
+              </li>
+            </xsl:for-each>
+          </ul>
+        </div>
+      </body>
+    </html>
+  </xsl:template>
+</xsl:stylesheet>
\ No newline at end of file