Browse Source

增加word导入导出,重构部分代码

宋悦 8 years ago
parent
commit
2beabce097
71 changed files with 10792 additions and 1472 deletions
  1. 93 1
      cqb-comm-utils/pom.xml
  2. 117 0
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/BeanCopierUtil.java
  3. 119 44
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/CommonUtils.java
  4. 35 35
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/enums/ExtractPolicy.java
  5. 65 53
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/enums/QuesStructType.java
  6. 44 0
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/enums/QuesUnit.java
  7. 734 0
      cqb-comm-utils/src/main/java/com/qmth/cqb/utils/word/DocxProcessUtil.java
  8. 3822 0
      cqb-comm-utils/src/main/resources/MML2OMML.XSL
  9. 2068 0
      cqb-comm-utils/src/main/resources/OMML2MML.XSL
  10. 1 0
      cqb-comm-utils/src/main/resources/common.properties
  11. 6 0
      cqb-comm-utils/src/main/resources/log4j.properties
  12. 1613 0
      cqb-comm-utils/src/main/resources/paper_template.ftl
  13. 0 11
      cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/dao/GenPaperRepo.java
  14. 0 128
      cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/model/GenPaper.java
  15. 0 73
      cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/model/GenPaperDetail.java
  16. 0 79
      cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/model/GenPaperResource.java
  17. 0 53
      cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/model/GenPaperRule.java
  18. 0 17
      cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/service/GenPaperService.java
  19. 1 7
      cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/web/GenPaperController.java
  20. 3 1
      cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperDetailRepo.java
  21. 0 12
      cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperDetailStructureRepo.java
  22. 6 1
      cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperDetailUnitRepo.java
  23. 9 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperStructDetailRepo.java
  24. 10 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperStructRepo.java
  25. 0 12
      cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperStructureRepo.java
  26. 87 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/dto/PaperDetailDto.java
  27. 67 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/dto/PaperDetailUnitDto.java
  28. 76 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/dto/PaperDto.java
  29. 1 1
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/ExtractConfig.java
  30. 80 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/ImportPaperCheck.java
  31. 90 110
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/Paper.java
  32. 28 8
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperDetail.java
  33. 0 100
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperDetailStructure.java
  34. 24 18
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperDetailUnit.java
  35. 109 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperStruct.java
  36. 104 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperStructDetail.java
  37. 0 67
      cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperStructure.java
  38. 177 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/ExportPaperService.java
  39. 751 50
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/ImportPaperService.java
  40. 1 1
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperDetailService.java
  41. 0 63
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperDetailStructureService.java
  42. 5 3
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperDetailUnitService.java
  43. 63 0
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperStructDetailService.java
  44. 9 9
      cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperStructService.java
  45. 24 34
      cqb-paper/src/main/java/com/qmth/cqb/paper/web/ImportPaperController.java
  46. 92 92
      cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperStructController.java
  47. 10 10
      cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperStructDetailController.java
  48. 0 9
      cqb-question-resource/src/main/java/com/qmth/cqb/question/dao/QuesOptionRepo.java
  49. 0 11
      cqb-question-resource/src/main/java/com/qmth/cqb/question/dao/QuestionTypeRepo.java
  50. 8 8
      cqb-question-resource/src/main/java/com/qmth/cqb/question/model/QuesOption.java
  51. 57 41
      cqb-question-resource/src/main/java/com/qmth/cqb/question/model/Question.java
  52. 15 35
      cqb-question-resource/src/main/java/com/qmth/cqb/question/model/QuestionType.java
  53. 9 48
      cqb-question-resource/src/main/java/com/qmth/cqb/question/service/QuesService.java
  54. 0 80
      cqb-question-resource/src/main/java/com/qmth/cqb/question/service/QuesStructTypeService.java
  55. 28 48
      cqb-question-resource/src/main/java/com/qmth/cqb/question/web/QuesController.java
  56. 0 83
      cqb-question-resource/src/main/java/com/qmth/cqb/question/web/QuestionTypeController.java
  57. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/dao/QuesOptionRepo.class
  58. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/dao/QuestionTypeRepo.class
  59. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/model/QuesOption.class
  60. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/model/Question.class
  61. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/model/QuestionType.class
  62. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/service/QuesService.class
  63. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/service/QuesStructTypeService.class
  64. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/web/QuesController.class
  65. BIN
      cqb-question-resource/target/classes/com/qmth/cqb/question/web/QuestionTypeController.class
  66. 1 1
      cqb-question-resource/target/maven-archiver/pom.properties
  67. 12 0
      cqb-starter/pom.xml
  68. 2 1
      cqb-starter/src/main/resources/application.properties
  69. 25 0
      cqb-starter/src/main/resources/log4j2.xml
  70. 89 13
      cqb-starter/src/test/java/com/qmth/cqb/AppTest.java
  71. 2 1
      pom.xml

+ 93 - 1
cqb-comm-utils/pom.xml

@@ -17,11 +17,18 @@
     </properties>
 
     <dependencies>
+
         <dependency>
             <groupId>com.google.code.gson</groupId>
             <artifactId>gson</artifactId>
             <version>2.7</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
@@ -37,25 +44,110 @@
             <artifactId>springfox-swagger2</artifactId>
             <version>${swagger-version}</version>
         </dependency>
+
         <dependency>
             <groupId>io.springfox</groupId>
             <artifactId>springfox-swagger-ui</artifactId>
             <version>${swagger-version}</version>
         </dependency>
 
-
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
             <scope>test</scope>
         </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-test</artifactId>
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.5</version>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.5</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>2.7</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.docx4j</groupId>
+            <artifactId>docx4j</artifactId>
+            <version>3.3.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>3.15</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>3.15</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-scratchpad</artifactId>
+            <version>3.15</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml-schemas</artifactId>
+            <version>3.15</version>
+        </dependency>
+
+        <dependency>
+            <groupId>net.sf.saxon</groupId>
+            <artifactId>Saxon-HE</artifactId>
+            <version>9.7.0-15</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jsoup</groupId>
+            <artifactId>jsoup</artifactId>
+            <version>1.10.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>net.sourceforge.jeuclid</groupId>
+            <artifactId>jeuclid-core</artifactId>
+            <version>3.1.9</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+            <version>2.3.25-incubating</version>
+        </dependency>
+
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>1.6.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.esotericsoftware</groupId>
+            <artifactId>reflectasm</artifactId>
+            <version>1.11.3</version>
+        </dependency>
+
          <dependency>
              <groupId>org.docx4j</groupId>
  	         <artifactId>docx4j</artifactId>

+ 117 - 0
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/BeanCopierUtil.java

@@ -0,0 +1,117 @@
+package com.qmth.cqb.utils;
+
+import com.esotericsoftware.reflectasm.ConstructorAccess;
+import org.springframework.cglib.beans.BeanCopier;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.lang.String.format;
+
+/**
+ * Created by songyue on 17/3/15.
+ */
+public class BeanCopierUtil {
+    private static final Map<String, BeanCopier> beanCopierCache = new ConcurrentHashMap<>();
+    private static final Map<String,ConstructorAccess> constructorAccessCache = new ConcurrentHashMap<>();
+
+    private static void copyProperties(Object source, Object target) {
+        BeanCopier copier = getBeanCopier(source.getClass(), target.getClass());
+        copier.copy(source, target, null);
+    }
+
+    /**
+     * 获取BeanCopier实例
+     * @param sourceClass
+     * @param targetClass
+     * @return
+     */
+    private static BeanCopier getBeanCopier(Class sourceClass, Class targetClass) {
+        String beanKey = generateKey(sourceClass, targetClass);
+        BeanCopier copier = null;
+        if (!beanCopierCache.containsKey(beanKey)) {
+            copier = BeanCopier.create(sourceClass, targetClass, false);
+            beanCopierCache.put(beanKey, copier);
+        } else {
+            copier = beanCopierCache.get(beanKey);
+        }
+        return copier;
+    }
+
+    /**
+     * 生成key
+     * @param class1
+     * @param class2
+     * @return
+     */
+    private static String generateKey(Class<?> class1, Class<?> class2) {
+        return class1.toString() + class2.toString();
+    }
+
+    /**
+     * 拷贝对象
+     * @param source
+     * @param targetClass
+     * @param <T>
+     * @return
+     */
+    public static <T> T copyProperties(Object source, Class<T> targetClass) {
+        T t = null;
+        try {
+            t = targetClass.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            throw new RuntimeException(format("Create new instance of %s failed: %s", targetClass, e.getMessage()));
+        }
+        copyProperties(source, t);
+        return t;
+    }
+
+    /**
+     * 拷贝List
+     * @param sourceList
+     * @param targetClass
+     * @param <T>
+     * @return
+     */
+    public static <T> List<T> copyPropertiesOfList(List<?> sourceList, Class<T> targetClass) {
+        if (CollectionUtils.isEmpty(sourceList)) {
+            return Collections.emptyList();
+        }
+        ConstructorAccess<T> constructorAccess = getConstructorAccess(targetClass);
+        List<T> resultList = new ArrayList<>(sourceList.size());
+        for (Object o : sourceList) {
+            T t = null;
+            try {
+                t = constructorAccess.newInstance();
+                copyProperties(o, t);
+                resultList.add(t);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return resultList;
+    }
+
+    /**
+     * 获取集合包装类
+     * @param targetClass
+     * @param <T>
+     * @return
+     */
+    private static <T> ConstructorAccess<T> getConstructorAccess(Class<T> targetClass) {
+        ConstructorAccess<T> constructorAccess = constructorAccessCache.get(targetClass.toString());
+        if(constructorAccess != null) {
+            return constructorAccess;
+        }
+        try {
+            constructorAccess = ConstructorAccess.get(targetClass);
+            constructorAccess.newInstance();
+            constructorAccessCache.put(targetClass.toString(),constructorAccess);
+        } catch (Exception e) {
+            throw new RuntimeException(format("Create new instance of %s failed: %s", targetClass, e.getMessage()));
+        }
+        return constructorAccess;
+    }
+
+}

+ 119 - 44
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/CommonUtils.java

@@ -1,54 +1,129 @@
 package com.qmth.cqb.utils;
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.qmth.cqb.utils.enums.QuesStructType;
 
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Properties;
+import java.util.stream.Stream;
 
 /**
  * Created by songyue on 16/12/27.
  */
 public final class CommonUtils {
-	
-	/**
-	 * 提取Html里面的文本信息,并把一般的转义字符串转换回来
-	 * @param htmlStr
-	 * @return
-	 * @throws ParserException
-	 */
-	public static String extractText(String htmlStr){
-		if(htmlStr.toLowerCase().contains("<!doctype")){
-			int index1 = htmlStr.toLowerCase().indexOf("<!doctype");
-			int index2 = htmlStr.indexOf('>',index1 + 1);
-			htmlStr = htmlStr.substring(0, index1) + htmlStr.substring(index2 + 1);
-		}
-		String regEx_head = "<[\\s]*?head[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?head[\\s]*?>"; //定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script> }
-		String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"; //定义script的正则表达式{或<script[^>]*?>[\\s\\S]*?<\\/script> }
-        String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"; //定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style> }
-        String regEx_html = "<[^>]+>"; //定义HTML标签的正则表达式
-
-        Pattern p_head = Pattern.compile(regEx_head,Pattern.CASE_INSENSITIVE);
-        Matcher m_head = p_head.matcher(htmlStr);
-        htmlStr = m_head.replaceAll(""); //过滤script标签
-
-        Pattern p_script = Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE);
-        Matcher m_script = p_script.matcher(htmlStr);
-        htmlStr = m_script.replaceAll(""); //过滤script标签
-
-        Pattern p_style = Pattern.compile(regEx_style,Pattern.CASE_INSENSITIVE);
-        Matcher m_style = p_style.matcher(htmlStr);
-        htmlStr = m_style.replaceAll(""); //过滤style标签
-
-        htmlStr = htmlStr.replace("<div", " <div").replace("<DIV", " <DIV")
-        		.replace("<p", " <p").replace("<P", " <P")
-        		.replace("<h", " <h").replace("<H", " <H")
-        		.replace("<br", " <br").replace("<BR", " <BR")
-        		.replace("<td", " <td").replace("<TD", " <TD")
-        		.replace("<th", " <th").replace("<TH", " <TH");
-        Pattern p_html = Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE);
-        Matcher m_html = p_html.matcher(htmlStr);
-        htmlStr = m_html.replaceAll(""); //过滤html标签
-        
-        return htmlStr.trim();
-	}
 
+    private static final String COMMON_PROPERTIES = "common.properties";
+
+    private static final String[] CN_SMALL_NUM =
+            { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
+    private static final String[] CN_BIG_NUM =
+            { "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千" };
+
+
+    /**
+     * 加载properties配置文件
+     * @param propertiesPath
+     * @return
+     */
+    public static Properties loadProperties(String propertiesPath){
+        InputStream inputStream = null;
+        Properties properties = new Properties();
+        try {
+            inputStream = ClassLoader.getSystemResourceAsStream(propertiesPath);
+            BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream));
+            properties.load(bf);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return properties;
+    }
+
+    /**
+     * 记载通用配置文件
+     * @return
+     */
+    public static Properties loadCommonProperties(){
+        return loadProperties(COMMON_PROPERTIES);
+    }
+
+    /**
+     * 获取临时文件夹根路径
+     * @return
+     */
+    public static String getTmpRootPath(){
+        return (String)loadCommonProperties().get("tmp_root_path");
+    }
+
+    /**
+     * 获取当前日期字符串
+     * @return
+     */
+    public static String getCurDate(){
+        return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
+    }
+
+    /**
+     * 获取当前日期时间字符串
+     * @return
+     */
+    public static String getCurDateTime(){
+        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+    }
+
+    /**
+     * 根据枚举名称获取枚举
+     * @param clazz
+     * @param name
+     * @param <T>
+     * @return
+     */
+    public static <T> T getEnum(Class<T> clazz, String name){
+        T[] enumConstants = clazz.getEnumConstants();
+        for(T _enum : enumConstants){
+            if(_enum.toString().equals(name)){
+                return _enum;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 校验题型
+     * @param quesType
+     * @return
+     */
+    public static boolean checkQuesType(String quesType){
+        return Stream.of(QuesStructType.values()).
+                anyMatch(type -> type.getName().equals(quesType));
+    }
+
+    /**
+     * 获取中文数字
+     * @param inputNum
+     * @return
+     */
+    public static String toCHNum(int inputNum) {
+        String resultNum = "";
+        String numStr = String.valueOf(inputNum);
+        int len = numStr.length();
+        for (int i = 0; i < len; i++) {
+            int tmpNum = numStr.charAt(i) - '0';
+            if (i != len - 1 && tmpNum != 0) {
+                resultNum += CN_SMALL_NUM[tmpNum] + CN_BIG_NUM[len - 2 - i];
+            } else {
+                resultNum += CN_SMALL_NUM[tmpNum];
+            }
+        }
+        return resultNum;
+
+    }
+
+    public static void main(String[] args) {
+//        QuesStructType quesStructType = getEnum(QuesStructType.class,"单选");
+//        System.out.println(quesStructType.getName());
+        System.out.println(toCHNum(1));
+    }
 }

+ 35 - 35
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/enumeration/ExtractPolicy.java → cqb-comm-utils/src/main/java/com/qmth/cqb/utils/enums/ExtractPolicy.java

@@ -1,35 +1,35 @@
-package com.qmth.cqb.utils.enumeration;
-
-public enum ExtractPolicy {
-	
-	ExtractPolicy("RANDOM_PAPER","随机抽卷");
-	
-	private String key;
-	private String value;
-	
-	
-	
-	private ExtractPolicy(String key, String value) {
-		this.key = key;
-		this.value = value;
-	}
-	
-	private ExtractPolicy(){
-		
-	}
-	public String getKey() {
-		return key;
-	}
-	public void setKey(String key) {
-		this.key = key;
-	}
-	public String getValue() {
-		return value;
-	}
-	public void setValue(String value) {
-		this.value = value;
-	}
-	
-	
-
-}
+package com.qmth.cqb.utils.enums;
+
+public enum ExtractPolicy {
+	
+	ExtractPolicy("RANDOM_PAPER","随机抽卷");
+	
+	private String key;
+	private String value;
+	
+	
+	
+	private ExtractPolicy(String key, String value) {
+		this.key = key;
+		this.value = value;
+	}
+	
+	private ExtractPolicy(){
+		
+	}
+	public String getKey() {
+		return key;
+	}
+	public void setKey(String key) {
+		this.key = key;
+	}
+	public String getValue() {
+		return value;
+	}
+	public void setValue(String value) {
+		this.value = value;
+	}
+	
+	
+
+}

+ 65 - 53
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/enumeration/QuesStructType.java → cqb-comm-utils/src/main/java/com/qmth/cqb/utils/enums/QuesStructType.java

@@ -1,53 +1,65 @@
-package com.qmth.cqb.utils.enumeration;
-
-public enum QuesStructType {
-	
-	SINGLE_ANSWER_QUESTION(1L,"单选",true,false),
-	MULTIPLE_ANSWER_QUESTION(2L,"多选",true,false),
-	BOOL_ANSWER_QUESTION(3L,"判断",true,false),
-	FILL_BLANK_QUESTION(4L,"填空",false,false),
-	TEXT_ANSWER_QUESTION(5L,"问答",false,false),
-	NESTED_ANSWER_QUESTION(6L,"套题",false,true);
-	
-	private Long id;
-	private String name;
-	private boolean objective;//是否是客观题
-	private boolean combline;//是否是组合题
-		
-	private QuesStructType(Long id, String name, boolean objective, boolean combline) {
-		this.id = id;
-		this.name = name;;
-		this.objective = objective;
-		this.combline = combline;
-	}
-	
-	private QuesStructType(){
-		
-	}
-	public Long getId() {
-		return id;
-	}
-	public void setId(Long id) {
-		this.id = id;
-	}
-	public String getName() {
-		return name;
-	}
-	public void setName(String name) {
-		this.name = name;
-	}
-	public boolean isObjective() {
-		return objective;
-	}
-	public void setObjective(boolean objective) {
-		this.objective = objective;
-	}
-	public boolean isCombline() {
-		return combline;
-	}
-	public void setCombline(boolean combline) {
-		this.combline = combline;
-	}
-	
-}
-
+package com.qmth.cqb.utils.enums;
+
+public enum QuesStructType {
+	
+	SINGLE_ANSWER_QUESTION(1L,"单选",true,false),
+	MULTIPLE_ANSWER_QUESTION(2L,"多选",true,false),
+	BOOL_ANSWER_QUESTION(3L,"判断",true,false),
+	FILL_BLANK_QUESTION(4L,"填空",false,false),
+	TEXT_ANSWER_QUESTION(5L,"问答",false,false),
+	NESTED_ANSWER_QUESTION(6L,"套题",false,true);
+	
+	private Long id;
+	private String name;
+	private boolean objective;//是否是客观题
+	private boolean combline;//是否是组合题
+		
+	private QuesStructType(Long id, String name, boolean objective, boolean combline) {
+		this.id = id;
+		this.name = name;;
+		this.objective = objective;
+		this.combline = combline;
+	}
+	
+	private QuesStructType(){
+		
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public boolean isObjective() {
+		return objective;
+	}
+
+	public void setObjective(boolean objective) {
+		this.objective = objective;
+	}
+
+	public boolean isCombline() {
+		return combline;
+	}
+
+	public void setCombline(boolean combline) {
+		this.combline = combline;
+	}
+
+	public String toString(){
+		return getName();
+	}
+	
+}
+

+ 44 - 0
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/enums/QuesUnit.java

@@ -0,0 +1,44 @@
+package com.qmth.cqb.utils.enums;
+
+/**
+ * Created by songyue on 17/3/15.
+ */
+public enum QuesUnit {
+
+    QUES_BODY(1L,"题干"),
+    QUES_OPTION(2L,"选项"),
+    QUES_ANSWER(3L,"答案");
+
+
+    private Long id;
+    private String name;
+
+    private QuesUnit(Long id, String name) {
+        this.id = id;
+        this.name = name;;
+    }
+
+    private QuesUnit(){
+
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String toString(){
+        return getName();
+    }
+}

+ 734 - 0
cqb-comm-utils/src/main/java/com/qmth/cqb/utils/word/DocxProcessUtil.java

@@ -0,0 +1,734 @@
+package com.qmth.cqb.utils.word;
+
+import com.qmth.cqb.utils.CommonUtils;
+import com.qmth.cqb.utils.enums.QuesUnit;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import net.sf.saxon.TransformerFactoryImpl;
+import net.sourceforge.jeuclid.LayoutContext;
+import net.sourceforge.jeuclid.context.LayoutContextImpl;
+import net.sourceforge.jeuclid.context.StyleAttributeLayoutContext;
+import net.sourceforge.jeuclid.converter.Converter;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.docx4j.Docx4J;
+import org.docx4j.TraversalUtil;
+import org.docx4j.XmlUtils;
+import org.docx4j.convert.in.FlatOpcXmlImporter;
+import org.docx4j.convert.out.HTMLSettings;
+import org.docx4j.convert.out.common.preprocess.PartialDeepCopy;
+import org.docx4j.dml.CTBlip;
+import org.docx4j.dml.wordprocessingDrawing.Inline;
+import org.docx4j.finders.ClassFinder;
+import org.docx4j.jaxb.Context;
+import org.docx4j.math.CTOMath;
+import org.docx4j.openpackaging.exceptions.Docx4JException;
+import org.docx4j.openpackaging.io3.stores.PartStore;
+import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
+import org.docx4j.openpackaging.parts.Part;
+import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
+import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
+import org.docx4j.openpackaging.parts.relationships.Namespaces;
+import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
+import org.docx4j.relationships.Relationship;
+import org.docx4j.wml.*;
+import org.docx4j.wml.Text;
+import org.dom4j.Namespace;
+import org.dom4j.io.SAXReader;
+import org.jsoup.Jsoup;
+import org.jsoup.select.Elements;
+import org.xml.sax.InputSource;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.*;
+import java.util.*;
+
+/**
+ * docx处理工具类
+ * Created by songyue on 17/3/10.
+ */
+public final class DocxProcessUtil {
+
+    public static final LayoutContext IMG_LAYOUT = new StyleAttributeLayoutContext(
+            LayoutContextImpl.getDefaultLayoutContext(), "3em", java.awt.Color.BLACK);
+    public static final String IMG_OUT_TYPE = "image/png";
+    public static final String ENCODING = "utf-8";
+    public static final String BASE64_HEADER = "data:image/png;base64,";
+    public static final String TEMP_FILE_IMP = CommonUtils.getTmpRootPath()+"docxImport/";
+    public static final String TEMP_FILE_EXP = CommonUtils.getTmpRootPath()+"docxExport/";
+    public static final String OMML2MML_XSL="OMML2MML.XSL";
+    public static final String PAPER_TEMPLATE="paper_template.ftl";
+    public static final String ANSWER_TEMPLATE="answer_template.ftl";
+    public static final String DOCX_SUFFIX = ".docx";
+    public static final String XML_SUFFIX = ".xml";
+    public static final String BODY_HEADER ="<w:body xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">";
+    public static final String BODY_TAIL ="</w:body>";
+    public static final String REL_ID_HEADER="rld999999";
+
+    static{
+        init();
+    }
+
+    /**
+     * 初始化文件夹
+     */
+    private static void init(){
+        File temp_file_exp = new File(TEMP_FILE_EXP);
+        File temp_file_img = new File(TEMP_FILE_IMP);
+        //如果输出目标文件夹不存在,则创建
+        if (!temp_file_img.exists()){
+            temp_file_img.mkdirs();
+        }
+        if (!temp_file_exp.exists()){
+            temp_file_exp.mkdirs();
+        }
+    }
+
+    /**
+     * 获取段落的所有文本
+     * @param p
+     * @return
+     */
+    public static String getPText(P p){
+        String returnText = "";
+        List<Object> tList = getAllElementFromObject(p,Text.class);
+        for(Object obj:tList){
+            Text text = (Text)obj;
+            returnText += text.getValue();
+        }
+        return returnText.trim();
+    }
+
+    /**
+     * 校验段落中是否含有公式或图片
+     * @param p
+     * @return
+     */
+    public static boolean isNotText(P p){
+        List<Object> mathList = getAllElementFromObject(p,CTOMath.class);
+        List<Object> drawList = getAllElementFromObject(p,Drawing.class);
+        if(mathList.size() > 0 || drawList.size() > 0){
+            return true;
+        }else{
+            return false;
+        }
+    }
+
+    /**
+     * 获取文档包副本(去除段落)
+     * @param wordMLPackage
+     * @return
+     * @throws Exception
+     */
+    public static WordprocessingMLPackage getTmpPackage(WordprocessingMLPackage wordMLPackage)
+            throws Exception{
+        //添加关系样式信息
+        Set<String> relationshipTypes = new HashSet<String>();
+        relationshipTypes.add(wordMLPackage.getMainDocumentPart().getRelationshipType());
+        //深拷贝
+        WordprocessingMLPackage tmpWordMlPackage = (WordprocessingMLPackage)
+                PartialDeepCopy.process(wordMLPackage,relationshipTypes);
+        //移除所有段落
+        initTmpPackage(tmpWordMlPackage);
+
+        return tmpWordMlPackage;
+    }
+
+    /**
+     * 初始化文档包(去除所有段落)
+     * @param wordMLPackage
+     * @return
+     * @throws Exception
+     */
+    public static void initTmpPackage(WordprocessingMLPackage wordMLPackage)
+            throws Exception{
+        //移除所有段落
+        List<Object> contentList = wordMLPackage.getMainDocumentPart().getContent();
+        contentList.removeAll(contentList);
+    }
+
+    /**
+     * 获得段落wordml
+     * @param p
+     * @return
+     */
+    public static String getPWordMl(P p)throws Exception{
+        return XmlUtils.marshaltoString(p);
+    }
+
+    /**
+     * 转换wordMl为html
+     * @param wordMl
+     * @return
+     * @throws Exception
+     */
+    public static String docx2Html(String wordMl,WordprocessingMLPackage wordMLPackage)
+            throws Exception{
+
+        initTmpPackage(wordMLPackage);
+
+        //转换wordml为完整的package对象
+        MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
+        Object p = XmlUtils.unmarshalString(wordMl);
+
+        mdp.getContent().add(p);
+
+        //转换公式为图片
+        replaceMath2Image(wordMLPackage,(P)p);
+
+        //设置导出临时html参数
+        HTMLSettings htmlSettings = Docx4J.createHTMLSettings();
+        htmlSettings.setImageDirPath(TEMP_FILE_IMP + "_files");
+        htmlSettings.setImageTargetUri(TEMP_FILE_IMP.substring(TEMP_FILE_IMP.lastIndexOf("/")+1)
+                + "_files");
+        htmlSettings.setWmlPackage(wordMLPackage);
+        String tmpHtmlPath = TEMP_FILE_IMP + UUID.randomUUID().toString() + ".html";
+        File tmpHtml = new File(tmpHtmlPath);
+        OutputStream os = new java.io.FileOutputStream(tmpHtml);
+        Docx4J.toHTML(htmlSettings,os,Docx4J.FLAG_EXPORT_PREFER_XSL);
+        os.flush();
+
+        //格式化html代码
+        String htmlStr = formatHtmlByPath(tmpHtmlPath);
+
+        //删除临时html文件
+        FileUtils.deleteQuietly(tmpHtml);
+
+        return htmlStr;
+    }
+
+    /**
+     * 替换所有公式为图片
+     * @param wordMLPackage
+     * @throws Exception
+     */
+    public static void replaceAllMath2Image(WordprocessingMLPackage wordMLPackage) throws Exception{
+        List<Object> pList = getAllElementFromObject(wordMLPackage.getMainDocumentPart(), P.class);
+        for (Object pObject : pList) {
+            P p=(P) pObject;
+            List<Object> pContent = p.getContent();
+            int index = 0;
+            for(Object child:pContent){
+                if(child instanceof ContentAccessor){
+                    index++;
+                    continue;
+                }
+                if (child instanceof JAXBElement) child = ((JAXBElement<?>)child).getValue();
+                if (child.getClass().equals(CTOMath.class)) {
+                    String omml = XmlUtils.marshaltoString(child, true, true,
+                            Context.jc,
+                            "http://schemas.openxmlformats.org/officeDocument/2006/math",
+                            "oMath", CTOMath.class);
+                    byte [] imgByte = convertMathml2Img(omml2mml(omml));
+                    pContent.set(index,
+                            newImage( wordMLPackage, imgByte, "math"+(index), "math"+(index)));
+                }
+                index++;
+            }
+        }
+    }
+
+    /**
+     * 替换公式为图片
+     * @param p
+     * @throws Exception
+     */
+    public static void replaceMath2Image(WordprocessingMLPackage wordMLPackage,P p) throws Exception{
+        List<Object> pContent = p.getContent();
+        int index = 0;
+        for(Object child:pContent){
+            if(child instanceof ContentAccessor){
+                index++;
+                continue;
+            }
+            if (child instanceof JAXBElement) child = ((JAXBElement<?>)child).getValue();
+            if (child.getClass().equals(CTOMath.class)) {
+                String omml = XmlUtils.marshaltoString(child, true, true,
+                        Context.jc,
+                        "http://schemas.openxmlformats.org/officeDocument/2006/math",
+                        "oMath", CTOMath.class);
+                byte [] imgByte = convertMathml2Img(omml2mml(omml));
+                pContent.set(index,
+                        newImage( wordMLPackage, imgByte, "math"+(index), "math"+(index)));
+            }
+            index++;
+        }
+    }
+
+    /**
+     * 创建新图片
+     * @param wordMLPackage
+     * @param bytes
+     * @param filenameHint
+     * @param altText
+     * @return
+     * @throws Exception
+     */
+    public static R newImage(WordprocessingMLPackage wordMLPackage,
+                             byte[] bytes,
+                             String filenameHint, String altText) throws Exception {
+        int id1=(int) ((Math.random()*1000)*(Math.random()*1000));
+        int id2=(int) ((Math.random()*1000)*(Math.random()*1000));
+
+        BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.
+                createImagePart(wordMLPackage,bytes);
+
+        Inline inline = imagePart.createImageInline(filenameHint, altText, id1, id2, false);
+
+        ObjectFactory factory = Context.getWmlObjectFactory();
+        R run = factory.createR();
+        Drawing drawing = factory.createDrawing();
+        run.getContent().add(drawing);
+        drawing.getAnchorOrInline().add(inline);
+        bytes = null;
+        imagePart = null;
+        return run;
+
+    }
+
+    /**
+     * 获取wordMl固定节点下所有子节点
+     * @param obj
+     * @param toSearch
+     * @return
+     */
+    public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
+
+        List<Object> result = new ArrayList<Object>();
+        if (obj instanceof JAXBElement) obj = ((JAXBElement<?>) obj).getValue();
+        if (obj.getClass().equals(toSearch))
+            result.add(obj);
+        else if (obj instanceof ContentAccessor) {
+            List<?> children = ((ContentAccessor) obj).getContent();
+            for (Object child : children) {
+                result.addAll(getAllElementFromObject(child, toSearch));
+            }
+        }
+        return result;
+    }
+
+    /**
+     * omml转换成mml
+     * @param omml
+     * @return
+     */
+    public static String omml2mml(String omml){
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        InputStream stylesheet = ClassLoader.getSystemResourceAsStream(OMML2MML_XSL);
+        StringReader sr = new StringReader(omml);
+        InputSource ommldata = new InputSource(sr);
+        StringWriter writer = new StringWriter();
+        org.w3c.dom.Document document = null;
+        DocumentBuilder builder = null;
+        Transformer transformer = null;
+        try {
+            builder = factory.newDocumentBuilder();
+            document = builder.parse(ommldata);
+            TransformerFactory tFactory = new TransformerFactoryImpl();
+            StreamSource stylesource = new StreamSource(stylesheet);
+            transformer = tFactory.newTransformer(stylesource);
+            DOMSource source = new DOMSource(document);
+            StreamResult result = new StreamResult(writer);
+            transformer.transform(source, result);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally{
+            IOUtils.closeQuietly(sr);
+            IOUtils.closeQuietly(writer);
+        }
+        String mml = writer.toString();
+        mml = ("<mml:math" + StringUtils.substringAfter(mml, "<mml:math")).replace("mml:", "");
+        return mml;
+    }
+
+    /**
+     * 格式化转换后的html(html字符串)
+     * @param htmlStr
+     * @return
+     */
+    public static String formatHtml(String htmlStr){
+        try{
+            org.jsoup.nodes.Document doc = Jsoup.parse(htmlStr);
+            Elements divs = doc.select("div[class='document");
+            doc.select("p").removeAttr("class").removeAttr("style");
+            doc.select("div").removeAttr("class").removeAttr("style");
+            doc.select("span").removeAttr("class").removeAttr("style");
+            doc.select("span").stream().forEach(element -> {
+                if(!element.hasText())element.remove();});
+            if(divs.size() > 0){
+                htmlStr = divs.html();
+            }else{
+                htmlStr = doc.html();
+            }
+            return htmlStr;
+        }catch(Exception e){
+            e.printStackTrace();
+        }
+        return htmlStr;
+    }
+
+    /**
+     * 格式化转换后的html(html临时文件)
+     * @param htmlPath
+     * @return
+     */
+    public static String formatHtmlByPath(String htmlPath){
+        String htmlStr = "";
+        File htmlFile;
+        try{
+            htmlFile = new File(htmlPath);
+            org.jsoup.nodes.Document doc = Jsoup.parse(htmlFile,ENCODING);
+            Elements divs = doc.select("div[class='document']");
+            doc.select("p").removeAttr("class").removeAttr("style");
+            doc.select("div").removeAttr("class").removeAttr("style");
+            doc.select("span").removeAttr("class").removeAttr("style");
+            doc.select("span").stream().forEach(element -> {
+                if(!element.hasText())element.remove();});
+            Elements imgs = doc.select("img");
+            for(org.jsoup.nodes.Element img:imgs){
+                String imgSrc = img.attr("src");
+                if(!StringUtils.isEmpty(imgSrc)){
+                    String imgBase64 = new String(getBase64ByPath(htmlFile.getParent()+"/"+imgSrc));
+                    img.attr("src",BASE64_HEADER+imgBase64);
+                }
+            }
+            if(divs.size() > 0){
+                htmlStr = divs.html();
+            }else{
+                htmlStr = doc.html();
+            }
+            return htmlStr;
+        }catch(Exception e){
+            e.printStackTrace();
+        }
+        return htmlStr;
+    }
+
+    /**
+     * 转换mathml为png图片
+     * @param mathMlStr
+     * @return
+     */
+    public static byte[] convertMathml2Img(String mathMlStr){
+        File xmlFile = null;
+        File imgFile = null;
+        FileOutputStream xmlFos = null;
+        byte[] base64Byte = new byte[0];
+        try {
+            xmlFile = new File(TEMP_FILE_IMP,UUID.randomUUID().toString());
+            imgFile = new File(TEMP_FILE_IMP,UUID.randomUUID().toString());
+            xmlFos = new FileOutputStream(xmlFile);
+            IOUtils.write(mathMlStr, xmlFos, ENCODING);
+            xmlFos.flush();
+            Converter.getInstance().convert(xmlFile, imgFile, IMG_OUT_TYPE, IMG_LAYOUT);
+            base64Byte = IOUtils.toByteArray(new FileInputStream(imgFile));
+        } catch(Exception e) {
+            e.printStackTrace();
+        } finally {
+            IOUtils.closeQuietly(xmlFos);
+            FileUtils.deleteQuietly(xmlFile);
+            FileUtils.deleteQuietly(imgFile);
+        }
+        return base64Byte;
+    }
+
+    /**
+     * 通过图片路径获取base64码
+     * @param imgFilePath
+     * @return
+     */
+    public static byte[] getBase64ByPath(String imgFilePath){
+        InputStream is = null;
+        byte[] base64Byte = new byte[0];
+        byte[] imgByte;
+        try {
+            is = new FileInputStream(new File(imgFilePath));
+            imgByte = IOUtils.toByteArray(is);
+            base64Byte = Base64.encodeBase64(imgByte);
+        }catch(Exception e) {
+            e.printStackTrace();
+        }finally {
+            IOUtils.closeQuietly(is);
+        }
+        return base64Byte;
+    }
+
+    /**
+     * 通过图片文件获取base64码
+     * @param imgFile
+     * @return
+     */
+    public static byte[] getBase64ByFile(File imgFile){
+        InputStream is = null;
+        byte[] base64Byte = new byte[0];
+        byte[] imgByte;
+        try {
+            is = new FileInputStream(imgFile);
+            imgByte = IOUtils.toByteArray(is);
+            base64Byte = Base64.encodeBase64(imgByte);
+        }catch(Exception e) {
+            e.printStackTrace();
+        }finally {
+            IOUtils.closeQuietly(is);
+        }
+        return base64Byte;
+    }
+
+    /**
+     * 格式化段落wordml
+     * @param pWordMl
+     * @return
+     * @throws Exception
+     */
+    public static String formatPWordMl(String pWordMl) throws Exception{
+        String tmpWordMl = pWordMl.replaceAll("\\\\\"","\"");
+        SAXReader sax = new SAXReader();
+        ByteArrayInputStream is = new ByteArrayInputStream(tmpWordMl.getBytes("UTF-8"));
+        org.dom4j.Document document = sax.read(is);
+        org.dom4j.Element root = document.getRootElement();
+        List<Namespace> namespaces = root.additionalNamespaces();
+        namespaces.stream().forEach(namespace -> {root.remove(namespace);});
+        return root.asXML();
+    }
+
+    /**
+     * 过滤试题单元标题
+     * @param p
+     * @param quesUnit
+     * @return
+     */
+    public static P formatP(P p, QuesUnit quesUnit){
+        List<Object> pContent = p.getContent();
+        int index = 0;
+
+        for(Object child:pContent) {
+            if(child.getClass().equals(R.class)){
+
+                R r = (R)child;
+                List<Object> rContent = r.getContent();
+
+                for(Object rChild:rContent){
+
+                    rChild = ((JAXBElement<?>)rChild).getValue();
+
+                    if(rChild.getClass().equals(Text.class)){
+                        ++index;
+                        Text text = (Text)rChild;
+                        String tmpText = text.getValue();
+                        if(quesUnit == QuesUnit.QUES_BODY){
+                            //过滤题干标题
+                            if(tmpText.matches("^\\d{1,}\\.[\\s\\S]*")){
+                                tmpText = tmpText.replaceFirst("\\d{1,}\\.","");
+                                text.setValue(tmpText);
+                            }else{
+                                tmpText = tmpText.replaceFirst("\\d{1,}","").replaceFirst("\\.","");
+                                text.setValue(tmpText);
+                                if(index == 2)break;
+                            }
+
+                        }else if(quesUnit == QuesUnit.QUES_OPTION){
+                            //过滤选项标题
+                            if(tmpText.matches("^[a-zA-Z]\\.[\\s\\S]*")){
+                                tmpText = tmpText.replaceFirst("[a-zA-Z]\\.","");
+                                text.setValue(tmpText);
+                            }else{
+                                tmpText = tmpText.replaceFirst("[a-zA-Z]","").replaceFirst("\\.","");
+                                text.setValue(tmpText);
+                                if(index == 2)break;
+                            }
+
+                        }else if(quesUnit == QuesUnit.QUES_ANSWER){
+                            //过滤答案标题
+                            if(index < 4){
+                                tmpText = tmpText.replaceFirst("\\[|\\]","").replaceFirst("答案","");
+                            }else{
+                                tmpText = tmpText.replaceFirst("[:|:]","");
+                            }
+                            text.setValue(tmpText);
+                            if(index == 4)break;
+                        }
+                    }
+                }
+            }
+
+        }
+        return p;
+    }
+
+    /**
+     * 导出word
+     * @param dataMap
+     * @param fileName
+     */
+    public static void exportWord(Map dataMap,String fileName,String templatePath){
+        Writer out = null;
+        try {
+            //创建配置实例
+            Configuration configuration = new Configuration(Configuration.VERSION_2_3_25);
+            //设置编码
+            configuration.setDefaultEncoding("UTF-8");
+            //设置ftl模板路径
+            configuration.setClassForTemplateLoading(DocxProcessUtil.class,"/");
+            //获取模板
+            Template template = configuration.getTemplate(templatePath,ENCODING);
+            //输出文件
+            File outFile = new File(TEMP_FILE_EXP+fileName+DOCX_SUFFIX);
+
+            //将模板和数据模型合并生成文件
+            out = new BufferedWriter(new OutputStreamWriter
+                    (new FileOutputStream(outFile),ENCODING));
+            //生成文件
+            template.process(dataMap, out);
+
+            out.flush();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }finally {
+            IOUtils.closeQuietly(out);
+        }
+    }
+
+    /**
+     * 导出试卷
+     * @param dataMap
+     * @param fileName
+     */
+    public static void exportPaper(Map dataMap,String fileName){
+        exportWord(dataMap,fileName,PAPER_TEMPLATE);
+    }
+
+    /**
+     * 导出答案
+     * @param dataMap
+     * @param fileName
+     */
+    public static void exportAnswer(Map dataMap,String fileName){
+        exportWord(dataMap,fileName,ANSWER_TEMPLATE);
+    }
+
+    /**
+     * 处理导出word中的图片
+     * @param fileName
+     * @param wordMLPackages
+     * @throws Exception
+     */
+    public static void processImage(String fileName,
+                                    List<WordprocessingMLPackage> wordMLPackages)
+            throws Exception{
+
+        String filePath = TEMP_FILE_EXP+fileName+DOCX_SUFFIX;
+        InputStream mainFile = new FileInputStream(filePath);
+        //以单个wordXml方式解析freemarker导出的文件
+        FlatOpcXmlImporter flatOpcXmlImporter = new FlatOpcXmlImporter(mainFile);
+        WordprocessingMLPackage wordMLPackage = (WordprocessingMLPackage) flatOpcXmlImporter.get();
+
+        for(WordprocessingMLPackage wp:wordMLPackages){
+            //获取资源文件存储
+            PartStore partStore = wp.getSourcePartStore();
+            //获取图片资源定义
+            RelationshipsPart rp = wp.getMainDocumentPart().getRelationshipsPart();
+            List<Relationship> rels = rp.getRelationshipsByType(Namespaces.IMAGE);
+
+            List<Part> parts = new ArrayList<Part>();
+            for(Relationship relationship:rels){
+                parts.add(rp.getPart(relationship));
+            }
+            //添加资源文件存储
+            wordMLPackage.setSourcePartStore(partStore);
+            //添加资源文件定义
+            for(Part p:parts){
+                wordMLPackage.getMainDocumentPart().addTargetPart(p,
+                                      RelationshipsPart.AddPartBehaviour.OVERWRITE_IF_NAME_EXISTS,
+                                      p.getSourceRelationship().getId());
+            }
+        }
+        //以word2007标准模式重新保存(zip包)
+        OutputStream os = new java.io.FileOutputStream(filePath);
+        Docx4J.save(wordMLPackage,os,Docx4J.FLAG_SAVE_ZIP_FILE);
+        IOUtils.closeQuietly(os);
+    }
+
+    /**
+     * 获取word二进制数据(空文档,只有样式和资源)
+     * @param wordMLPackage
+     * @return
+     * @throws Exception
+     */
+    public static byte[] getPkgByte(WordprocessingMLPackage wordMLPackage) throws Exception {
+
+        DocxProcessUtil.initTmpPackage(wordMLPackage);
+
+        File tmpFile = new File(DocxProcessUtil.TEMP_FILE_IMP
+                + UUID.randomUUID().toString());
+        OutputStream outputStream = new FileOutputStream(tmpFile);
+        Docx4J.save(wordMLPackage,outputStream);
+
+        InputStream inputStream = new FileInputStream(tmpFile);
+        byte[] bytes = IOUtils.toByteArray(inputStream);
+
+        outputStream.flush();
+        IOUtils.closeQuietly(outputStream);
+        IOUtils.closeQuietly(inputStream);
+        FileUtils.deleteQuietly(tmpFile);
+
+        return bytes;
+    }
+
+    /**
+     * 通过二进制流获取word文档包
+     * @param bytes
+     * @return
+     */
+    public static WordprocessingMLPackage getPkg(byte [] bytes){
+        InputStream inputStream = new ByteArrayInputStream(bytes);
+        WordprocessingMLPackage wordMLPackage = null;
+        try {
+            wordMLPackage = Docx4J.load(inputStream);
+        } catch (Docx4JException e) {
+            e.printStackTrace();
+        }
+        return wordMLPackage;
+    }
+
+    /**
+     * 初始化word文档图片资源路径,防止导出试卷时资源ID冲突
+     * @param wordMLPackage
+     */
+    public static void initPkgImage(WordprocessingMLPackage wordMLPackage){
+        //获取文档中所有图片引用位置
+        ClassFinder finder = new ClassFinder(CTBlip.class);
+        new TraversalUtil(wordMLPackage.getMainDocumentPart().getContent(), finder);
+        List<Object> blips = finder.results;
+        //获取文档中所有图片引用定义
+        List<Relationship> relationships =
+                wordMLPackage.getMainDocumentPart()
+                        .getRelationshipsPart().getRelationshipsByType(Namespaces.IMAGE);
+        //同步替换资源ID
+        int index = 0;
+        for(Relationship relationship:relationships){
+            String tmpId = relationship.getId();
+            for(Object obj:blips){
+                if(obj.getClass().equals(CTBlip.class)){
+                    CTBlip ctBlip = (CTBlip)obj;
+                    String tmpEmbed = ctBlip.getEmbed();
+                    if(tmpId.equals(tmpEmbed)){
+                        String tmp = REL_ID_HEADER+(++index);
+                        relationship.setId(tmp);
+                        ctBlip.setEmbed(tmp);
+                    }
+                }
+            }
+        }
+    }
+
+}

+ 3822 - 0
cqb-comm-utils/src/main/resources/MML2OMML.XSL

@@ -0,0 +1,3822 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mml="http://www.w3.org/1998/Math/MathML"
+	xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
+  <xsl:output method="xml" encoding="UTF-8" />
+
+
+  <xsl:variable name="StrUCAlphabet">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
+  <xsl:variable name="StrLCAlphabet">abcdefghijklmnopqrstuvwxyz</xsl:variable>
+
+  <!-- %%Template: match *
+
+		The catch all template, just passes through 
+	-->
+  <xsl:template match="*">
+    <xsl:apply-templates select="*" />
+  </xsl:template>
+
+  <!-- %%Template: match *
+
+		Another catch all template, just passes through 
+	-->
+  <xsl:template match="/">
+    <m:oMath>
+      <xsl:apply-templates select="*" />
+    </m:oMath>
+  </xsl:template>
+
+  <!-- %%Template: SReplace
+
+		Replace all occurences of sOrig in sInput with sReplacement
+		and return the resulting string. -->
+  <xsl:template name="SReplace">
+    <xsl:param name="sInput" />
+    <xsl:param name="sOrig" />
+    <xsl:param name="sReplacement" />
+
+    <xsl:choose>
+      <xsl:when test="not(contains($sInput, $sOrig))">
+        <xsl:value-of select="$sInput" />
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="sBefore" select="substring-before($sInput, $sOrig)" />
+        <xsl:variable name="sAfter" select="substring-after($sInput, $sOrig)" />
+        <xsl:variable name="sAfterProcessed">
+          <xsl:call-template name="SReplace">
+            <xsl:with-param name="sInput" select="$sAfter" />
+            <xsl:with-param name="sOrig" select="$sOrig" />
+            <xsl:with-param name="sReplacement" select="$sReplacement" />
+          </xsl:call-template>
+        </xsl:variable>
+
+        <xsl:value-of select="concat($sBefore, concat($sReplacement, $sAfterProcessed))" />
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: OutputText
+
+		Post processing on the string given and otherwise do
+		a xsl:value-of on it -->
+  <xsl:template name="OutputText">
+    <xsl:param name="sInput" />
+
+    <!-- Add local variable as you add new post processing tasks -->
+
+    <!-- 1. Remove any unwanted characters -->
+    <xsl:variable name="sCharStrip">
+      <xsl:value-of select="translate($sInput, '&#x2062;&#x200B;', '')" />
+    </xsl:variable>
+
+    <!-- 2. Replace any characters as needed -->
+    <!--	Replace &#x2A75; <-> ==			 -->
+    <xsl:variable name="sCharReplace">
+      <xsl:call-template name="SReplace">
+        <xsl:with-param name="sInput" select="$sCharStrip" />
+        <xsl:with-param name="sOrig" select="'&#x2A75;'" />
+        <xsl:with-param name="sReplacement" select="'=='" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <!-- Replace &#xa0; (non-breaking space) with ' ' -->
+    <xsl:variable name="sCharReplaceFinal" select="translate($sCharReplace, '&#xa0;', ' ')" />
+
+    <!-- Finally, return the last value -->
+    <xsl:value-of select="$sCharReplaceFinal" />
+  </xsl:template>
+
+
+  <!-- Template that determines whether or the given node 
+	     ndCur is a token element that doesn't have an mglyph as 
+			 a child.
+	-->
+  <xsl:template name="FNonGlyphToken">
+    <xsl:param name="ndCur" select="." />
+    <xsl:choose>
+      <xsl:when test="$ndCur/self::mml:mi[not(child::mml:mglyph)] | 
+	                     $ndCur/self::mml:mn[not(child::mml:mglyph)] | 
+	                     $ndCur/self::mml:mo[not(child::mml:mglyph)] | 
+	                     $ndCur/self::mml:ms[not(child::mml:mglyph)] |
+                       $ndCur/self::mml:mtext[not(child::mml:mglyph)]">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- Template used to determine if the current token element (ndCur) is the beginning of a run. 
+			 A token element is the beginning of if:
+			 
+			 the count of preceding elements is 0 
+			 or 
+			 the directory preceding element is not a non-glyph token.
+	-->
+  <xsl:template name="FStartOfRun">
+    <xsl:param name="ndCur" select="." />
+    <xsl:variable name="fPrecSibNonGlyphToken">
+      <xsl:call-template name="FNonGlyphToken">
+        <xsl:with-param name="ndCur" select="$ndCur/preceding-sibling::*[1]" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="count($ndCur/preceding-sibling::*)=0 
+											or $fPrecSibNonGlyphToken=0">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Template that determines if ndCur is the argument of an nary expression. 
+			 
+			 ndCur is the argument of an nary expression if:
+			 
+			 1.  The preceding sibling is one of the following:  munder, mover, msub, msup, munder, msubsup, munderover
+			 and
+			 2.  The preceding sibling's child is an nary char as specified by the template "isNary"
+	-->
+  <xsl:template name="FIsNaryArgument">
+    <xsl:param name="ndCur" select="." />
+
+    <xsl:variable name="fNary">
+      <xsl:call-template name="isNary">
+        <xsl:with-param name="ndCur" select="$ndCur/preceding-sibling::*[1]/child::*[1]" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="preceding-sibling::*[1][self::mml:munder or self::mml:mover or self::mml:munderover or
+                                                    self::mml:msub or self::mml:msup or self::mml:msubsup]
+							      and $fNary='true'">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: mml:mrow | mml:mstyle
+
+		 if this row is the next sibling of an n-ary (i.e. any of 
+         mover, munder, munderover, msupsub, msup, or msub with 
+         the base being an n-ary operator) then ignore this. Otherwise
+         pass through -->
+  <xsl:template match="mml:mrow|mml:mstyle">
+    <xsl:variable name="fNaryArgument">
+      <xsl:call-template name="FIsNaryArgument">
+        <xsl:with-param name="ndCur" select="."/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:if test="$fNaryArgument=0">
+      <xsl:variable name="fLinearFrac">
+        <xsl:call-template name="FLinearFrac">
+          <xsl:with-param name="ndCur" select="." />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="$fLinearFrac=1">
+          <xsl:call-template name="MakeLinearFraction">
+            <xsl:with-param name="ndCur" select="." />
+          </xsl:call-template>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:variable name="fFunc">
+            <xsl:call-template name="FIsFunc">
+              <xsl:with-param name="ndCur" select="." />
+            </xsl:call-template>
+          </xsl:variable>
+          <xsl:choose>
+            <xsl:when test="$fFunc=1">
+              <xsl:call-template name="WriteFunc">
+                <xsl:with-param name="ndCur" select="." />
+              </xsl:call-template>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:apply-templates select="*" />
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:if>
+  </xsl:template>
+  <xsl:template match="mml:mi[not(child::mml:mglyph)] | 
+	                     mml:mn[not(child::mml:mglyph)] | 
+	                     mml:mo[not(child::mml:mglyph)] | 
+	                     mml:ms[not(child::mml:mglyph)] |
+                       mml:mtext[not(child::mml:mglyph)]">
+
+    <!-- tokens with mglyphs as children are tranformed
+			 in a different manner than "normal" token elements.  
+			 Where normal token elements are token elements that
+			 contain only text -->
+    <xsl:variable name="fStartOfRun">
+      <xsl:call-template name="FStartOfRun">
+        <xsl:with-param name="ndCur" select="." />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <!--In MathML, successive characters that are all part of one string are sometimes listed as separate 
+			tags based on their type (identifier (mi), name (mn), operator (mo), quoted (ms), literal text (mtext)), 
+			where said tags act to link one another into one logical run.  In order to wrap the text of successive mi's, 
+			mn's, and mo's into one m:t, we need to denote where a run begins.  The beginning of a run is the first mi, mn, 
+			or mo whose immediately preceding sibling either doesn't exist or is something other than a "normal" mi, mn, mo, 
+			ms, or mtext tag-->
+
+    <!-- If this mi/mo/mn/ms . . . is part the numerator or denominator of a linear fraction, then don't collect. -->
+    <xsl:variable name="fLinearFracParent">
+      <xsl:call-template name="FLinearFrac">
+        <xsl:with-param name="ndCur" select="parent::*" />
+      </xsl:call-template>
+    </xsl:variable>
+    <!-- If this mi/mo/mn/ms . . . is part of the name of a function, then don't collect. -->
+    <xsl:variable name="fFunctionName">
+      <xsl:call-template name="FIsFunc">
+        <xsl:with-param name="ndCur" select="parent::*" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="fShouldCollect"
+					select="($fLinearFracParent=0 and $fFunctionName=0) and (parent::mml:mrow or parent::mml:mstyle or 
+					parent::mml:msqrt or parent::mml:menclose or
+					parent::mml:math or parent::mml:mphantom or 
+					parent::mml:mtd or parent::mml:maction)" />
+
+    <!--In MathML, the meaning of the different parts that make up mathematical structures, such as a fraction 
+			having a numerator and a denominator, is determined by the relative order of those different parts.  
+			For instance, In a fraction, the numerator is the first child and the denominator is the second child.  
+			To allow for more complex structures, MathML allows one to link a group of mi, mn, and mo's together 
+			using the mrow, or mstyle tags.  The mi, mn, and mo's found within any of the above tags are considered 
+			one run.  Therefore, if the parent of any mi, mn, or mo is found to be an mrow or mstyle, then the contiguous 
+			mi, mn, and mo's will be considered one run.-->
+    <xsl:choose>
+      <xsl:when test="$fShouldCollect">
+        <xsl:choose>
+          <xsl:when test="$fStartOfRun=1">
+            <!--If this is the beginning of the run, pass all run attributes to CreateRunWithSameProp.-->
+            <xsl:call-template name="CreateRunWithSameProp">
+              <xsl:with-param name="mathbackground">
+                <!-- Look for the unqualified mathml attribute mathbackground.
+										 Fall back to the qualified mathml attribute if necessary.
+										 This priority of unqualified over qualified will be 
+										 followed throughout this xslt. -->
+                <xsl:choose>
+                  <xsl:when test="@mathbackground">
+                    <xsl:value-of select="@mathbackground"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:mathbackground"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="mathcolor">
+                <xsl:choose>
+                  <xsl:when test="@mathcolor">
+                    <xsl:value-of select="@mathcolor"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:mathcolor"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="mathvariant">
+                <xsl:choose>
+                  <xsl:when test="@mathvariant">
+                    <xsl:value-of select="@mathvariant"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:mathvariant"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="color">
+                <xsl:choose>
+                  <xsl:when test="@color">
+                    <xsl:value-of select="@color"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:color"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="font-family">
+                <xsl:choose>
+                  <xsl:when test="@font-family">
+                    <xsl:value-of select="@font-family"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:font-family"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="fontsize">
+                <xsl:choose>
+                  <xsl:when test="@fontsize">
+                    <xsl:value-of select="@fontsize"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:fontsize"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="fontstyle">
+                <xsl:choose>
+                  <xsl:when test="@fontstyle">
+                    <xsl:value-of select="@fontstyle"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:fontstyle"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="fontweight">
+                <xsl:choose>
+                  <xsl:when test="@fontweight">
+                    <xsl:value-of select="@fontweight"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:fontweight"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="mathsize">
+                <xsl:choose>
+                  <xsl:when test="@mathsize">
+                    <xsl:value-of select="@mathsize"/>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="@mml:mathsize"/>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:with-param>
+              <xsl:with-param name="ndTokenFirst" select="." />
+            </xsl:call-template>
+          </xsl:when>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+        <!--Only one element will be part of run-->
+        <xsl:element name="m:r">
+          <!--Create Run Properties based on current node's attributes-->
+          <xsl:call-template name="CreateRunProp">
+            <xsl:with-param name="mathvariant">
+              <xsl:choose>
+                <xsl:when test="@mathvariant">
+                  <xsl:value-of select="@mathvariant"/>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="@mml:mathvariant"/>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+            <xsl:with-param name="fontstyle">
+              <xsl:choose>
+                <xsl:when test="@fontstyle">
+                  <xsl:value-of select="@fontstyle"/>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="@mml:fontstyle"/>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+            <xsl:with-param name="fontweight">
+              <xsl:choose>
+                <xsl:when test="@fontweight">
+                  <xsl:value-of select="@fontweight"/>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="@mml:fontweight"/>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+            <xsl:with-param name="mathcolor">
+              <xsl:choose>
+                <xsl:when test="@mathcolor">
+                  <xsl:value-of select="@mathcolor"/>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="@mml:mathcolor"/>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+            <xsl:with-param name="mathsize">
+              <xsl:choose>
+                <xsl:when test="@mathsize">
+                  <xsl:value-of select="@mathsize"/>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="@mml:mathsize"/>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+            <xsl:with-param name="color">
+              <xsl:choose>
+                <xsl:when test="@color">
+                  <xsl:value-of select="@color"/>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="@mml:color"/>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+            <xsl:with-param name="fontsize">
+              <xsl:choose>
+                <xsl:when test="@fontsize">
+                  <xsl:value-of select="@fontsize"/>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="@mml:fontsize"/>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+            <xsl:with-param name="ndCur" select="." />
+            <xsl:with-param name="fNor">
+              <xsl:call-template name="FNor">
+                <xsl:with-param name="ndCur" select="." />
+              </xsl:call-template>
+            </xsl:with-param>
+          </xsl:call-template>
+          <xsl:element name="m:t">
+            <xsl:call-template name="OutputText">
+              <xsl:with-param name="sInput" select="normalize-space(.)" />
+            </xsl:call-template>
+          </xsl:element>
+        </xsl:element>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: CreateRunWithSameProp
+	-->
+  <xsl:template name="CreateRunWithSameProp">
+    <xsl:param name="mathbackground" />
+    <xsl:param name="mathcolor" />
+    <xsl:param name="mathvariant" />
+    <xsl:param name="color" />
+    <xsl:param name="font-family" />
+    <xsl:param name="fontsize" />
+    <xsl:param name="fontstyle" />
+    <xsl:param name="fontweight" />
+    <xsl:param name="mathsize" />
+    <xsl:param name="ndTokenFirst" />
+
+    <!--Given mathcolor, color, mstyle's (ancestor) color, and precedence of 
+			said attributes, determine the actual color of the current run-->
+    <xsl:variable name="sColorPropCur">
+      <xsl:choose>
+        <xsl:when test="$mathcolor!=''">
+          <xsl:value-of select="$mathcolor" />
+        </xsl:when>
+        <xsl:when test="$color!=''">
+          <xsl:value-of select="$color" />
+        </xsl:when>
+        <xsl:when test="$ndTokenFirst/ancestor::mml:mstyle[@color][1]/@color!=''">
+          <xsl:value-of select="$ndTokenFirst/ancestor::mml:mstyle[@color][1]/@color" />
+        </xsl:when>
+        <xsl:when test="$ndTokenFirst/ancestor::mml:mstyle[@mml:color][1]/@mml:color!=''">
+          <xsl:value-of select="$ndTokenFirst/ancestor::mml:mstyle[@color][1]/@mml:color" />
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="''" />
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <!--Given mathsize, and fontsize and precedence of said attributes, 
+			determine the actual font size of the current run-->
+    <xsl:variable name="sSzCur">
+      <xsl:choose>
+        <xsl:when test="$mathsize!=''">
+          <xsl:value-of select="$mathsize" />
+        </xsl:when>
+        <xsl:when test="$fontsize!=''">
+          <xsl:value-of select="$fontsize" />
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="''" />
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <!--Given mathvariant, fontstyle, and fontweight, and precedence of 
+			the attributes, determine the actual font of the current run-->
+    <xsl:variable name="sFontCur">
+      <xsl:call-template name="GetFontCur">
+        <xsl:with-param name="mathvariant" select="$mathvariant" />
+        <xsl:with-param name="fontstyle" select="$fontstyle" />
+        <xsl:with-param name="fontweight" select="$fontweight" />
+        <xsl:with-param name="ndCur" select="$ndTokenFirst" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <!-- The omml equivalent structure for mml:mtext is an omml run with the run property m:nor (normal) set.
+         Therefore, we can only collect mtexts with  other mtext elements.  Suppose the $ndTokenFirst is an 
+         mml:mtext, then if any of its following siblings are to be grouped, they must also be mml:text elements.  
+         The inverse is also true, suppose the $ndTokenFirst isn't an mml:mtext, then if any of its following siblings 
+         are to be grouped with $ndTokenFirst, they can't be mml:mtext elements-->
+    <xsl:variable name="fNdTokenFirstIsMText">
+      <xsl:choose>
+        <xsl:when test="$ndTokenFirst/self::mml:mtext">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <!--In order to determine the length of the run, we will find the number of nodes before the inital node in the run and
+			the number of nodes before the first node that DOES NOT belong to the current run.  The number of nodes that will
+			be printed is One Less than the difference between the latter and the former-->
+
+    <!--Find index of current node-->
+    <xsl:variable name="nndBeforeFirst" select="count($ndTokenFirst/preceding-sibling::*)" />
+
+    <!--Find index of next change in run properties.
+		
+		    The basic idea is that we want to find the position of the last node in the longest 
+				sequence of nodes, starting from ndTokenFirst, that can be grouped into a run.  For
+				example, nodes A and B can be grouped together into the same run iff they have the same 
+				props.
+				
+				To accomplish this grouping, we want to find the next sibling to ndTokenFirst that shouldn't be 
+				included in the run of text.  We do this by counting the number of elements that precede the first
+				such element that doesn't belong.  The xpath that accomplishes this is below.
+				    
+						Count the number of siblings the precede the first element after ndTokenFirst that shouldn't belong.
+						count($ndTokenFirst/following-sibling::*[ . . . ][1]/preceding-sibling::*)
+						
+				Now, the hard part to this is what is represented by the '. . .' above.  This conditional expression is 
+				defining what elements *don't* belong to the current run.  The conditions are as follows:
+				
+				The element is not a token element (mi, mn, mo, ms, or mtext)
+				
+				or
+				
+				The token element contains a glyph child (this is handled separately).
+				
+				or
+				
+				The token is an mtext and the run didn't start with an mtext, or the token isn't an mtext and the run started 
+				with an mtext.  We do this check because mtext transforms into an omml m:nor property, and thus, these mtext
+				token elements need to be grouped separately from other token elements.
+				
+				// We do an or not( . . . ), because it was easier to define what token elements match than how they don't match.
+				// Thus, this inner '. . .' defines how token attributes equate to one another.  We add the 'not' outside of to accomplish
+				// the goal of the outer '. . .', which is the find the next element that *doesn't* match.
+				or not(
+				   The background colors match.
+					 
+					 and
+					 
+							The current font (sFontCur) matches the mathvariant
+					 
+							or
+							
+							sFontCur is normal and matches the current font characteristics
+							
+							or 
+							
+							sFontCur is italic and matches the current font characteristics
+							
+							or 
+							
+							. . .
+				
+					 and
+					 
+					 The font family matches the current font family.
+					 ) // end of not().-->
+    <xsl:variable name="nndBeforeLim" select="count($ndTokenFirst/following-sibling::*
+					[(not(self::mml:mi) and not(self::mml:mn) and not(self::mml:mo) and not(self::mml:ms) and not(self::mml:mtext))
+					or
+					(self::mml:mi[child::mml:mglyph] or self::mml:mn[child::mml:mglyph] or self::mml:mo[child::mml:mglyph] or self::mml:ms[child::mml:mglyph] or self::mml:mtext[child::mml:mglyph])
+					or
+					(($fNdTokenFirstIsMText=1 and not(self::mml:mtext)) or ($fNdTokenFirstIsMText=0 and self::mml:mtext))
+					or  
+					not(
+						((($sFontCur=@mathvariant or $sFontCur=@mml:mathvariant)
+							or
+							($sFontCur='normal'
+							 and ((@mathvariant='normal' or @mml:mathvariant='normal')
+									  or (((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
+											  and (
+									           ((@fontstyle='normal' or @mml:fontstyle='normal') and (not(@fontweight='bold') and not(@mml:fontweight='bold')))
+									           or (self::mml:mi and string-length(normalize-space(.)) &gt; 1)
+									           or (self::mml:mn and string(number(self::mml:mn/text()))='NaN')
+									          )
+									     )
+									 )
+							)
+							or
+							($sFontCur='italic' 
+							 and ((@mathvariant='italic' or @mml:mathvariant='italic')
+									  or (((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
+												and (
+									           ((@fontstyle='italic' or @mml:fontstyle='italic') and (not(@fontweight='bold') and not(@mml:fontweight='bold')))
+										         or  
+															((self::mml:mn and string(number(self::mml:mn/text()))!='NaN')
+															 or self::mml:mo
+															 or (self::mml:mi and string-length(normalize-space(.)) &lt;= 1)
+									            )
+									          )
+									     )
+									 )
+							) 
+							or
+							($sFontCur='bold'
+							 and ((@mathvariant='bold' or @mml:mathvariant='bold')
+									  or (((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
+									      and (
+									           ((@fontweight='bold' or @mml:fontweight='bold')
+									           and ((@fontstyle='normal' or @mml:fontstyle='normal') or (self::mml:mi and string-length(normalize-space(.)) &lt;= 1))
+									          )
+									     )
+									   )  
+									 )
+							)
+						  or
+							(($sFontCur='bi' or $sFontCur='bold-italic')
+							 and (
+									  (@mathvariant='bold-italic' or @mml:mathvariant='bold-italic')
+									  or (((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
+												and (
+														 ((@fontweight='bold' or @mml:fontweight='bold') and (@fontstyle='italic' or @mml:fontstyle='italic'))
+														 or ((@fontweight='bold' or @mml:fontweight='bold')
+														  	 and (self::mml:mn 
+																 		  or self::mml:mo 
+																			or (self::mml:mi and string-length(normalize-space(.)) &lt;= 1)))
+									          )
+									     )
+									 )
+							)		     
+							or
+              (($sFontCur='' 
+                 and (
+                     ((not(@mathvariant) or @mathvariant='')
+                        and (not(@mml:mathvariant) or @mml:mathvariant='')
+                        and (not(@fontstyle) or @fontstyle='')
+                        and (not(@mml:fontstyle) or @mml:fontstyle='')
+                        and (not(@fontweight)or @fontweight='')
+                        and (not(@mml:fontweight) or @mml:fontweight='')
+		              ) 
+                      or 
+                        (@mathvariant='italic' or @mml:mathvariant='italic')  
+                      or (
+                           ((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
+                               and (
+	                                 (((@fontweight='normal' or @mml:fontweight='normal') 
+		                                and (@fontstyle='italic' or @mml:fontstyle='italic'))
+	                                 )
+	                                 or
+		                                ((not(@fontweight) or @fontweight='') and (not(@mml:fontweight) or @mml:fontweight=''))
+			                                and (@fontstyle='italic' or @mml:fontstyle='italic')
+	                                 or
+		                                ((not(@fontweight) or @fontweight='') and (not(@mml:fontweight) or @mml:fontweight=''))
+			                                and (not(@fontstyle) or @fontstyle='')
+			                                and (not(@mml:fontstyle) or @mml:fontstyle=''))
+                            )
+		              )
+
+              ))
+							or
+              ($sFontCur='normal' 
+               and ((self::mml:mi 
+                     and (not(@mathvariant) or @mathvariant='')
+	                 and (not(@mml:mathvariant) or @mml:mathvariant)
+	                 and (not(@fontstyle) or @fontstyle='') 
+	                 and (not(@mml:fontstyle) or @mml:fontstyle='')
+	                 and (not(@fontweight) or @fontweight='') 
+	                 and (not(@mml:fontweight) or @mml:fontweight='')
+	                 and (string-length(normalize-space(.)) &gt; 1)
+	                 )
+	                or ((self::mml:ms or self::mml:mtext) 
+		                and (not(@mathvariant) or @mathvariant='')
+		                and (not(@mml:mathvariant) or @mml:mathvariant)
+		                and (not(@fontstyle) or @fontstyle)
+		                and (not(@fontstyle) or @fontstyle='')
+		                and (not(@fontweight) or @fontweight)
+		                and (not(@mml:fontweight) or @mml:fontweight='')
+		                )
+	                )
+              )			 
+						)
+						and
+            (($font-family = @font-family or $font-family = @mml:font-family)
+              or (($font-family='' or not($font-family))
+	              and (not(@font-family) or @font-family='')
+	              and (not(@mml:font-family) or @mml:font-family='')
+	             ) 
+            )
+					))
+					][1]/preceding-sibling::*)" />
+
+    <xsl:variable name="cndRun" select="$nndBeforeLim - $nndBeforeFirst" />
+
+    <!--Contiguous groups of like-property mi, mn, and mo's are separated by non- mi, mn, mo tags, or mi,mn, or mo
+			tags with different properties.  nndBeforeLim is the number of nodes before the next tag which separates contiguous 
+			groups of like-property mi, mn, and mo's.  Knowing this delimiting tag allows for the aggregation of the correct 
+			number of mi, mn, and mo tags.-->
+    <xsl:element name="m:r">
+
+      <!--The beginning and ending of the current run has been established. Now we should open a run element-->
+      <xsl:choose>
+
+        <!--If cndRun > 0, then there is a following diffrent prop, or non- Token, 
+						although there may or may not have been a preceding different prop, or non-
+						Token-->
+        <xsl:when test="$cndRun &gt; 0">
+          <xsl:call-template name="CreateRunProp">
+            <xsl:with-param name="mathvariant" select="$mathvariant" />
+            <xsl:with-param name="fontstyle" select="$fontstyle" />
+            <xsl:with-param name="fontweight" select="$fontweight" />
+            <xsl:with-param name="mathcolor" select="$mathcolor" />
+            <xsl:with-param name="mathsize" select="$mathsize" />
+            <xsl:with-param name="color" select="$color" />
+            <xsl:with-param name="fontsize" select="$fontsize" />
+            <xsl:with-param name="ndCur" select="$ndTokenFirst" />
+            <xsl:with-param name="fNor">
+              <xsl:call-template name="FNor">
+                <xsl:with-param name="ndCur" select="$ndTokenFirst" />
+              </xsl:call-template>
+            </xsl:with-param>
+          </xsl:call-template>
+          <xsl:element name="m:t">
+            <xsl:call-template name="OutputText">
+              <xsl:with-param name="sInput">
+                <xsl:choose>
+                  <xsl:when test="namespace-uri($ndTokenFirst) = 'http://www.w3.org/1998/Math/MathML' and local-name($ndTokenFirst) = 'ms'">
+                    <xsl:call-template name="OutputMs">
+                      <xsl:with-param name="msCur" select="$ndTokenFirst" />
+                    </xsl:call-template>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="normalize-space($ndTokenFirst)" />
+                  </xsl:otherwise>
+                </xsl:choose>
+                <xsl:for-each select="$ndTokenFirst/following-sibling::*[position() &lt; $cndRun]">
+                  <xsl:choose>
+                    <xsl:when test="namespace-uri(.) = 'http://www.w3.org/1998/Math/MathML' and 
+													local-name(.) = 'ms'">
+                      <xsl:call-template name="OutputMs">
+                        <xsl:with-param name="msCur" select="." />
+                      </xsl:call-template>
+                    </xsl:when>
+                    <xsl:otherwise>
+                      <xsl:value-of select="normalize-space(.)" />
+                    </xsl:otherwise>
+                  </xsl:choose>
+                </xsl:for-each>
+              </xsl:with-param>
+            </xsl:call-template>
+          </xsl:element>
+        </xsl:when>
+        <xsl:otherwise>
+
+          <!--if cndRun lt;= 0, then iNextNonToken = 0, 
+						and iPrecNonToken gt;= 0.  In either case, b/c there 
+						is no next different property or non-Token 
+						(which is implied by the nndBeforeLast being equal to 0) 
+						you can put all the remaining mi, mn, and mo's into one 
+						group.-->
+          <xsl:call-template name="CreateRunProp">
+            <xsl:with-param name="mathvariant" select="$mathvariant" />
+            <xsl:with-param name="fontstyle" select="$fontstyle" />
+            <xsl:with-param name="fontweight" select="$fontweight" />
+            <xsl:with-param name="mathcolor" select="$mathcolor" />
+            <xsl:with-param name="mathsize" select="$mathsize" />
+            <xsl:with-param name="color" select="$color" />
+            <xsl:with-param name="fontsize" select="$fontsize" />
+            <xsl:with-param name="ndCur" select="$ndTokenFirst" />
+            <xsl:with-param name="fNor">
+              <xsl:call-template name="FNor">
+                <xsl:with-param name="ndCur" select="$ndTokenFirst" />
+              </xsl:call-template>
+            </xsl:with-param>
+          </xsl:call-template>
+          <xsl:element name="m:t">
+
+            <!--Create the Run, first output current, then in a 
+							for-each, because all the following siblings are
+							mn, mi, and mo's that conform to the run's properties,
+							group them together-->
+            <xsl:call-template name="OutputText">
+              <xsl:with-param name="sInput">
+                <xsl:choose>
+                  <xsl:when test="namespace-uri($ndTokenFirst) = 'http://www.w3.org/1998/Math/MathML' and 
+													local-name($ndTokenFirst) = 'ms'">
+                    <xsl:call-template name="OutputMs">
+                      <xsl:with-param name="msCur" select="$ndTokenFirst" />
+                    </xsl:call-template>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="normalize-space($ndTokenFirst)" />
+                  </xsl:otherwise>
+                </xsl:choose>
+                <xsl:for-each select="$ndTokenFirst/following-sibling::*[self::mml:mi or self::mml:mn or self::mml:mo or self::mml:ms or self::mml:mtext]">
+                  <xsl:choose>
+                    <xsl:when test="namespace-uri(.) = 'http://www.w3.org/1998/Math/MathML' and 
+													local-name(.) = 'ms'">
+                      <xsl:call-template name="OutputMs">
+                        <xsl:with-param name="msCur" select="." />
+                      </xsl:call-template>
+                    </xsl:when>
+                    <xsl:otherwise>
+                      <xsl:value-of select="normalize-space(.)" />
+                    </xsl:otherwise>
+                  </xsl:choose>
+                </xsl:for-each>
+              </xsl:with-param>
+            </xsl:call-template>
+          </xsl:element>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:element>
+
+    <!--The run was terminated by an mi, mn, mo, ms, or mtext with different properties, 
+				therefore, call-template CreateRunWithSameProp, using cndRun+1 node as new start node-->
+    <xsl:if test="$nndBeforeLim!=0 
+           and ($ndTokenFirst/following-sibling::*[$cndRun]/self::mml:mi or 
+					      $ndTokenFirst/following-sibling::*[$cndRun]/self::mml:mn or
+					      $ndTokenFirst/following-sibling::*[$cndRun]/self::mml:mo or
+					      $ndTokenFirst/following-sibling::*[$cndRun]/self::mml:ms or
+                $ndTokenFirst/following-sibling::*[$cndRun]/self::mml:mtext) 
+            and (count($ndTokenFirst/following-sibling::*[$cndRun]/mml:mglyph) = 0)">
+      <xsl:call-template name="CreateRunWithSameProp">
+        <xsl:with-param name="mathbackground">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@mathbackground">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mathbackground"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:mathbackground"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="mathcolor">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@mathcolor">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mathcolor"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:mathcolor"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="mathvariant">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@mathvariant">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mathvariant"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:mathvariant"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="color">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@color">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@color"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:color"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="font-family">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@font-family">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@font-family"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:font-family"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="fontsize">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@fontsize">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@fontsize"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:fontsize"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="fontstyle">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@fontstyle">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@fontstyle"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:fontstyle"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="fontweight">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@fontweight">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@fontweight"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:fontweight"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="mathsize">
+          <xsl:choose>
+            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@mathsize">
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mathsize"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:mathsize"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="ndTokenFirst" select="$ndTokenFirst/following-sibling::*[$cndRun]" />
+      </xsl:call-template>
+    </xsl:if>
+  </xsl:template>
+
+  <!-- %%Template: FNor
+				 Given the context of ndCur, determine if ndCur should be omml's normal style.
+	-->
+  <xsl:template name="FNor">
+    <xsl:param name="ndCur" select="." />
+    <xsl:choose>
+      <!-- Is the current node an mml:mtext, or if this is an mglyph whose parent is 
+             an mml:mtext. -->
+      <xsl:when test="$ndCur/self::mml:mtext or ($ndCur/self::mml:mglyph and parent::mml:mtext)">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- %%Template: CreateRunProp
+	-->
+  <xsl:template name="CreateRunProp">
+    <xsl:param name="mathbackground" />
+    <xsl:param name="mathcolor" />
+    <xsl:param name="mathvariant" />
+    <xsl:param name="color" />
+    <xsl:param name="font-family" />
+    <xsl:param name="fontsize" />
+    <xsl:param name="fontstyle" />
+    <xsl:param name="fontweight" />
+    <xsl:param name="mathsize" />
+    <xsl:param name="ndCur" />
+    <xsl:param name="fontfamily" />
+    <xsl:param name="fNor" />
+    <xsl:variable name="mstyleColor">
+      <xsl:if test="not(not($ndCur))">
+        <xsl:choose>
+          <xsl:when test="$ndCur/ancestor::mml:mstyle[@color][1]/@color">
+            <xsl:value-of select="$ndCur/ancestor::mml:mstyle[@color][1]/@color"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="$ndCur/ancestor::mml:mstyle[@color][1]/@mml:color"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:if>
+    </xsl:variable>
+    <xsl:call-template name="CreateMathRPR">
+      <xsl:with-param name="mathvariant" select="$mathvariant" />
+      <xsl:with-param name="fontstyle" select="$fontstyle" />
+      <xsl:with-param name="fontweight" select="$fontweight" />
+      <xsl:with-param name="ndCur" select="$ndCur" />
+      <xsl:with-param name="fNor" select="$fNor" />
+    </xsl:call-template>
+  </xsl:template>
+
+  <!-- %%Template: CreateMathRPR
+	-->
+  <xsl:template name="CreateMathRPR">
+    <xsl:param name="mathvariant" />
+    <xsl:param name="fontstyle" />
+    <xsl:param name="fontweight" />
+    <xsl:param name="ndCur" />
+    <xsl:param name="fNor" />
+    <xsl:variable name="sFontCur">
+      <xsl:call-template name="GetFontCur">
+        <xsl:with-param name="mathvariant" select="$mathvariant" />
+        <xsl:with-param name="fontstyle" select="$fontstyle" />
+        <xsl:with-param name="fontweight" select="$fontweight" />
+        <xsl:with-param name="ndCur" select="$ndCur" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:if test="$fNor=1 or ($sFontCur!='italic' and $sFontCur!='')">
+      <xsl:element name="m:rPr">
+        <xsl:if test="$fNor=1">
+          <m:nor />
+        </xsl:if>
+        <xsl:call-template name="CreateMathScrStyProp">
+          <xsl:with-param name="font" select="$sFontCur" />
+          <xsl:with-param name="fNor" select="$fNor" />
+        </xsl:call-template>
+      </xsl:element>
+    </xsl:if>
+  </xsl:template>
+
+  <!-- %%Template: GetFontCur
+	-->
+  <xsl:template name="GetFontCur">
+    <xsl:param name="ndCur" />
+    <xsl:param name="mathvariant" />
+    <xsl:param name="fontstyle" />
+    <xsl:param name="fontweight" />
+    <xsl:choose>
+      <xsl:when test="$mathvariant!=''">
+        <xsl:value-of select="$mathvariant" />
+      </xsl:when>
+      <xsl:when test="not($ndCur)">
+        <xsl:value-of select="'italic'" />
+      </xsl:when>
+      <xsl:when test="$ndCur/self::mml:mi and (string-length(normalize-space($ndCur)) &lt;= 1)
+								      or $ndCur/self::mml:mn and string(number($ndCur/text()))!='NaN'
+								      or $ndCur/self::mml:mo">
+
+        <!-- The default for the above three cases is fontstyle=italic fontweight=normal.-->
+        <xsl:choose>
+          <xsl:when test="$fontstyle='normal' and $fontweight='bold'">
+            <!-- In omml, a sty of 'b' (which is what bold is translated into)
+						     implies a normal fontstyle -->
+            <xsl:value-of select="'bold'" />
+          </xsl:when>
+          <xsl:when test="$fontstyle='normal'">
+            <xsl:value-of select="'normal'" />
+          </xsl:when>
+          <xsl:when test="$fontweight='bold'">
+            <xsl:value-of select="'bi'" />
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="'italic'" />
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+        <!--Default is fontweight = 'normal' and fontstyle='normal'-->
+        <xsl:choose>
+          <xsl:when test="$fontstyle='italic' and $fontweight='bold'">
+            <xsl:value-of select="'bi'" />
+          </xsl:when>
+          <xsl:when test="$fontstyle='italic'">
+            <xsl:value-of select="'italic'" />
+          </xsl:when>
+          <xsl:when test="$fontweight='bold'">
+            <xsl:value-of select="'bold'" />
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="'normal'" />
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- %%Template: CreateMathScrStyProp
+	-->
+  <xsl:template name="CreateMathScrStyProp">
+    <xsl:param name="font" />
+    <xsl:param name="fNor" select="0"/>
+    <xsl:choose>
+      <xsl:when test="$font='normal' and $fNor=0">
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">p</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='bold'">
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">b</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='italic'">
+      </xsl:when>
+      <xsl:when test="$font='script'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">script</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='bold-script'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">script</xsl:attribute>
+        </xsl:element>
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">b</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='double-struck'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">double-struck</xsl:attribute>
+        </xsl:element>
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">p</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='fraktur'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">fraktur</xsl:attribute>
+        </xsl:element>
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">p</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='bold-fraktur'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">fraktur</xsl:attribute>
+        </xsl:element>
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">b</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='sans-serif'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">sans-serif</xsl:attribute>
+        </xsl:element>
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">p</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='bold-sans-serif'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">sans-serif</xsl:attribute>
+        </xsl:element>
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">b</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='sans-serif-italic'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">sans-serif</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='sans-serif-bold-italic'">
+        <xsl:element name="m:scr">
+          <xsl:attribute name="m:val">sans-serif</xsl:attribute>
+        </xsl:element>
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">bi</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='monospace'" />
+      <!-- We can't do monospace, so leave empty -->
+      <xsl:when test="$font='bold'">
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">b</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+      <xsl:when test="$font='bi' or $font='bold-italic'">
+        <xsl:element name="m:sty">
+          <xsl:attribute name="m:val">bi</xsl:attribute>
+        </xsl:element>
+      </xsl:when>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="FBar">
+    <xsl:param name="sLineThickness" />
+    <xsl:variable name="sLowerLineThickness" select="translate($sLineThickness, $StrUCAlphabet, $StrLCAlphabet)" />
+    <xsl:choose>
+      <xsl:when test="string-length($sLowerLineThickness)=0
+                      or $sLowerLineThickness='thin' 
+                      or $sLowerLineThickness='medium' 
+                      or $sLowerLineThickness='thick'">1</xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="fStrContainsNonZeroDigit">
+          <xsl:call-template name="FStrContainsNonZeroDigit">
+            <xsl:with-param name="s" select="$sLowerLineThickness" />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:choose>
+          <xsl:when test="$fStrContainsNonZeroDigit=1">1</xsl:when>
+          <xsl:otherwise>0</xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- %%Template: match mfrac 
+		-->
+  <xsl:template match="mml:mfrac">
+    <xsl:variable name="fBar">
+      <xsl:call-template name="FBar">
+        <xsl:with-param name="sLineThickness">
+          <xsl:choose>
+            <xsl:when test="@linethickness">
+              <xsl:value-of select="@linethickness"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@mml:linethickness"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:element name="m:f">
+      <xsl:element name="m:fPr">
+        <xsl:element name="m:type">
+          <xsl:attribute name="m:val">
+            <xsl:choose>
+              <xsl:when test="$fBar=0">noBar</xsl:when>
+              <xsl:when test="@bevelled='true' or @mml:bevelled='true'">skw</xsl:when>
+              <xsl:otherwise>bar</xsl:otherwise>
+            </xsl:choose>
+          </xsl:attribute>
+        </xsl:element>
+      </xsl:element>
+      <xsl:element name="m:num">
+        <xsl:call-template name="CreateArgProp" />
+        <xsl:apply-templates select="child::*[1]" />
+      </xsl:element>
+      <xsl:element name="m:den">
+        <xsl:call-template name="CreateArgProp" />
+        <xsl:apply-templates select="child::*[2]" />
+      </xsl:element>
+    </xsl:element>
+  </xsl:template>
+
+  <!-- %%Template: match menclose msqrt
+	-->
+  <xsl:template match="mml:menclose | mml:msqrt">
+    <xsl:variable name="sLowerCaseNotation">
+      <xsl:choose>
+        <xsl:when test="@notation">
+          <xsl:value-of select="translate(@notation, $StrUCAlphabet, $StrLCAlphabet)"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="translate(@mml:notation, $StrUCAlphabet, $StrLCAlphabet)"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:choose>
+      <!-- Take care of default -->
+      <xsl:when test="$sLowerCaseNotation='radical' 
+                      or not($sLowerCaseNotation) 
+                      or $sLowerCaseNotation='' 
+                      or self::mml:msqrt">
+        <xsl:element name="m:rad">
+          <xsl:element name="m:radPr">
+            <xsl:element name="m:degHide">
+              <xsl:attribute name="m:val">on</xsl:attribute>
+            </xsl:element>
+          </xsl:element>
+          <xsl:element name="m:deg">
+            <xsl:call-template name="CreateArgProp" />
+          </xsl:element>
+          <xsl:element name="m:e">
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="*" />
+          </xsl:element>
+        </xsl:element>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:choose>
+          <xsl:when test="$sLowerCaseNotation='actuarial' or $sLowerCaseNotation='longdiv'" />
+          <xsl:otherwise>
+            <xsl:element name="m:borderBox">
+              <!-- Dealing with more complex notation attribute -->
+              <xsl:variable name="fBox">
+                <xsl:choose>
+                  <!-- Word doesn't have circle and roundedbox concepts, therefore, map both to a 
+                       box. -->
+                  <xsl:when test="contains($sLowerCaseNotation, 'box')
+                                  or contains($sLowerCaseNotation, 'circle')
+                                  or contains($sLowerCaseNotation, 'roundedbox')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <xsl:variable name="fTop">
+                <xsl:choose>
+                  <xsl:when test="contains($sLowerCaseNotation, 'top')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <xsl:variable name="fBot">
+                <xsl:choose>
+                  <xsl:when test="contains($sLowerCaseNotation, 'bottom')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <xsl:variable name="fLeft">
+                <xsl:choose>
+                  <xsl:when test="contains($sLowerCaseNotation, 'left')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <xsl:variable name="fRight">
+                <xsl:choose>
+                  <xsl:when test="contains($sLowerCaseNotation, 'right')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <xsl:variable name="fStrikeH">
+                <xsl:choose>
+                  <xsl:when test="contains($sLowerCaseNotation, 'horizontalstrike')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <xsl:variable name="fStrikeV">
+                <xsl:choose>
+                  <xsl:when test="contains($sLowerCaseNotation, 'verticalstrike')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <xsl:variable name="fStrikeBLTR">
+                <xsl:choose>
+                  <xsl:when test="contains($sLowerCaseNotation, 'updiagonalstrike')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <xsl:variable name="fStrikeTLBR">
+                <xsl:choose>
+                  <xsl:when test="contains($sLowerCaseNotation, 'downdiagonalstrike')">1</xsl:when>
+                  <xsl:otherwise>0</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+
+              <!-- Should we create borderBoxPr? 
+                   We should if the enclosure isn't Word's default, which is
+                   a plain box -->
+              <xsl:if test="$fStrikeH=1 
+                          or $fStrikeV=1
+                          or $fStrikeBLTR=1 
+                          or $fStrikeTLBR=1
+                          or ($fBox=0
+                              and not($fTop=1 
+                                      and $fBot=1
+                                      and $fLeft=1
+                                      and $fRight=1)
+                              )">
+                <xsl:element name="m:borderBoxPr">
+                  <xsl:if test="$fBox=0">
+                    <xsl:if test="$fTop=0">
+                      <xsl:element name="m:hideTop">
+                        <xsl:attribute name="m:val">on</xsl:attribute>
+                      </xsl:element>
+                    </xsl:if>
+                    <xsl:if test="$fBot=0">
+                      <xsl:element name="m:hideBot">
+                        <xsl:attribute name="m:val">on</xsl:attribute>
+                      </xsl:element>
+                    </xsl:if>
+                    <xsl:if test="$fLeft=0">
+                      <xsl:element name="m:hideLeft">
+                        <xsl:attribute name="m:val">on</xsl:attribute>
+                      </xsl:element>
+                    </xsl:if>
+                    <xsl:if test="$fRight=0">
+                      <xsl:element name="m:hideRight">
+                        <xsl:attribute name="m:val">on</xsl:attribute>
+                      </xsl:element>
+                    </xsl:if>
+                  </xsl:if>
+                  <xsl:if test="$fStrikeH=1">
+                    <xsl:element name="m:strikeH">
+                      <xsl:attribute name="m:val">on</xsl:attribute>
+                    </xsl:element>
+                  </xsl:if>
+                  <xsl:if test="$fStrikeV=1">
+                    <xsl:element name="m:strikeV">
+                      <xsl:attribute name="m:val">on</xsl:attribute>
+                    </xsl:element>
+                  </xsl:if>
+                  <xsl:if test="$fStrikeBLTR=1">
+                    <xsl:element name="m:strikeBLTR">
+                      <xsl:attribute name="m:val">on</xsl:attribute>
+                    </xsl:element>
+                  </xsl:if>
+                  <xsl:if test="$fStrikeTLBR=1">
+                    <xsl:element name="m:strikeTLBR">
+                      <xsl:attribute name="m:val">on</xsl:attribute>
+                    </xsl:element>
+                  </xsl:if>
+                </xsl:element>
+              </xsl:if>
+              <xsl:element name="m:e">
+                <xsl:call-template name="CreateArgProp" />
+                <xsl:apply-templates select="*" />
+              </xsl:element>
+            </xsl:element>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: CreateArgProp
+	-->
+  <xsl:template name="CreateArgProp">
+    <xsl:if test="not(count(ancestor-or-self::mml:mstyle[@scriptlevel='0' or @scriptlevel='1' or @scriptlevel='2'])=0)
+                  or not(count(ancestor-or-self::mml:mstyle[@mml:scriptlevel='0' or @mml:scriptlevel='1' or @mml:scriptlevel='2'])=0)">
+      <xsl:element name="m:argPr">
+        <xsl:element name="m:scrLvl">
+          <xsl:attribute name="m:val">
+            <xsl:choose>
+              <xsl:when test="ancestor-or-self::mml:mstyle[@scriptlevel][1]/@scriptlevel">
+                <xsl:value-of select="ancestor-or-self::mml:mstyle[@scriptlevel][1]/@scriptlevel"/>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:value-of select="ancestor-or-self::mml:mstyle[@scriptlevel][1]/@mml:scriptlevel"/>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:attribute>
+        </xsl:element>
+      </xsl:element>
+    </xsl:if>
+  </xsl:template>
+
+  <!-- %%Template: match mroot
+	-->
+  <xsl:template match="mml:mroot">
+    <xsl:element name="m:rad">
+      <xsl:element name="m:radPr">
+        <xsl:element name="m:degHide">
+          <xsl:attribute name="m:val">off</xsl:attribute>
+        </xsl:element>
+      </xsl:element>
+      <xsl:element name="m:deg">
+        <xsl:call-template name="CreateArgProp" />
+        <xsl:apply-templates select="child::*[2]" />
+      </xsl:element>
+      <xsl:element name="m:e">
+        <xsl:call-template name="CreateArgProp" />
+        <xsl:apply-templates select="child::*[1]" />
+      </xsl:element>
+    </xsl:element>
+  </xsl:template>
+
+  <!-- MathML has no concept of a linear fraction.  When transforming a linear fraction
+       from Omml to MathML, we create the following MathML:
+       
+       <mml:mrow>
+         <mml:mrow>
+            // numerator
+         </mml:mrow>
+         <mml:mo>/</mml:mo>
+         <mml:mrow>
+            // denominator
+         </mml:mrow>
+       </mml:mrow>
+       
+       This template looks for four things:
+          1.  ndCur is an mml:mrow
+          2.  ndCur has three children
+          3.  The second child is an <mml:mo>
+          4.  The second child's text is '/'
+       
+       -->
+  <xsl:template name="FLinearFrac">
+    <xsl:param name="ndCur" select="." />
+    <xsl:variable name="sNdText">
+      <xsl:value-of select="normalize-space($ndCur/*[2])"/>
+    </xsl:variable>
+
+    <xsl:choose>
+      <!-- I spy a linear fraction -->
+      <xsl:when test="$ndCur/self::mml:mrow
+                      and count($ndCur/*)=3
+                      and $ndCur/*[2][self::mml:mo]
+                      and $sNdText='/'">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- Though presentation mathml can certainly typeset any generic function with the
+	     appropriate function operator spacing, presentation MathML has no concept of 
+			 a function structure like omml does.  In order to preserve the omml <func> 
+			 element, we must establish how an omml <func> element looks in mml.  This 
+			 is shown below:
+       
+       <mml:mrow>
+         <mml:mrow>
+            // function name
+         </mml:mrow>
+         <mml:mo>&#x02061;</mml:mo>
+         <mml:mrow>
+            // function argument
+         </mml:mrow>
+       </mml:mrow>
+       
+       This template looks for six things to be true:
+					1.  ndCur is an mml:mrow
+					2.  ndCur has three children
+					3.  The first child is an <mml:mrow>
+					4.  The second child is an <mml:mo>
+					5.  The third child is an <mml:mrow>
+					6.  The second child's text is '&#x02061;'
+       -->
+  <xsl:template name="FIsFunc">
+    <xsl:param name="ndCur" select="." />
+    <xsl:variable name="sNdText">
+      <xsl:value-of select="normalize-space($ndCur/*[2])"/>
+    </xsl:variable>
+
+    <xsl:choose>
+      <!-- Is this an omml function -->
+      <xsl:when test="count($ndCur/*)=3
+								      and $ndCur/self::*[self::mml:mrow]
+                      and $ndCur/*[2][self::mml:mo]
+                      and $sNdText='&#x02061;'">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- Given the node of the linear fraction's parent mrow, 
+       make a linear fraction -->
+  <xsl:template name="MakeLinearFraction">
+    <xsl:param name="ndCur" select="." />
+    <xsl:element name="m:f">
+      <xsl:element name="m:fPr">
+        <xsl:element name="m:type">
+          <xsl:attribute name="m:val">lin</xsl:attribute>
+        </xsl:element>
+      </xsl:element>
+      <xsl:element name="m:num">
+        <xsl:call-template name="CreateArgProp" />
+        <xsl:apply-templates select="$ndCur/*[1]" />
+      </xsl:element>
+      <xsl:element name="m:den">
+        <xsl:call-template name="CreateArgProp" />
+        <xsl:apply-templates select="$ndCur/*[3]" />
+      </xsl:element>
+    </xsl:element>
+  </xsl:template>
+
+
+  <!-- Given the node of the function's parent mrow, 
+       make an omml function -->
+  <xsl:template name="WriteFunc">
+    <xsl:param name="ndCur" select="." />
+
+    <xsl:element name="m:func">
+      <xsl:element name="m:fName">
+        <xsl:apply-templates select="$ndCur/child::*[1]" />
+      </xsl:element>
+      <xsl:element name="m:e">
+        <xsl:apply-templates select="$ndCur/child::*[3]" />
+      </xsl:element>
+    </xsl:element>
+  </xsl:template>
+
+
+  <!-- MathML doesn't have the concept of nAry structures.  The best approximation
+       to these is to have some under/over or sub/sup followed by an mrow or mstyle.
+       
+       In the case that we've come across some under/over or sub/sup that contains an 
+       nAry operator, this function handles the following sibling to the nAry structure.
+       
+       If the following sibling is:
+       
+          mml:mstyle, then apply templates to the children of this mml:mstyle
+          
+          mml:mrow, determine if this mrow is a linear fraction 
+          (see comments for FlinearFrac template).
+              If so, make an Omml linear fraction.
+              If not, apply templates as was done for mml:mstyle.
+       
+       -->
+  <xsl:template name="NaryHandleMrowMstyle">
+    <xsl:param name="ndCur" select="." />
+    <!-- if the next sibling is an mrow, pull it in by 
+							doing whatever we would have done to its children. 
+							The mrow itself will be skipped, see template above. -->
+    <xsl:choose>
+      <xsl:when test="$ndCur[self::mml:mrow]">
+        <!-- Check for linear fraction -->
+        <xsl:variable name="fLinearFrac">
+          <xsl:call-template name="FLinearFrac">
+            <xsl:with-param name="ndCur" select="$ndCur" />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:choose>
+          <xsl:when test="$fLinearFrac=1">
+            <xsl:call-template name="MakeLinearFraction">
+              <xsl:with-param name="ndCur" select="$ndCur" />
+            </xsl:call-template>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:variable name="fFunc">
+              <xsl:call-template name="FIsFunc">
+                <xsl:with-param name="ndCur" select="." />
+              </xsl:call-template>
+            </xsl:variable>
+            <xsl:choose>
+              <xsl:when test="$fFunc=1">
+                <xsl:call-template name="WriteFunc">
+                  <xsl:with-param name="ndCur" select="." />
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:apply-templates select="$ndCur/*" />
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:when test="$ndCur[self::mml:mstyle]">
+        <xsl:apply-templates select="$ndCur/*" />
+      </xsl:when>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- MathML munder/mover can represent several Omml constructs 
+       (m:bar, m:limLow, m:limUpp, m:acc, m:groupChr, etc.).  The following 
+       templates (FIsBar, FIsAcc, and FIsGroupChr) are used to determine 
+			 which of these Omml constructs an munder/mover should be translated into. -->
+
+  <!-- Note:  ndCur should only be an munder/mover MathML element.
+  
+       ndCur should be interpretted as an m:bar if
+          1)  its respective accent attribute is not true
+          2)  its second child is an mml:mo
+          3)  the character of the mml:mo is the correct under/over bar. -->
+  <xsl:template name="FIsBar">
+    <xsl:param name="ndCur" />
+    <xsl:variable name="fUnder">
+      <xsl:choose>
+        <xsl:when test="$ndCur[self::mml:munder]">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="sLowerCaseAccent">
+      <xsl:choose>
+        <xsl:when test="$fUnder=1">
+          <xsl:choose>
+            <xsl:when test="$ndCur/@accentunder">
+              <xsl:value-of select="translate($ndCur/@accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/@mml:accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:choose>
+            <xsl:when test="$ndCur/@accent">
+              <xsl:value-of select="translate($ndCur/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="fAccent">
+      <xsl:choose>
+        <xsl:when test="$sLowerCaseAccent='true'">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:choose>
+      <!-- The script is unaccented and the second child is an mo -->
+      <xsl:when test="$fAccent = 0 
+                      and $ndCur/child::*[2]/self::mml:mo">
+        <xsl:variable name="sOperator">
+          <xsl:value-of select="$ndCur/child::*[2]" />
+        </xsl:variable>
+        <xsl:choose>
+          <!-- Should we write an underbar? -->
+          <xsl:when test="$fUnder = 1">
+            <xsl:choose>
+              <xsl:when test="$sOperator = '&#x0332;' or $sOperator = '&#x005F;'">1</xsl:when>
+              <xsl:otherwise>0</xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <!-- Should we write an overbar? -->
+          <xsl:otherwise>
+            <xsl:choose>
+              <xsl:when test="$sOperator = '&#x0305;' or $sOperator = '&#x00AF;'">1</xsl:when>
+              <xsl:otherwise>0</xsl:otherwise>
+            </xsl:choose>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Note:  ndCur should only be an mover MathML element.
+  
+       ndCur should be interpretted as an m:acc if
+          1)  its accent attribute is true
+          2)  its second child is an mml:mo
+          3)  there is only zero or one character in the mml:mo -->
+  <xsl:template name="FIsAcc">
+    <xsl:param name="ndCur" select="." />
+
+    <xsl:variable name="sLowerCaseAccent">
+      <xsl:choose>
+        <xsl:when test="$ndCur/@accent">
+          <xsl:value-of select="translate($ndCur/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="translate($ndCur/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="sLowerCaseMoAccent">
+      <xsl:choose>
+        <xsl:when test="$ndCur/child::*[2] = mml:mo and $ndCur/child::*[2]/@accent">
+          <xsl:value-of select="translate($ndCur/child::*[2]/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+        </xsl:when>
+        <xsl:when test="$ndCur/child::*[2] = mml:mo and $ndCur/child::*[2]/@mml:accent">
+          <xsl:value-of select="translate($ndCur/child::*[2]/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+        </xsl:when>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="fAccent">
+      <xsl:choose>
+        <xsl:when test="$sLowerCaseMoAccent='true' or ($sLowerCaseMoAccent='' and $sLowerCaseAccent='true')">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:choose>
+      <!-- The script is accented and the second child is an mo -->
+      <xsl:when test="$fAccent = 1 
+                      and $ndCur/child::*[2] = mml:mo">
+        <xsl:variable name="sOperator">
+          <xsl:value-of select="$ndCur/child::*[2]" />
+        </xsl:variable>
+        <xsl:choose>
+          <!-- There is only one operator, this is a valid Omml accent! -->
+          <xsl:when test="string-length($sOperator) &lt;= 1">1</xsl:when>
+          <!-- More than one accented operator.  This isn't a valid
+               omml accent -->
+          <xsl:otherwise>0</xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <!-- Not accented, not an operator, or both, but in any case, this is
+           not an Omml accent. -->
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- Is ndCur a groupChr? 
+			 ndCur is a groupChr if:
+			 
+				 1.  The accent is false (note:  accent attribute 
+						 for munder is accentunder). 
+				 2.  ndCur is an munder or mover.
+				 3.  ndCur has two children
+				 4.  Of these two children, one is an mml:mo and the other is an mml:mrow
+				 5.  The number of characters in the mml:mo is 1.
+			 
+			 If all of the above are true, then return 1, else return 0.
+	-->
+  <xsl:template name="FIsGroupChr">
+    <xsl:param name="ndCur" select="." />
+    <xsl:variable name="fUnder">
+      <xsl:choose>
+        <xsl:when test="$ndCur[self::mml:munder]">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="sLowerCaseAccent">
+      <xsl:choose>
+        <xsl:when test="$fUnder=1">
+          <xsl:choose>
+            <xsl:when test="$ndCur/@accentunder">
+              <xsl:value-of select="translate($ndCur/@accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/@mml:accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:choose>
+            <xsl:when test="$ndCur/@accent">
+              <xsl:value-of select="translate($ndCur/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="fAccentFalse">
+      <xsl:choose>
+        <xsl:when test="$sLowerCaseAccent='false'">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:choose>
+      <xsl:when test="$fAccentFalse=1
+                      and $ndCur[self::mml:munder or self::mml:mover] 
+                      and count($ndCur/child::*)=2 
+                      and (($ndCur/child::*[1][self::mml:mrow] and $ndCur/child::*[2][self::mml:mo]) 
+                            or ($ndCur/child::*[1][self::mml:mo] and $ndCur/child::*[2][self::mml:mrow]))">
+        <xsl:variable name="sOperator">
+          <xsl:value-of select="$ndCur/child::mml:mo" />
+        </xsl:variable>
+        <xsl:choose>
+          <xsl:when test="string-length($sOperator) &lt;= 1">1</xsl:when>
+          <xsl:otherwise>0</xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- %%Template: match munder
+	-->
+  <xsl:template match="mml:munder">
+    <xsl:variable name="fNary">
+      <xsl:call-template name="isNary">
+        <xsl:with-param name="ndCur" select="child::*[1]" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fNary='true'">
+        <m:nary>
+          <xsl:call-template name="CreateNaryProp">
+            <xsl:with-param name="chr">
+              <xsl:value-of select="normalize-space(child::*[1])" />
+            </xsl:with-param>
+            <xsl:with-param name="sMathmlType" select="'munder'" />
+          </xsl:call-template>
+          <m:sub>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sub>
+          <m:sup>
+            <xsl:call-template name="CreateArgProp" />
+          </m:sup>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:call-template name="NaryHandleMrowMstyle">
+              <xsl:with-param name="ndCur" select="following-sibling::*[1]" />
+            </xsl:call-template>
+          </m:e>
+        </m:nary>
+      </xsl:when>
+      <xsl:otherwise>
+        <!-- Should this munder be interpreted as an OMML m:bar? -->
+        <xsl:variable name="fIsBar">
+          <xsl:call-template name="FIsBar">
+            <xsl:with-param name="ndCur" select="." />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:choose>
+          <xsl:when test="$fIsBar=1">
+            <m:bar>
+              <m:barPr>
+                <m:pos m:val="bot" />
+              </m:barPr>
+              <m:e>
+                <xsl:call-template name="CreateArgProp" />
+                <xsl:apply-templates select="child::*[1]" />
+              </m:e>
+            </m:bar>
+          </xsl:when>
+          <xsl:otherwise>
+            <!-- It isn't an integral or underbar, is this a groupChr? -->
+            <xsl:variable name="fGroupChr">
+              <xsl:call-template name="FIsGroupChr">
+                <xsl:with-param name="ndCur" select="." />
+              </xsl:call-template>
+            </xsl:variable>
+            <xsl:choose>
+              <xsl:when test="$fGroupChr=1">
+                <xsl:element name="m:groupChr">
+                  <xsl:call-template name="CreateGroupChrPr">
+                    <xsl:with-param name="chr">
+                      <xsl:value-of select="mml:mo" />
+                    </xsl:with-param>
+                    <xsl:with-param name="pos">
+                      <xsl:choose>
+                        <xsl:when test="child::*[1][self::mml:mrow]">bot</xsl:when>
+                        <xsl:otherwise>top</xsl:otherwise>
+                      </xsl:choose>
+                    </xsl:with-param>
+                    <xsl:with-param name="vertJc">top</xsl:with-param>
+                  </xsl:call-template>
+                  <xsl:element name="m:e">
+                    <xsl:apply-templates select="mml:mrow" />
+                  </xsl:element>
+                </xsl:element>
+              </xsl:when>
+              <xsl:otherwise>
+                <!-- Generic munder -->
+                <xsl:element name="m:limLow">
+                  <xsl:element name="m:e">
+                    <xsl:call-template name="CreateArgProp" />
+                    <xsl:apply-templates select="child::*[1]" />
+                  </xsl:element>
+                  <xsl:element name="m:lim">
+                    <xsl:call-template name="CreateArgProp" />
+                    <xsl:apply-templates select="child::*[2]" />
+                  </xsl:element>
+                </xsl:element>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- Given the values for chr, pos, and vertJc, create an omml
+	     groupChr's groupChrPr -->
+  <xsl:template name="CreateGroupChrPr">
+    <xsl:param name="chr">&#x23df;</xsl:param>
+    <xsl:param name="pos" select="bot" />
+    <xsl:param name="vertJc" select="top" />
+    <xsl:element name="m:groupChrPr">
+      <xsl:element name="m:chr">
+        <xsl:attribute name="m:val">
+          <xsl:value-of select="$chr"/>
+        </xsl:attribute>
+      </xsl:element>
+      <xsl:element name="m:pos">
+        <xsl:attribute name="m:val">
+          <xsl:value-of select="$pos"/>
+        </xsl:attribute>
+      </xsl:element>
+      <xsl:element name="m:vertJc">
+        <xsl:attribute name="m:val">
+          <xsl:value-of select="$vertJc"/>
+        </xsl:attribute>
+      </xsl:element>
+    </xsl:element>
+  </xsl:template>
+
+
+  <!--
+      Convert a non-combining character into its upper combining
+      couterpart.
+      
+      { Non-combining, Upper-combining }
+      {U+02D8, U+0306}, // BREVE
+      {U+00B8, U+0312}, // CEDILLA
+      {U+0060, U+0300}, // GRAVE ACCENT
+      {U+002D, U+0305}, // HYPHEN-MINUS/OVERLINE
+      {U+2212, U+0305}, // MINUS SIGN/OVERLINE
+      {U+002E, U+0305}, // FULL STOP/DOT ABOVE
+      {U+02D9, U+0307}, // DOT ABOVE
+      {U+02DD, U+030B}, // DOUBLE ACUTE ACCENT
+      {U+00B4, U+0301}, // ACUTE ACCENT
+      {U+007E, U+0303}, // TILDE
+      {U+02DC, U+0303}, // SMALL TILDE
+      {U+00A8, U+0308}, // DIAERESIS
+      {U+02C7, U+030C}, // CARON
+      {U+005E, U+0302}, // CIRCUMFLEX ACCENT
+      {U+00AF, U+0305}, // MACRON
+      {U+005F, ::::::}, // LOW LINE
+      {U+2192, U+20D7}, // RIGHTWARDS ARROW
+      {U+27F6, U+20D7}, // LONG RIGHTWARDS ARROW
+      {U+2190, U+20D6}, // LEFT ARROW
+  -->
+  <xsl:template name="ToUpperCombining">
+    <xsl:param name="ch" />
+    <xsl:choose>
+      <!-- BREVE -->
+      <xsl:when test="$ch='&#x02D8;'">&#x0306;</xsl:when>
+      <!-- CEDILLA -->
+      <xsl:when test="$ch='&#x00B8;'">&#x0312;</xsl:when>
+      <!-- GRAVE ACCENT -->
+      <xsl:when test="$ch='&#x0060;'">&#x0300;</xsl:when>
+      <!-- HYPHEN-MINUS/OVERLINE -->
+      <xsl:when test="$ch='&#x002D;'">&#x0305;</xsl:when>
+      <!-- MINUS SIGN/OVERLINE -->
+      <xsl:when test="$ch='&#x2212;'">&#x0305;</xsl:when>
+      <!-- FULL STOP/DOT ABOVE -->
+      <xsl:when test="$ch='&#x002E;'">&#x0307;</xsl:when>
+      <!-- DOT ABOVE -->
+      <xsl:when test="$ch='&#x02D9;'">&#x0307;</xsl:when>
+      <!-- DOUBLE ACUTE ACCENT -->
+      <xsl:when test="$ch='&#x02DD;'">&#x030B;</xsl:when>
+      <!-- ACUTE ACCENT -->
+      <xsl:when test="$ch='&#x00B4;'">&#x0301;</xsl:when>
+      <!-- TILDE -->
+      <xsl:when test="$ch='&#x007E;'">&#x0303;</xsl:when>
+      <!-- SMALL TILDE -->
+      <xsl:when test="$ch='&#x02DC;'">&#x0303;</xsl:when>
+      <!-- DIAERESIS -->
+      <xsl:when test="$ch='&#x00A8;'">&#x0308;</xsl:when>
+      <!-- CARON -->
+      <xsl:when test="$ch='&#x02C7;'">&#x030C;</xsl:when>
+      <!-- CIRCUMFLEX ACCENT -->
+      <xsl:when test="$ch='&#x005E;'">&#x0302;</xsl:when>
+      <!-- MACRON -->
+      <xsl:when test="$ch='&#x00AF;'">&#x0305;</xsl:when>
+      
+      <!-- LOW LINE -->
+      
+      <!-- RIGHTWARDS ARROW -->
+      <xsl:when test="$ch='&#x2192;'">&#x20D7;</xsl:when>
+      <!-- LONG RIGHTWARDS ARROW -->
+      <xsl:when test="$ch='&#x27F6;'">&#x20D7;</xsl:when>
+      <!-- LEFT ARROW -->
+      <xsl:when test="$ch='&#x2190;'">&#x20D6;</xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$ch"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- %%Template: match mover
+	-->
+  <xsl:template match="mml:mover">
+    <xsl:variable name="fNary">
+      <xsl:call-template name="isNary">
+        <xsl:with-param name="ndCur" select="child::*[1]" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fNary='true'">
+        <m:nary>
+          <xsl:call-template name="CreateNaryProp">
+            <xsl:with-param name="chr">
+              <xsl:value-of select="normalize-space(child::*[1])" />
+            </xsl:with-param>
+            <xsl:with-param name="sMathmlType" select="'mover'" />
+          </xsl:call-template>
+          <m:sub>
+            <xsl:call-template name="CreateArgProp" />
+          </m:sub>
+          <m:sup>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sup>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:call-template name="NaryHandleMrowMstyle">
+              <xsl:with-param name="ndCur" select="following-sibling::*[1]" />
+            </xsl:call-template>
+          </m:e>
+        </m:nary>
+      </xsl:when>
+      <xsl:otherwise>
+        <!-- Should this munder be interpreted as an OMML m:bar or m:acc? -->
+
+        <!-- Check to see if this is an m:bar -->
+        <xsl:variable name="fIsBar">
+          <xsl:call-template name="FIsBar">
+            <xsl:with-param name="ndCur" select="." />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:choose>
+          <xsl:when test="$fIsBar = 1">
+            <m:bar>
+              <m:barPr>
+                <m:pos m:val="top" />
+              </m:barPr>
+              <m:e>
+                <xsl:call-template name="CreateArgProp" />
+                <xsl:apply-templates select="child::*[1]" />
+              </m:e>
+            </m:bar>
+          </xsl:when>
+          <xsl:otherwise>
+            <!-- Not an m:bar, should it be an m:acc? -->
+            <xsl:variable name="fIsAcc">
+              <xsl:call-template name="FIsAcc">
+                <xsl:with-param name="ndCur" select="." />
+              </xsl:call-template>
+            </xsl:variable>
+            <xsl:choose>
+              <xsl:when test="$fIsAcc=1">
+                <m:acc>
+                  <m:accPr>
+                    <m:chr>
+                      <xsl:variable name="ch">
+                        <xsl:value-of select="child::*[2]" />
+                      </xsl:variable>
+                      <xsl:variable name="chComb">
+                        <xsl:call-template name="ToUpperCombining">
+                          <xsl:with-param name="ch" select="$ch" />
+                        </xsl:call-template>
+                      </xsl:variable>
+                      <xsl:attribute name="m:val">
+                        <xsl:value-of select="$chComb" />
+                      </xsl:attribute>
+                    </m:chr>
+                  </m:accPr>
+                  <m:e>
+                    <xsl:call-template name="CreateArgProp" />
+                    <xsl:apply-templates select="child::*[1]" />
+                  </m:e>
+                </m:acc>
+              </xsl:when>
+              <xsl:otherwise>
+                <!-- This isn't an integral, overbar or accent, 
+								     could it be a groupChr? -->
+                <xsl:variable name="fGroupChr">
+                  <xsl:call-template name="FIsGroupChr">
+                    <xsl:with-param name="ndCur" select="." />
+                  </xsl:call-template>
+                </xsl:variable>
+                <xsl:choose>
+                  <xsl:when test="$fGroupChr=1">
+                    <xsl:element name="m:groupChr">
+                      <xsl:call-template name="CreateGroupChrPr">
+                        <xsl:with-param name="chr">
+                          <xsl:value-of select="mml:mo" />
+                        </xsl:with-param>
+                        <xsl:with-param name="pos">
+                          <xsl:choose>
+                            <xsl:when test="child::*[1][self::mml:mrow]">top</xsl:when>
+                            <xsl:otherwise>bot</xsl:otherwise>
+                          </xsl:choose>
+                        </xsl:with-param>
+                        <xsl:with-param name="vertJc">bot</xsl:with-param>
+                      </xsl:call-template>
+                      <xsl:element name="m:e">
+                        <xsl:apply-templates select="mml:mrow" />
+                      </xsl:element>
+                    </xsl:element>
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <!-- Generic mover -->
+                    <xsl:element name="m:limUpp">
+                      <xsl:element name="m:e">
+                        <xsl:call-template name="CreateArgProp" />
+                        <xsl:apply-templates select="child::*[1]" />
+                      </xsl:element>
+                      <xsl:element name="m:lim">
+                        <xsl:call-template name="CreateArgProp" />
+                        <xsl:apply-templates select="child::*[2]" />
+                      </xsl:element>
+                    </xsl:element>
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- %%Template: match munderover
+	-->
+  <xsl:template match="mml:munderover">
+    <xsl:variable name="fNary">
+      <xsl:call-template name="isNary">
+        <xsl:with-param name="ndCur" select="child::*[1]" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fNary='true'">
+        <m:nary>
+          <xsl:call-template name="CreateNaryProp">
+            <xsl:with-param name="chr">
+              <xsl:value-of select="normalize-space(child::*[1])" />
+            </xsl:with-param>
+            <xsl:with-param name="sMathmlType" select="'munderover'" />
+          </xsl:call-template>
+          <m:sub>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sub>
+          <m:sup>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[3]" />
+          </m:sup>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:call-template name="NaryHandleMrowMstyle">
+              <xsl:with-param name="ndCur" select="following-sibling::*[1]" />
+            </xsl:call-template>
+          </m:e>
+        </m:nary>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:element name="m:limUpp">
+          <xsl:element name="m:e">
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:element name="m:limLow">
+              <xsl:element name="m:e">
+                <xsl:call-template name="CreateArgProp" />
+                <xsl:apply-templates select="child::*[1]" />
+              </xsl:element>
+              <xsl:element name="m:lim">
+                <xsl:call-template name="CreateArgProp" />
+                <xsl:apply-templates select="child::*[2]" />
+              </xsl:element>
+            </xsl:element>
+          </xsl:element>
+          <xsl:element name="m:lim">
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[3]" />
+          </xsl:element>
+        </xsl:element>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: match mfenced -->
+  <xsl:template match="mml:mfenced">
+    <m:d>
+      <xsl:call-template name="CreateDelimProp">
+        <xsl:with-param name="fChOpenValid">
+          <xsl:choose>
+            <xsl:when test="@open">
+              <xsl:value-of select="1"/>
+            </xsl:when>
+            <xsl:when test="@mml:open">
+              <xsl:value-of select="1"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="0"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="chOpen">
+          <xsl:choose>
+            <xsl:when test="@open">
+              <xsl:value-of select="@open"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@mml:open"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="fChSeparatorsValid">
+          <xsl:choose>
+            <xsl:when test="@separators">
+              <xsl:value-of select="1"/>
+            </xsl:when>
+            <xsl:when test="@mml:separators">
+              <xsl:value-of select="1"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="0"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="chSeparators">
+          <xsl:choose>
+            <xsl:when test="@separators">
+              <xsl:value-of select="@separators"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@mml:separators"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="fChCloseValid">
+          <xsl:choose>
+            <xsl:when test="@close">
+              <xsl:value-of select="1"/>
+            </xsl:when>
+            <xsl:when test="@mml:close">
+              <xsl:value-of select="1"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="0"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+        <xsl:with-param name="chClose">
+          <xsl:choose>
+            <xsl:when test="@close">
+              <xsl:value-of select="@close"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@mml:close"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:with-param>
+      </xsl:call-template>
+      <xsl:for-each select="*">
+        <m:e>
+          <xsl:call-template name="CreateArgProp" />
+          <xsl:apply-templates select="."/>
+        </m:e>
+      </xsl:for-each>
+    </m:d>
+  </xsl:template>
+
+  <!-- %%Template: CreateDelimProp
+	
+		Given the characters to use as open, close and separators for 
+		the delim object, create the m:dPr (delim properties). 		
+		
+		MathML can have any number of separators in an mfenced object, but 
+		OMML can only represent one separator for each d (delim) object.
+		So, we pick the first separator specified. 		
+	-->
+  <xsl:template name="CreateDelimProp">
+    <xsl:param name="fChOpenValid" />
+    <xsl:param name="chOpen" />
+    <xsl:param name="fChSeparatorsValid" />
+    <xsl:param name="chSeparators" />
+    <xsl:param name="fChCloseValid" />
+    <xsl:param name="chClose" />
+    <xsl:variable name="chSep" select="substring($chSeparators, 1, 1)" />
+
+    <!-- do we need a dPr at all? If everything's at its default value, then 
+			don't bother at all -->
+    <xsl:if test="($fChOpenValid=1 and not($chOpen = '(')) or
+						  ($fChCloseValid=1 and not($chClose = ')')) or 
+						  not($chSep = '|')">
+      <m:dPr>
+        <!-- the default for MathML and OMML is '('. -->
+        <xsl:if test="$fChOpenValid=1 and not($chOpen = '(')">
+          <m:begChr>
+            <xsl:attribute name="m:val">
+              <xsl:value-of select="$chOpen" />
+            </xsl:attribute>
+          </m:begChr>
+        </xsl:if>
+
+        <!-- the default for MathML is ',' and for OMML is '|' -->
+
+        <xsl:choose>
+          <!-- matches OMML's default, don't bother to write anything out -->
+          <xsl:when test="$chSep = '|'" />
+
+          <!-- Not specified, use MathML's default. We test against 
+					the existence of the actual attribute, not the substring -->
+          <xsl:when test="$fChSeparatorsValid=0">
+            <m:sepChr m:val=',' />
+          </xsl:when>
+
+          <xsl:otherwise>
+            <m:sepChr>
+              <xsl:attribute name="m:val">
+                <xsl:value-of select="$chSep" />
+              </xsl:attribute>
+            </m:sepChr>
+          </xsl:otherwise>
+        </xsl:choose>
+
+        <!-- the default for MathML and OMML is ')'. -->
+        <xsl:if test="$fChCloseValid=1 and not($chClose = ')')">
+          <m:endChr>
+            <xsl:attribute name="m:val">
+              <xsl:value-of select="$chClose" />
+            </xsl:attribute>
+          </m:endChr>
+        </xsl:if>
+      </m:dPr>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template name="LQuoteFromMs">
+    <xsl:param name="msCur" select="." />
+    <xsl:choose>
+      <xsl:when test="(not($msCur/@lquote) or $msCur/@lquote='')
+                      and (not($msCur/@mml:lquote) or $msCur/@mml:lquote='')">
+        <xsl:text>"</xsl:text>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:choose>
+          <xsl:when test="$msCur/@lquote">
+            <xsl:value-of select="$msCur/@lquote"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="$msCur/@mml:lquote"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="RQuoteFromMs">
+    <xsl:param name="msCur" select="." />
+    <xsl:choose>
+      <xsl:when test="(not($msCur/@rquote) or $msCur/@rquote='')
+                       and (not($msCur/@mml:rquote) or $msCur/@mml:rquote='')">
+        <xsl:text>"</xsl:text>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:choose>
+          <xsl:when test="$msCur/@rquote">
+            <xsl:value-of select="$msCur/@rquote"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="$msCur/@mml:rquote"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: OutputMs
+	-->
+  <xsl:template name="OutputMs">
+    <xsl:param name="msCur" />
+
+    <xsl:variable name="chLquote">
+      <xsl:call-template name="LQuoteFromMs">
+        <xsl:with-param name="msCur" select="$msCur" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:variable name="chRquote">
+      <xsl:call-template name="RQuoteFromMs">
+        <xsl:with-param name="msCur" select="$msCur" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:value-of select="$chLquote"/>
+    <xsl:value-of select="normalize-space($msCur)" />
+    <xsl:value-of select="$chRquote"/>
+  </xsl:template>
+
+  <!-- %%Template: match msub
+	-->
+  <xsl:template match="mml:msub">
+    <xsl:variable name="fNary">
+      <xsl:call-template name="isNary">
+        <xsl:with-param name="ndCur" select="child::*[1]" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fNary='true'">
+        <m:nary>
+          <xsl:call-template name="CreateNaryProp">
+            <xsl:with-param name="chr">
+              <xsl:value-of select="normalize-space(child::*[1])" />
+            </xsl:with-param>
+            <xsl:with-param name="sMathmlType" select="'msub'" />
+          </xsl:call-template>
+          <m:sub>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sub>
+          <m:sup>
+            <xsl:call-template name="CreateArgProp" />
+          </m:sup>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:call-template name="NaryHandleMrowMstyle">
+              <xsl:with-param name="ndCur" select="following-sibling::*[1]" />
+            </xsl:call-template>
+          </m:e>
+        </m:nary>
+      </xsl:when>
+      <xsl:otherwise>
+        <m:sSub>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[1]" />
+          </m:e>
+          <m:sub>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sub>
+        </m:sSub>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: match msup
+	-->
+  <xsl:template match="mml:msup">
+    <xsl:variable name="fNary">
+      <xsl:call-template name="isNary">
+        <xsl:with-param name="ndCur" select="child::*[1]" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fNary='true'">
+        <m:nary>
+          <xsl:call-template name="CreateNaryProp">
+            <xsl:with-param name="chr">
+              <xsl:value-of select="normalize-space(child::*[1])" />
+            </xsl:with-param>
+            <xsl:with-param name="sMathmlType" select="'msup'" />
+          </xsl:call-template>
+          <m:sub>
+            <xsl:call-template name="CreateArgProp" />
+          </m:sub>
+          <m:sup>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sup>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:call-template name="NaryHandleMrowMstyle">
+              <xsl:with-param name="ndCur" select="following-sibling::*[1]" />
+            </xsl:call-template>
+          </m:e>
+        </m:nary>
+      </xsl:when>
+      <xsl:otherwise>
+        <m:sSup>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[1]" />
+          </m:e>
+          <m:sup>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sup>
+        </m:sSup>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: match msubsup
+	-->
+  <xsl:template match="mml:msubsup">
+    <xsl:variable name="fNary">
+      <xsl:call-template name="isNary">
+        <xsl:with-param name="ndCur" select="child::*[1]" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fNary='true'">
+        <m:nary>
+          <xsl:call-template name="CreateNaryProp">
+            <xsl:with-param name="chr">
+              <xsl:value-of select="normalize-space(child::*[1])" />
+            </xsl:with-param>
+            <xsl:with-param name="sMathmlType" select="'msubsup'" />
+          </xsl:call-template>
+          <m:sub>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sub>
+          <m:sup>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[3]" />
+          </m:sup>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:call-template name="NaryHandleMrowMstyle">
+              <xsl:with-param name="ndCur" select="following-sibling::*[1]" />
+            </xsl:call-template>
+          </m:e>
+        </m:nary>
+      </xsl:when>
+      <xsl:otherwise>
+        <m:sSubSup>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[1]" />
+          </m:e>
+          <m:sub>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[2]" />
+          </m:sub>
+          <m:sup>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[3]" />
+          </m:sup>
+        </m:sSubSup>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: SplitScripts 
+	
+		Takes an collection of nodes, and splits them
+		odd and even into sup and sub scripts. Used for dealing with
+		mmultiscript.
+		
+		This template assumes you want to output both a sub and sup element.
+		-->
+  <xsl:template name="SplitScripts">
+    <xsl:param name="ndScripts" />
+    <m:sub>
+      <xsl:call-template name="CreateArgProp" />
+      <xsl:apply-templates select="$ndScripts[(position() mod 2) = 1]" />
+    </m:sub>
+    <m:sup>
+      <xsl:call-template name="CreateArgProp" />
+      <xsl:apply-templates select="$ndScripts[(position() mod 2) = 0]" />
+    </m:sup>
+  </xsl:template>
+
+  <!-- %%Template: match mmultiscripts
+	
+		There is some subtlety with the mml:mprescripts element. Everything that comes before 
+		that is considered a script (as opposed to a pre-script), but it need not be present.
+	-->
+  <xsl:template match="mml:mmultiscripts">
+
+    <!-- count the nodes. Everything that comes after a mml:mprescripts is considered a pre-script;
+			Everything that does not have an mml:mprescript as a preceding-sibling (and is not itself 
+			mml:mprescript) is a script, except for the first child which is always the base.
+			The mml:none element is a place holder for a sub/sup element slot.
+			
+			mmultisript pattern:
+			<mmultiscript>
+				(base)
+				(sub sup)* // Where <none/> can replace a sub/sup entry to preserve pattern.
+				<mprescripts />
+				(presub presup)*
+			</mmultiscript>
+			-->
+    <!-- Count of presecript nodes that we'd print (this is essentially anything but the none placeholder. -->
+    <xsl:variable name="cndPrescriptStrict" select="count(mml:mprescripts[1]/following-sibling::*[not(self::mml:none)])" />
+    <!-- Count of all super script excluding mml:none -->
+    <xsl:variable name="cndSuperScript" select="count(*[not(preceding-sibling::mml:mprescripts)
+																														and not(self::mml:mprescripts)
+																														and ((position() mod 2) = 1) 
+																														and not(self::mml:none)]) - 1"/>
+    <!-- Count of all sup script excluding mml:none -->
+    <xsl:variable name="cndSubScript" select="count(*[not(preceding-sibling::mml:mprescripts)
+																														and not(self::mml:mprescripts)
+																														and ((position() mod 2) = 0) 
+																														and not(self::mml:none)])"/>
+    <!-- Count of all scripts excluding mml:none -->
+    <xsl:variable name="cndScriptStrict" select="$cndSuperScript + $cndSubScript" />
+    <!-- Count of all scripts including mml:none.  This is essentially all nodes before the 
+		first mml:mprescripts except the base. -->
+    <xsl:variable name="cndScript" select="count(*[not(preceding-sibling::mml:mprescripts) and not(self::mml:mprescripts)]) - 1" />
+
+    <xsl:choose>
+      <!-- The easy case first. No prescripts, and no script ... just a base -->
+      <xsl:when test="$cndPrescriptStrict &lt;= 0 and $cndScriptStrict &lt;= 0">
+        <xsl:apply-templates select="*[1]" />
+      </xsl:when>
+
+      <!-- Next, if there are no prescripts -->
+      <xsl:when test="$cndPrescriptStrict &lt;= 0">
+        <!-- we know we have some scripts or else we would have taken the earlier
+					  branch. -->
+        <xsl:choose>
+          <!-- We have both sub and super scripts-->
+          <xsl:when test="$cndSuperScript &gt; 0 and $cndSubScript &gt; 0">
+            <m:sSubSup>
+              <m:e>
+                <xsl:call-template name="CreateArgProp" />
+                <xsl:apply-templates select="child::*[1]" />
+              </m:e>
+
+              <!-- Every child except the first is a script.  Do the split -->
+              <xsl:call-template name="SplitScripts">
+                <xsl:with-param name="ndScripts" select="*[position() &gt; 1]" />
+              </xsl:call-template>
+            </m:sSubSup>
+          </xsl:when>
+          <!-- Just a sub script -->
+          <xsl:when test="$cndSubScript &gt; 0">
+            <m:sSub>
+              <m:e>
+                <xsl:call-template name="CreateArgProp" />
+                <xsl:apply-templates select="child::*[1]" />
+              </m:e>
+
+              <!-- No prescripts and no super scripts, therefore, it's a sub. -->
+              <m:sub>
+                <xsl:apply-templates select="*[position() &gt; 1]" />
+              </m:sub>
+            </m:sSub>
+          </xsl:when>
+          <!-- Just super script -->
+          <xsl:otherwise>
+            <m:sSup>
+              <m:e>
+                <xsl:call-template name="CreateArgProp" />
+                <xsl:apply-templates select="child::*[1]" />
+              </m:e>
+
+              <!-- No prescripts and no sub scripts, therefore, it's a sup. -->
+              <m:sup>
+                <xsl:apply-templates select="*[position() &gt; 1]" />
+              </m:sup>
+            </m:sSup>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+
+      <!-- Next, if there are no scripts -->
+      <xsl:when test="$cndScriptStrict &lt;= 0">
+        <!-- we know we have some prescripts or else we would have taken the earlier
+					  branch. So, create an sPre and split the elements -->
+        <m:sPre>
+          <m:e>
+            <xsl:call-template name="CreateArgProp" />
+            <xsl:apply-templates select="child::*[1]" />
+          </m:e>
+
+          <!-- The prescripts come after the mml:mprescript and if we get here
+							we know there exists some elements after the mml:mprescript element. 
+							
+							The prescript element has no sub/subsup variation, therefore, even if
+							we're only writing sub, we need to write out both the sub and sup element.
+							-->
+          <xsl:call-template name="SplitScripts">
+            <xsl:with-param name="ndScripts" select="mml:mprescripts[1]/following-sibling::*" />
+          </xsl:call-template>
+        </m:sPre>
+      </xsl:when>
+
+      <!-- Finally, the case with both prescripts and scripts. Create an sPre 
+				element to house the prescripts, with a sub/sup/subsup element at its base. -->
+      <xsl:otherwise>
+        <m:sPre>
+          <m:e>
+            <xsl:choose>
+              <!-- We have both sub and super scripts-->
+              <xsl:when test="$cndSuperScript &gt; 0 and $cndSubScript &gt; 0">
+                <m:sSubSup>
+                  <m:e>
+                    <xsl:call-template name="CreateArgProp" />
+                    <xsl:apply-templates select="child::*[1]" />
+                  </m:e>
+
+                  <!-- scripts come before the mml:mprescript but after the first child, so their
+								 positions will be 2, 3, ... ($nndScript + 1) -->
+                  <xsl:call-template name="SplitScripts">
+                    <xsl:with-param name="ndScripts" select="*[(position() &gt; 1) and (position() &lt;= ($cndScript + 1))]" />
+                  </xsl:call-template>
+                </m:sSubSup>
+              </xsl:when>
+              <!-- Just a sub script -->
+              <xsl:when test="$cndSubScript &gt; 0">
+                <m:sSub>
+                  <m:e>
+                    <xsl:call-template name="CreateArgProp" />
+                    <xsl:apply-templates select="child::*[1]" />
+                  </m:e>
+
+                  <!-- We have prescripts but no super scripts, therefore, do a sub 
+									and apply templates to all tokens counted by cndScript. -->
+                  <m:sub>
+                    <xsl:apply-templates select="*[position() &gt; 1 and (position() &lt;= ($cndScript + 1))]" />
+                  </m:sub>
+                </m:sSub>
+              </xsl:when>
+              <!-- Just super script -->
+              <xsl:otherwise>
+                <m:sSup>
+                  <m:e>
+                    <xsl:call-template name="CreateArgProp" />
+                    <xsl:apply-templates select="child::*[1]" />
+                  </m:e>
+
+                  <!-- We have prescripts but no sub scripts, therefore, do a sub 
+									and apply templates to all tokens counted by cndScript. -->
+                  <m:sup>
+                    <xsl:apply-templates select="*[position() &gt; 1 and (position() &lt;= ($cndScript + 1))]" />
+                  </m:sup>
+                </m:sSup>
+              </xsl:otherwise>
+            </xsl:choose>
+          </m:e>
+
+          <!-- The prescripts come after the mml:mprescript and if we get here
+							we know there exists one such element -->
+          <xsl:call-template name="SplitScripts">
+            <xsl:with-param name="ndScripts" select="mml:mprescripts[1]/following-sibling::*" />
+          </xsl:call-template>
+        </m:sPre>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Template that determines if ndCur is an equation array.
+				
+			 ndCur is an equation array if:
+			 
+			 1.  There are are no frame lines
+			 2.  There are no column lines
+			 3.  There are no row lines
+			 4.  There is no row with more than 1 column  
+			 5.  There is no row with fewer than 1 column
+			 6.  There are no labeled rows.
+			 
+	-->
+  <xsl:template name="FIsEqArray">
+    <xsl:param name="ndCur" select="." />
+
+    <!-- There should be no frame, columnlines, or rowlines -->
+    <xsl:choose>
+      <xsl:when test="(not($ndCur/@frame) or $ndCur/@frame='' or $ndCur/@frame='none')
+                      and (not($ndCur/@mml:frame) or $ndCur/@mml:frame='' or $ndCur/@mml:frame='none')
+								      and (not($ndCur/@columnlines) or $ndCur/@columnlines='' or $ndCur/@columnlines='none')
+                      and (not($ndCur/@mml:columnlines) or $ndCur/@mml:columnlines='' or $ndCur/@mml:columnlines='none')
+								      and (not($ndCur/@rowlines) or $ndCur/@rowlines='' or $ndCur/@rowlines='none')
+                      and (not($ndCur/@mml:rowlines) or $ndCur/@mml:rowlines='' or $ndCur/@mml:rowlines='none')
+								      and not($ndCur/mml:mtr[count(mml:mtd) &gt; 1])
+											and not($ndCur/mml:mtr[count(mml:mtd) &lt; 1])
+								      and not($ndCur/mml:mlabeledtr)">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Template used to determine if we should ignore a collection when iterating through 
+	     a mathml equation array row.
+	
+			 So far, the only thing that needs to be ignored is the argument of an nary.  We
+			 can ignore this since it is output when we apply-templates to the munder[over]/msub[sup].
+	-->
+  <xsl:template name="FIgnoreCollection">
+    <xsl:param name="ndCur" select="." />
+
+    <xsl:variable name="fNaryArgument">
+      <xsl:call-template name="FIsNaryArgument">
+        <xsl:with-param name="ndCur" select="$ndCur" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:choose>
+      <xsl:when test="$fNaryArgument=1">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Template used to determine if we've already encountered an maligngroup or malignmark.
+	
+			 This is needed because omml has an implicit spacing alignment (omml spacing alignment = 
+			 mathml's maligngroup element) at the beginning of each equation array row.  Therefore, 
+			 the first maligngroup (implied or explicit) we encounter does not need to be output.  
+			 This template recursively searches up the xml tree and looks at previous siblings to see 
+			 if they have a descendant that is an maligngroup or malignmark.  We look for the malignmark 
+			 to find the implicit maligngroup.
+	-->
+  <xsl:template name="FFirstAlignAlreadyFound">
+    <xsl:param name="ndCur" select="." />
+
+    <xsl:choose>
+      <xsl:when test="count($ndCur/preceding-sibling::*[descendant-or-self::mml:maligngroup
+								                                        or descendant-or-self::mml:malignmark]) &gt; 0">1</xsl:when>
+      <xsl:when test="not($ndCur/parent::mml:mtd)">
+        <xsl:call-template name="FFirstAlignAlreadyFound">
+          <xsl:with-param name="ndCur" select="$ndCur/parent::*" />
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- This template builds a string that is result of concatenating a given string several times. 
+	
+			 Given strToRepeat, create a string that has strToRepeat repeated iRepitions times. 
+	-->
+  <xsl:template name="ConcatStringRepeat">
+    <xsl:param name="strToRepeat" select="''" />
+    <xsl:param name="iRepetitions" select="0" />
+    <xsl:param name="strBuilding" select="''" />
+
+    <xsl:choose>
+      <xsl:when test="$iRepetitions &lt;= 0">
+        <xsl:value-of select="$strBuilding" />
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="ConcatStringRepeat">
+          <xsl:with-param name="strToRepeat" select="$strToRepeat" />
+          <xsl:with-param name="iRepetitions" select="$iRepetitions - 1" />
+          <xsl:with-param name="strBuilding" select="concat($strBuilding, $strToRepeat)" />
+        </xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- This template determines if ndCur is a special collection.
+			 By special collection, I mean is ndCur the outer element of some special grouping 
+			 of mathml elements that actually represents some over all omml structure.
+			 
+			 For instance, is ndCur a linear fraction, or an omml function.
+	-->
+  <xsl:template name="FSpecialCollection">
+    <xsl:param name="ndCur" select="." />
+    <xsl:choose>
+      <xsl:when test="$ndCur/self::mml:mrow">
+        <xsl:variable name="fLinearFraction">
+          <xsl:call-template name="FLinearFrac">
+            <xsl:with-param name="ndCur" select="$ndCur"/>
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:variable name="fFunc">
+          <xsl:call-template name="FIsFunc">
+            <xsl:with-param name="ndCur" select="$ndCur" />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:choose>
+          <xsl:when test="$fLinearFraction=1 or $fFunc=1">1</xsl:when>
+          <xsl:otherwise>0</xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- This template iterates through the children of an equation array row (mtr) and outputs
+	     the equation.
+			 
+			 This template does all the work to output ampersands and skip the right elements when needed.
+	-->
+  <xsl:template name="ProcessEqArrayRow">
+    <xsl:param name="ndCur" select="." />
+
+    <xsl:for-each select="$ndCur/*">
+      <xsl:variable name="fSpecialCollection">
+        <xsl:call-template name="FSpecialCollection">
+          <xsl:with-param name="ndCur" select="." />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:variable name="fIgnoreCollection">
+        <xsl:call-template name="FIgnoreCollection">
+          <xsl:with-param name="ndCur" select="." />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:choose>
+        <!-- If we have an alignment element output the ampersand. -->
+        <xsl:when test="self::mml:maligngroup or self::mml:malignmark">
+          <!-- Omml has an implied spacing alignment at the beginning of each equation.
+					     Therefore, if this is the first ampersand to be output, don't actually output. -->
+          <xsl:variable name="fFirstAlignAlreadyFound">
+            <xsl:call-template name="FFirstAlignAlreadyFound">
+              <xsl:with-param name="ndCur" select="." />
+            </xsl:call-template>
+          </xsl:variable>
+          <!-- Don't output unless it is an malignmark or we have already previously found an alignment point. -->
+          <xsl:if test="self::mml:malignmark or $fFirstAlignAlreadyFound=1">
+            <m:r>
+              <m:t>&amp;</m:t>
+            </m:r>
+          </xsl:if>
+        </xsl:when>
+        <!-- If this node is an non-special mrow or mstyle and we aren't supposed to ignore this collection, then
+				     go ahead an apply templates to this node. -->
+        <xsl:when test="$fIgnoreCollection=0 and ((self::mml:mrow and $fSpecialCollection=0) or self::mml:mstyle)">
+          <xsl:call-template name="ProcessEqArrayRow">
+            <xsl:with-param name="ndCur" select="." />
+          </xsl:call-template>
+        </xsl:when>
+        <!-- At this point we have some mathml structure (fraction, nary, non-grouping element, etc.) -->
+        <!-- If this mathml structure has alignment groups or marks as children, then extract those since
+				     omml can't handle that. -->
+        <xsl:when test="descendant::mml:maligngroup or descendant::mml:malignmark">
+          <xsl:variable name="cMalignGroups">
+            <xsl:value-of select="count(descendant::mml:maligngroup)" />
+          </xsl:variable>
+          <xsl:variable name="cMalignMarks">
+            <xsl:value-of select="count(descendant::mml:malignmark)" />
+          </xsl:variable>
+          <!-- Output all maligngroups and malignmarks as '&' -->
+          <xsl:if test="$cMalignGroups + $cMalignMarks &gt; 0">
+            <xsl:variable name="str">
+              <xsl:call-template name="ConcatStringRepeat">
+                <xsl:with-param name="strToRepeat" select="'&amp;'" />
+                <xsl:with-param name="iRepetitions" select="$cMalignGroups + $cMalignMarks" />
+                <xsl:with-param name="strBuilding" select="''" />
+              </xsl:call-template>
+            </xsl:variable>
+            <xsl:element name="m:r">
+              <xsl:element name="m:t">
+                <xsl:call-template name="OutputText">
+                  <xsl:with-param name="sInput" select="$str" />
+                </xsl:call-template>
+              </xsl:element>
+            </xsl:element>
+          </xsl:if>
+          <!-- Now that the '&' have been extracted, just apply-templates to this node.-->
+          <xsl:apply-templates select="." />
+        </xsl:when>
+        <!-- If there are no alignment points as descendants, then go ahead and output this node. -->
+        <xsl:otherwise>
+          <xsl:apply-templates select="." />
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:for-each>
+  </xsl:template>
+
+  <!-- This template transforms mtable into its appropriate omml type.
+	
+			 There are two possible omml constructs that an mtable can become:  a matrix or 
+			 an equation array.
+			 
+			 Because omml has no generic table construct, the omml matrix is the best approximate
+			 for a mathml table.
+			 
+			 Our equation array transformation is very simple.  The main goal of this transform is to
+			 allow roundtripping omml eq arrays through mathml.  The template ProcessEqArrayRow was never
+			 intended to account for many of the alignment flexibilities that are present in mathml like 
+			 using the alig attribute, using alignmark attribute in token elements, etc.
+			 
+			 The restrictions on this transform require <malignmark> and <maligngroup> elements to be outside of
+			 any non-grouping mathml elements (that is, mrow and mstyle).  Moreover, these elements cannot be the children of
+			 mrows that represent linear fractions or functions.  Also, <malignmark> cannot be a child
+			 of token attributes.
+			 
+			 In the case that the above 
+	
+	-->
+  <xsl:template match="mml:mtable">
+    <xsl:variable name="fEqArray">
+      <xsl:call-template name="FIsEqArray">
+        <xsl:with-param name="ndCur" select="." />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fEqArray=1">
+        <xsl:element name="m:eqArr">
+          <xsl:for-each select="mml:mtr">
+            <xsl:element name="m:e">
+              <xsl:call-template name="ProcessEqArrayRow">
+                <xsl:with-param name="ndCur" select="mml:mtd" />
+              </xsl:call-template>
+            </xsl:element>
+          </xsl:for-each>
+        </xsl:element>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="cMaxElmtsInRow">
+          <xsl:call-template name="CountMaxElmtsInRow">
+            <xsl:with-param name="ndCur" select="*[1]" />
+            <xsl:with-param name="cMaxElmtsInRow" select="0" />
+          </xsl:call-template>
+        </xsl:variable>
+        <m:m>
+          <m:mPr>
+            <m:baseJc m:val="center" />
+            <m:plcHide m:val="on" />
+            <m:mcs>
+              <m:mc>
+                <m:mcPr>
+                  <m:count>
+                    <xsl:attribute name="m:val">
+                      <xsl:value-of select="$cMaxElmtsInRow" />
+                    </xsl:attribute>
+                  </m:count>
+                  <m:mcJc m:val="center" />
+                </m:mcPr>
+              </m:mc>
+            </m:mcs>
+          </m:mPr>
+          <xsl:for-each select="*">
+            <xsl:choose>
+              <xsl:when test="self::mml:mtr or self::mml:mlabeledtr">
+                <m:mr>
+                  <xsl:choose>
+                    <xsl:when test="self::mml:mtr">
+                      <xsl:for-each select="*">
+                        <m:e>
+                          <xsl:apply-templates select="." />
+                        </m:e>
+                      </xsl:for-each>
+                      <xsl:call-template name="CreateEmptyElmt">
+                        <xsl:with-param name="cEmptyMtd" select="$cMaxElmtsInRow - count(*)" />
+                      </xsl:call-template>
+                    </xsl:when>
+                    <xsl:otherwise>
+                      <xsl:for-each select="*[position() &gt; 1]">
+                        <m:e>
+                          <xsl:apply-templates select="." />
+                        </m:e>
+                      </xsl:for-each>
+                      <xsl:call-template name="CreateEmptyElmt">
+                        <xsl:with-param name="cEmptyMtd" select="$cMaxElmtsInRow - (count(*) - 1)" />
+                      </xsl:call-template>
+                    </xsl:otherwise>
+                  </xsl:choose>
+                </m:mr>
+              </xsl:when>
+              <xsl:otherwise>
+                <m:mr>
+                  <m:e>
+                    <xsl:apply-templates select="." />
+                  </m:e>
+                  <xsl:call-template name="CreateEmptyElmt">
+                    <xsl:with-param name="cEmptyMtd" select="$cMaxElmtsInRow - 1" />
+                  </xsl:call-template>
+                </m:mr>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:for-each>
+        </m:m>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  <xsl:template match="m:mtd">
+    <xsl:apply-templates select="*" />
+  </xsl:template>
+  <xsl:template name="CreateEmptyElmt">
+    <xsl:param name="cEmptyMtd" />
+    <xsl:if test="$cEmptyMtd &gt; 0">
+      <m:e></m:e>
+      <xsl:call-template name="CreateEmptyElmt">
+        <xsl:with-param name="cEmptyMtd" select="$cEmptyMtd - 1" />
+      </xsl:call-template>
+    </xsl:if>
+  </xsl:template>
+  <xsl:template name="CountMaxElmtsInRow">
+    <xsl:param name="ndCur" />
+    <xsl:param name="cMaxElmtsInRow" select="0" />
+    <xsl:choose>
+      <xsl:when test="not($ndCur)">
+        <xsl:value-of select="$cMaxElmtsInRow" />
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="CountMaxElmtsInRow">
+          <xsl:with-param name="ndCur" select="$ndCur/following-sibling::*[1]" />
+          <xsl:with-param name="cMaxElmtsInRow">
+            <xsl:choose>
+              <xsl:when test="local-name($ndCur) = 'mlabeledtr' and 
+								            namespace-uri($ndCur) = 'http://www.w3.org/1998/Math/MathML'">
+                <xsl:choose>
+                  <xsl:when test="(count($ndCur/*) - 1) &gt; $cMaxElmtsInRow">
+                    <xsl:value-of select="count($ndCur/*) - 1" />
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="$cMaxElmtsInRow" />
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:when>
+              <xsl:when test="local-name($ndCur) = 'mtr' and 
+								            namespace-uri($ndCur) = 'http://www.w3.org/1998/Math/MathML'">
+                <xsl:choose>
+                  <xsl:when test="count($ndCur/*) &gt; $cMaxElmtsInRow">
+                    <xsl:value-of select="count($ndCur/*)" />
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="$cMaxElmtsInRow" />
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:choose>
+                  <xsl:when test="1 &gt; $cMaxElmtsInRow">
+                    <xsl:value-of select="1" />
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="$cMaxElmtsInRow" />
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:with-param>
+        </xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="GetMglyphAltText">
+    <xsl:param name="ndCur" select="." />
+    <xsl:choose>
+      <xsl:when test="$ndCur/@alt">
+        <xsl:value-of select="normalize-space($ndCur/@alt)"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="normalize-space($ndCur/@mml:alt)"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="mml:mglyph">
+    <xsl:element name="m:r">
+      <xsl:element name="m:rPr">
+        <xsl:element name="m:nor" />
+      </xsl:element>
+      <xsl:element name="m:t">
+        <xsl:call-template name="OutputText">
+          <xsl:with-param name="sInput">
+            <xsl:call-template name="GetMglyphAltText">
+              <xsl:with-param name="ndCur" select="." />
+            </xsl:call-template>
+          </xsl:with-param>
+        </xsl:call-template>
+      </xsl:element>
+    </xsl:element>
+  </xsl:template>
+
+  <!-- Omml doesn't really support mglyph, so just output the alt text -->
+  <xsl:template match="mml:mi[child::mml:mglyph] | 
+	                     mml:mn[child::mml:mglyph] | 
+	                     mml:mo[child::mml:mglyph] | 
+	                     mml:ms[child::mml:mglyph] | 
+	                     mml:mtext[child::mml:mglyph]">
+    <xsl:variable name="mathvariant">
+      <xsl:choose>
+        <xsl:when test="@mathvariant">
+          <xsl:value-of select="@mathvariant"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@mml:mathvariant"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="fontstyle">
+      <xsl:choose>
+        <xsl:when test="@fontstyle">
+          <xsl:value-of select="@fontstyle"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@mml:fontstyle"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="fontweight">
+      <xsl:choose>
+        <xsl:when test="@fontweight">
+          <xsl:value-of select="@fontweight"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@mml:fontweight"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="mathcolor">
+      <xsl:choose>
+        <xsl:when test="@mathcolor">
+          <xsl:value-of select="@mathcolor"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@mml:mathcolor"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="mathsize">
+      <xsl:choose>
+        <xsl:when test="@mathsize">
+          <xsl:value-of select="@mathsize"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@mml:mathsize"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="color">
+      <xsl:choose>
+        <xsl:when test="@color">
+          <xsl:value-of select="@color"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@mml:color"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="fontsize">
+      <xsl:choose>
+        <xsl:when test="@fontsize">
+          <xsl:value-of select="@fontsize"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@mml:fontsize"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="fNor">
+      <xsl:call-template name="FNor">
+        <xsl:with-param name="ndCur" select="." />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <!-- Output MS Left Quote (if need be) -->
+    <xsl:if test="self::mml:ms">
+      <xsl:variable name="chLquote">
+        <xsl:call-template name="LQuoteFromMs">
+          <xsl:with-param name="curMs" select="." />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:element name="m:r">
+        <xsl:call-template name="CreateRunProp">
+          <xsl:with-param name="mathvariant" select="$mathvariant" />
+          <xsl:with-param name="fontstyle" select="$fontstyle" />
+          <xsl:with-param name="fontweight" select="$fontweight" />
+          <xsl:with-param name="mathcolor" select="$mathcolor" />
+          <xsl:with-param name="mathsize" select="$mathsize" />
+          <xsl:with-param name="color" select="$color" />
+          <xsl:with-param name="fontsize" select="$fontsize" />
+          <xsl:with-param name="fNor" select="$fNor" />
+          <xsl:with-param name="ndCur" select="." />
+        </xsl:call-template>
+        <xsl:element name="m:t">
+          <xsl:call-template name="OutputText">
+            <xsl:with-param name="sInput" select="$chLquote"/>
+          </xsl:call-template>
+        </xsl:element>
+      </xsl:element>
+    </xsl:if>
+    <xsl:for-each select="mml:mglyph | text()">
+      <xsl:variable name="fForceNor">
+        <xsl:choose>
+          <xsl:when test="self::mml:mglyph">1</xsl:when>
+          <xsl:otherwise>0</xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+
+      <xsl:variable name="str">
+        <xsl:choose>
+          <xsl:when test="self::mml:mglyph">
+            <xsl:call-template name="GetMglyphAltText">
+              <xsl:with-param name="ndCur" select="." />
+            </xsl:call-template>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="normalize-space(.)"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+      <xsl:if test="string-length($str) &gt; 0">
+        <xsl:element name="m:r">
+          <xsl:call-template name="CreateRunProp">
+            <xsl:with-param name="mathvariant" select="$mathvariant" />
+            <xsl:with-param name="fontstyle" select="$fontstyle" />
+            <xsl:with-param name="fontweight" select="$fontweight" />
+            <xsl:with-param name="mathcolor" select="$mathcolor" />
+            <xsl:with-param name="mathsize" select="$mathsize" />
+            <xsl:with-param name="color" select="$color" />
+            <xsl:with-param name="fontsize" select="$fontsize" />
+            <xsl:with-param name="fNor">
+              <xsl:choose>
+                <xsl:when test="$fForceNor=1">1</xsl:when>
+                <xsl:otherwise>
+                  <xsl:value-of select="$fNor"/>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+            <xsl:with-param name="ndCur" select="." />
+          </xsl:call-template>
+          <xsl:element name="m:t">
+            <xsl:call-template name="OutputText">
+              <xsl:with-param name="sInput" select="$str"/>
+            </xsl:call-template>
+          </xsl:element>
+        </xsl:element>
+      </xsl:if>
+    </xsl:for-each>
+
+    <!-- Output MS Right Quote (if need be) -->
+    <xsl:if test="self::mml:ms">
+      <xsl:variable name="chRquote">
+        <xsl:call-template name="RQuoteFromMs">
+          <xsl:with-param name="curMs" select="." />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:element name="m:r">
+        <xsl:call-template name="CreateRunProp">
+          <xsl:with-param name="mathvariant" select="$mathvariant" />
+          <xsl:with-param name="fontstyle" select="$fontstyle" />
+          <xsl:with-param name="fontweight" select="$fontweight" />
+          <xsl:with-param name="mathcolor" select="$mathcolor" />
+          <xsl:with-param name="mathsize" select="$mathsize" />
+          <xsl:with-param name="color" select="$color" />
+          <xsl:with-param name="fontsize" select="$fontsize" />
+          <xsl:with-param name="fNor" select="$fNor" />
+          <xsl:with-param name="ndCur" select="." />
+        </xsl:call-template>
+        <xsl:element name="m:t">
+          <xsl:call-template name="OutputText">
+            <xsl:with-param name="sInput" select="$chRquote"/>
+          </xsl:call-template>
+        </xsl:element>
+      </xsl:element>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template name="FStrContainsNonZeroDigit">
+    <xsl:param name="s" />
+
+    <!-- Translate any nonzero digit into a 9 -->
+    <xsl:variable name="sNonZeroDigitsToNineDigit" select="translate($s, '12345678', '99999999')" />
+    <xsl:choose>
+      <!-- Search for 9s -->
+      <xsl:when test="contains($sNonZeroDigitsToNineDigit, '9')">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="FStrContainsDigits">
+    <xsl:param name="s" />
+
+    <!-- Translate any digit into a 0 -->
+    <xsl:variable name="sDigitsToZeroDigit" select="translate($s, '123456789', '000000000')" />
+    <xsl:choose>
+      <!-- Search for 0s -->
+      <xsl:when test="contains($sDigitsToZeroDigit, '0')">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- Used to determine if mpadded attribute {width, height, depth } 
+       indicates to show everything. 
+       
+       Unlike mathml, whose mpadded structure has great flexibility in modifying the 
+       bounding box's width, height, and depth, Word can only have zero or full width, height, and depth.
+       Thus, if the width, height, or depth attributes indicate any kind of nonzero width, height, 
+       or depth, we'll translate that into a show full width, height, or depth for OMML.  Only if the attribute
+       indicates a zero width, height, or depth, will we report back FFull as false.
+       
+       Example:  s=0%    ->  FFull returns 0.
+                 s=2%    ->  FFull returns 1.
+                 s=0.1em ->  FFull returns 1.     
+       
+       -->
+  <xsl:template name="FFull">
+    <xsl:param name="s" />
+
+    <xsl:variable name="fStrContainsNonZeroDigit">
+      <xsl:call-template name="FStrContainsNonZeroDigit">
+        <xsl:with-param name="s" select="$s" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:variable name="fStrContainsDigits">
+      <xsl:call-template name="FStrContainsDigits">
+        <xsl:with-param name="s" select="$s" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:choose>
+      <!-- String contained non-zero digit -->
+      <xsl:when test="$fStrContainsNonZeroDigit=1">1</xsl:when>
+      <!-- String didn't contain a non-zero digit, but it did contain digits.
+           This must mean that all digits in the string were 0s. -->
+      <xsl:when test="$fStrContainsDigits=1">0</xsl:when>
+      <!-- Else, no digits, therefore, return true.
+           We return true in the otherwise condition to take account for the possibility
+           in MathML to say something like width="height". -->
+      <xsl:otherwise>1</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- Just outputs phant properties, doesn't do any fancy 
+       thinking of its own, just obeys the defaults of 
+       phants. -->
+  <xsl:template name="CreatePhantPropertiesCore">
+    <xsl:param name="fShow" select="1" />
+    <xsl:param name="fFullWidth" select="1" />
+    <xsl:param name="fFullHeight" select="1" />
+    <xsl:param name="fFullDepth" select="1" />
+
+    <xsl:if test="$fShow=0 
+                    or $fFullWidth=0 
+                    or $fFullHeight=0
+                    or $fFullDepth=0">
+      <xsl:element name="m:phantPr">
+        <xsl:if test="$fShow=0">
+          <xsl:element name="m:show">
+            <xsl:attribute name="m:val">off</xsl:attribute>
+          </xsl:element>
+        </xsl:if>
+        <xsl:if test="$fFullWidth=0">
+          <xsl:element name="m:zeroWid">
+            <xsl:attribute name="m:val">on</xsl:attribute>
+          </xsl:element>
+        </xsl:if>
+        <xsl:if test="$fFullHeight=0">
+          <xsl:element name="m:zeroAsc">
+            <xsl:attribute name="m:val">on</xsl:attribute>
+          </xsl:element>
+        </xsl:if>
+        <xsl:if test="$fFullDepth=0">
+          <xsl:element name="m:zeroDesc">
+            <xsl:attribute name="m:val">on</xsl:attribute>
+          </xsl:element>
+        </xsl:if>
+      </xsl:element>
+    </xsl:if>
+  </xsl:template>
+
+  <!-- Figures out if we should factor in width, height, and depth attributes.  
+  
+       If so, then it 
+       gets these attributes, does some processing to figure out what the attributes indicate, 
+       then passes these indications to CreatePhantPropertiesCore.  
+       
+       If we aren't supposed to factor in width, height, or depth, then we'll just output the show
+       attribute. -->
+  <xsl:template name="CreatePhantProperties">
+    <xsl:param name="ndCur" select="." />
+    <xsl:param name="fShow" select="1"/>
+
+    <xsl:choose>
+      <!-- In the special case that we have an mphantom with one child which is an mpadded, then we should 
+           subsume the mpadded attributes into the mphantom attributes.  The test statement below imples the 
+           'one child which is an mpadded'.  The first part, that the parent of mpadded is an mphantom, is implied
+           by being in this template, which is only called when we've encountered an mphantom.
+           
+           Word outputs its invisible phantoms with smashing as 
+
+              <mml:mphantom>
+                <mml:mpadded . . . >
+                  
+                </mml:mpadded>
+              </mml:mphantom>
+
+            This test is used to allow roundtripping smashed invisible phantoms. -->
+      <xsl:when test="count($ndCur/child::*)=1 and count($ndCur/mml:mpadded)=1">
+        <xsl:variable name="sLowerCaseWidth">
+          <xsl:choose>
+            <xsl:when test="$ndCur/mml:mpadded/@width">
+              <xsl:value-of select="translate($ndCur/mml:mpadded/@width, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/mml:mpadded/@mml:width, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+        <xsl:variable name="sLowerCaseHeight">
+          <xsl:choose>
+            <xsl:when test="$ndCur/mml:mpadded/@height">
+              <xsl:value-of select="translate($ndCur/mml:mpadded/@height, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/mml:mpadded/@mml:height, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+        <xsl:variable name="sLowerCaseDepth">
+          <xsl:choose>
+            <xsl:when test="$ndCur/mml:mpadded/@depth">
+              <xsl:value-of select="translate($ndCur/mml:mpadded/@depth, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/mml:mpadded/@mml:depth, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+
+        <xsl:variable name="fFullWidth">
+          <xsl:call-template name="FFull">
+            <xsl:with-param name="s" select="$sLowerCaseWidth" />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:variable name="fFullHeight">
+          <xsl:call-template name="FFull">
+            <xsl:with-param name="s" select="$sLowerCaseHeight" />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:variable name="fFullDepth">
+          <xsl:call-template name="FFull">
+            <xsl:with-param name="s" select="$sLowerCaseDepth" />
+          </xsl:call-template>
+        </xsl:variable>
+
+        <xsl:call-template name="CreatePhantPropertiesCore">
+          <xsl:with-param name="fShow" select="$fShow"/>
+          <xsl:with-param name="fFullWidth" select="$fFullWidth" />
+          <xsl:with-param name="fFullHeight" select="$fFullHeight" />
+          <xsl:with-param name="fFullDepth" select="$fFullDepth" />
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="CreatePhantPropertiesCore">
+          <xsl:with-param name="fShow" select="$fShow"/>
+        </xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="mml:mpadded">
+    <xsl:choose>
+      <xsl:when test="count(parent::mml:mphantom)=1 and count(preceding-sibling::*)=0 and count(following-sibling::*)=0">
+        <!-- This mpadded is inside an mphantom that has already setup phantom attributes, therefore, just apply templates -->
+        <xsl:apply-templates select="*" />
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="sLowerCaseWidth">
+          <xsl:choose>
+            <xsl:when test="@width">
+              <xsl:value-of select="@width"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@mml:width"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+        <xsl:variable name="sLowerCaseHeight">
+          <xsl:choose>
+            <xsl:when test="@height">
+              <xsl:value-of select="@height"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@mml:height"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+        <xsl:variable name="sLowerCaseDepth">
+          <xsl:choose>
+            <xsl:when test="@depth">
+              <xsl:value-of select="@depth"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@mml:depth"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+
+        <xsl:variable name="fFullWidth">
+          <xsl:call-template name="FFull">
+            <xsl:with-param name="s" select="$sLowerCaseWidth" />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:variable name="fFullHeight">
+          <xsl:call-template name="FFull">
+            <xsl:with-param name="s" select="$sLowerCaseHeight" />
+          </xsl:call-template>
+        </xsl:variable>
+        <xsl:variable name="fFullDepth">
+          <xsl:call-template name="FFull">
+            <xsl:with-param name="s" select="$sLowerCaseDepth" />
+          </xsl:call-template>
+        </xsl:variable>
+
+        <xsl:element name="m:phant">
+          <xsl:call-template name="CreatePhantPropertiesCore">
+            <xsl:with-param name="fShow" select="1"/>
+            <xsl:with-param name="fFullWidth" select="$fFullWidth" />
+            <xsl:with-param name="fFullHeight" select="$fFullHeight" />
+            <xsl:with-param name="fFullDepth" select="$fFullDepth" />
+          </xsl:call-template>
+          <m:e>
+            <xsl:apply-templates select="*" />
+          </m:e>
+        </xsl:element>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="mml:mphantom">
+    <xsl:element name="m:phant">
+      <xsl:call-template name="CreatePhantProperties">
+        <xsl:with-param name="ndCur" select="." />
+        <xsl:with-param name="fShow" select="0" />
+      </xsl:call-template>
+      <m:e>
+        <xsl:apply-templates select="*" />
+      </m:e>
+    </xsl:element>
+  </xsl:template>
+
+  <xsl:template name="isNaryOper">
+    <xsl:param name="sNdCur" />
+    <xsl:value-of select="($sNdCur = '&#x222B;' 
+                            or $sNdCur = '&#x222C;' 
+                            or $sNdCur = '&#x222D;' 
+                            or $sNdCur = '&#x222E;' 
+                            or $sNdCur = '&#x222F;' 
+                            or $sNdCur = '&#x2230;' 
+                            or $sNdCur = '&#x2232;' 
+                            or $sNdCur = '&#x2233;' 
+                            or $sNdCur = '&#x2231;' 
+                            or $sNdCur = '&#x2229;' 
+                            or $sNdCur = '&#x222A;' 
+                            or $sNdCur = '&#x220F;' 
+                            or $sNdCur = '&#x2210;' 
+                            or $sNdCur = '&#x2211;' 
+                            or $sNdCur = '&#x22C0;' 
+                            or $sNdCur = '&#x22C1;' 
+                            or $sNdCur = '&#x22C2;' 
+                            or $sNdCur = '&#x22C3;')" />
+  </xsl:template>
+
+
+  <xsl:template name="isNary">
+    <!-- ndCur is the element around the nAry operator -->
+    <xsl:param name="ndCur" />
+    <xsl:variable name="sNdCur">
+      <xsl:value-of select="normalize-space($ndCur)" />
+    </xsl:variable>
+
+    <xsl:variable name="fNaryOper">
+      <xsl:call-template name="isNaryOper">
+        <xsl:with-param name="sNdCur" select="$sNdCur" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <!-- Narys shouldn't be MathML accents.  -->
+    <xsl:variable name="fUnder">
+      <xsl:choose>
+        <xsl:when test="$ndCur/parent::*[self::mml:munder]">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="sLowerCaseAccent">
+      <xsl:choose>
+        <xsl:when test="$fUnder=1">
+          <xsl:choose>
+            <xsl:when test="$ndCur/parent::*[self::mml:munder]/@accentunder">
+              <xsl:value-of select="translate($ndCur/parent::*[self::mml:munder]/@accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/parent::*[self::mml:munder]/@mml:accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:choose>
+            <xsl:when test="$ndCur/parent::*/@accent">
+              <xsl:value-of select="translate($ndCur/parent::*/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="translate($ndCur/parent::*/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="fAccent">
+      <xsl:choose>
+        <xsl:when test="$sLowerCaseAccent='true'">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:choose>
+      <!-- This ndCur is in fact part of an nAry if
+      
+           1)  The last descendant of ndCur (which could be ndCur itself) is an operator.
+           2)  Along that chain of descendants we only encounter mml:mo, mml:mstyle, and mml:mrow elements.
+           3)  the operator in mml:mo is a valid nAry operator
+           4)  The nAry is not accented.
+           -->
+      <xsl:when test="$fNaryOper = 'true'
+                      and $fAccent=0
+                      and $ndCur/descendant-or-self::*[last()]/self::mml:mo
+                      and not($ndCur/descendant-or-self::*[not(self::mml:mo or 
+			                                                     self::mml:mstyle or 
+			                                                     self::mml:mrow)])">
+        <xsl:value-of select="true()" />
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="false()" />
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="CreateNaryProp">
+    <xsl:param name="chr" />
+    <xsl:param name="sMathmlType" />
+    <xsl:param name="sGrow">
+      <xsl:choose>
+        <xsl:when test="child::*[1]/@stretchy">
+          <xsl:value-of select="translate(child::*[1]/@stretchy, $StrUCAlphabet, $StrLCAlphabet)"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="translate(child::*[1]/@mml:stretchy, $StrUCAlphabet, $StrLCAlphabet)"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:param>
+    <m:naryPr>
+      <m:chr>
+        <xsl:attribute name="m:val">
+          <xsl:value-of select="$chr" />
+        </xsl:attribute>
+      </m:chr>
+      <m:limLoc>
+        <xsl:attribute name="m:val">
+          <xsl:choose>
+            <xsl:when test="$sMathmlType='munder' or 
+									$sMathmlType='mover' or 
+									$sMathmlType='munderover'">
+              <xsl:text>undOvr</xsl:text>
+            </xsl:when>
+            <xsl:when test="$sMathmlType='msub' or
+					                $sMathmlType='msup' or
+					                $sMathmlType='msubsup'">
+              <xsl:text>subSup</xsl:text>
+            </xsl:when>
+          </xsl:choose>
+        </xsl:attribute>
+      </m:limLoc>
+      <m:grow>
+        <xsl:attribute name="m:val">
+          <xsl:choose>
+            <xsl:when test="$sGrow='true'">1</xsl:when>
+            <xsl:when test="$sGrow='false'">0</xsl:when>
+            <xsl:when test="$chr='&#x222B;' 
+                            or $chr='&#x222E;' 
+                            or $chr='&#x222F;' 
+                            or $chr='&#x2232;' 
+                            or $chr='&#x2233;'
+                            or $chr='&#x2229;'
+                            or $chr='&#x222A;' 
+                            or $chr='&#x220F;' 
+                            or $chr='&#x2211;' 
+                            or $chr='&#x22C0;'
+                            or $chr='&#x22C1;' 
+                            or $chr='&#x22C2;'
+                            or $chr='&#x22C3;'">1</xsl:when>
+            <xsl:otherwise>0</xsl:otherwise>
+          </xsl:choose>
+        </xsl:attribute>
+      </m:grow>
+      <m:subHide>
+        <xsl:attribute name="m:val">
+          <xsl:choose>
+            <xsl:when test="$sMathmlType='mover' or
+						                $sMathmlType='msup'">
+              <xsl:text>on</xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:text>off</xsl:text>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:attribute>
+      </m:subHide>
+      <m:supHide>
+        <xsl:attribute name="m:val">
+          <xsl:choose>
+            <xsl:when test="$sMathmlType='munder' or
+						                $sMathmlType='msub'">
+              <xsl:text>on</xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:text>off</xsl:text>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:attribute>
+      </m:supHide>
+    </m:naryPr>
+  </xsl:template>
+</xsl:stylesheet>

+ 2068 - 0
cqb-comm-utils/src/main/resources/OMML2MML.XSL

@@ -0,0 +1,2068 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mml="http://www.w3.org/1998/Math/MathML"
+	xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
+  <xsl:output method="xml" encoding="UTF-16" />
+
+  <!-- %% Global Definitions -->
+
+  <!-- Every single unicode character that is recognized by OMML as an operator -->
+  <xsl:variable name="sOperators"
+		select="concat(
+          '&#x00A8;&#x0021;&#x0022;&#x0023;&#x0026;&#x0028;&#x0029;&#x002B;&#x002C;&#x002D;&#x002E;&#x002F;&#x003A;',
+          '&#x003B;&#x003C;&#x003D;&#x003E;&#x003F;&#x0040;&#x005B;&#x005C;&#x005D;&#x005E;&#x005F;&#x0060;&#x007B;',
+          '&#x007C;&#x007D;&#x007E;&#x00A1;&#x00A6;&#x00AC;&#x00AF;&#x00B0;&#x00B1;&#x00B2;&#x00B3;&#x00B4;&#x00B7;&#x00B9;&#x00BF;',
+          '&#x00D7;&#x007E;&#x00F7;&#x02C7;&#x02D8;&#x02D9;&#x02DC;&#x02DD;&#x0300;&#x0301;&#x0302;&#x0303;&#x0304;&#x0305;&#x0306;&#x0307;&#x0308;&#x0309;',
+          '&#x030A;&#x030B;&#x030C;&#x030D;&#x030E;&#x030F;&#x0310;&#x0311;&#x0312;&#x0313;&#x0314;&#x0315;',
+          '&#x0316;&#x0317;&#x0318;&#x0319;&#x031A;&#x031B;&#x031C;&#x031D;&#x031E;&#x031F;&#x0320;&#x0321;',
+          '&#x0322;&#x0323;&#x0324;&#x0325;&#x0326;&#x0327;&#x0328;&#x0329;&#x032A;&#x032B;&#x032C;&#x032D;',
+          '&#x032E;&#x032F;&#x0330;&#x0331;&#x0332;&#x0333;&#x0334;&#x0335;&#x0336;&#x0337;&#x0338;&#x033F;',
+          '&#x2000;&#x2001;&#x2002;&#x2003;&#x2004;&#x2005;&#x2006;&#x2009;&#x200A;&#x2010;&#x2012;&#x2013;',
+          '&#x2014;&#x2016;&#x2020;&#x2021;&#x2022;&#x2024;&#x2025;&#x2026;&#x2032;&#x2033;&#x2034;&#x203C;',
+          '&#x2040;&#x2044;&#x204E;&#x204F;&#x2050;&#x2057;&#x2061;&#x2062;&#x2063;&#x2070;&#x2074;&#x2075;',
+          '&#x2076;&#x2077;&#x2078;&#x2079;&#x207A;&#x207B;&#x207C;&#x207D;&#x207E;&#x2080;&#x2081;&#x2082;',
+          '&#x2083;&#x2084;&#x2085;&#x2086;&#x2087;&#x2088;&#x2089;&#x208A;&#x208B;&#x208C;&#x208D;&#x208E;',
+          '&#x20D0;&#x20D1;&#x20D2;&#x20D3;&#x20D4;&#x20D5;&#x20D6;&#x20D7;&#x20D8;&#x20D9;&#x20DA;&#x20DB;',
+          '&#x20DC;&#x20DD;&#x20DE;&#x20DF;&#x20E0;&#x20E1;&#x20E4;&#x20E5;&#x20E6;&#x20E7;&#x20E8;&#x20E9;',
+          '&#x20EA;&#x2140;&#x2146;&#x2190;&#x2191;&#x2192;&#x2193;&#x2194;&#x2195;&#x2196;&#x2197;&#x2198;&#x2199;',
+          '&#x219A;&#x219B;&#x219C;&#x219D;&#x219E;&#x219F;&#x21A0;&#x21A1;&#x21A2;&#x21A3;&#x21A4;&#x21A5;',
+          '&#x21A6;&#x21A7;&#x21A8;&#x21A9;&#x21AA;&#x21AB;&#x21AC;&#x21AD;&#x21AE;&#x21AF;&#x21B0;&#x21B1;',
+          '&#x21B2;&#x21B3;&#x21B6;&#x21B7;&#x21BA;&#x21BB;&#x21BC;&#x21BD;&#x21BE;&#x21BF;&#x21C0;&#x21C1;',
+          '&#x21C2;&#x21C3;&#x21C4;&#x21C5;&#x21C6;&#x21C7;&#x21C8;&#x21C9;&#x21CA;&#x21CB;&#x21CC;&#x21CD;',
+          '&#x21CE;&#x21CF;&#x21D0;&#x21D1;&#x21D2;&#x21D3;&#x21D4;&#x21D5;&#x21D6;&#x21D7;&#x21D8;&#x21D9;',
+          '&#x21DA;&#x21DB;&#x21DC;&#x21DD;&#x21DE;&#x21DF;&#x21E0;&#x21E1;&#x21E2;&#x21E3;&#x21E4;&#x21E5;',
+          '&#x21E6;&#x21E7;&#x21E8;&#x21E9;&#x21F3;&#x21F4;&#x21F5;&#x21F6;&#x21F7;&#x21F8;&#x21F9;&#x21FA;',
+          '&#x21FB;&#x21FC;&#x21FD;&#x21FE;&#x21FF;&#x2200;&#x2201;&#x2202;&#x2203;&#x2204;&#x2206;&#x2207;',
+          '&#x2208;&#x2209;&#x220A;&#x220B;&#x220C;&#x220D;&#x220F;&#x2210;&#x2211;&#x2212;&#x2213;&#x2214;',
+          '&#x2215;&#x2216;&#x2217;&#x2218;&#x2219;&#x221A;&#x221B;&#x221C;&#x221D;&#x2223;&#x2224;&#x2225;',
+          '&#x2226;&#x2227;&#x2228;&#x2229;&#x222A;&#x222B;&#x222C;&#x222D;&#x222E;&#x222F;&#x2230;&#x2231;',
+          '&#x2232;&#x2233;&#x2234;&#x2235;&#x2236;&#x2237;&#x2238;&#x2239;&#x223A;&#x223B;&#x223C;&#x223D;',
+          '&#x223E;&#x2240;&#x2241;&#x2242;&#x2243;&#x2244;&#x2245;&#x2246;&#x2247;&#x2248;&#x2249;&#x224A;',
+          '&#x224B;&#x224C;&#x224D;&#x224E;&#x224F;&#x2250;&#x2251;&#x2252;&#x2253;&#x2254;&#x2255;&#x2256;',
+          '&#x2257;&#x2258;&#x2259;&#x225A;&#x225B;&#x225C;&#x225D;&#x225E;&#x225F;&#x2260;&#x2261;&#x2262;',
+          '&#x2263;&#x2264;&#x2265;&#x2266;&#x2267;&#x2268;&#x2269;&#x226A;&#x226B;&#x226C;&#x226D;&#x226E;',
+          '&#x226F;&#x2270;&#x2271;&#x2272;&#x2273;&#x2274;&#x2275;&#x2276;&#x2277;&#x2278;&#x2279;&#x227A;',
+          '&#x227B;&#x227C;&#x227D;&#x227E;&#x227F;&#x2280;&#x2281;&#x2282;&#x2283;&#x2284;&#x2285;&#x2286;',
+          '&#x2287;&#x2288;&#x2289;&#x228A;&#x228B;&#x228C;&#x228D;&#x228E;&#x228F;&#x2290;&#x2291;&#x2292;',
+          '&#x2293;&#x2294;&#x2295;&#x2296;&#x2297;&#x2298;&#x2299;&#x229A;&#x229B;&#x229C;&#x229D;&#x229E;',
+          '&#x229F;&#x22A0;&#x22A1;&#x22A2;&#x22A3;&#x22A5;&#x22A6;&#x22A7;&#x22A8;&#x22A9;&#x22AA;&#x22AB;',
+          '&#x22AC;&#x22AD;&#x22AE;&#x22AF;&#x22B0;&#x22B1;&#x22B2;&#x22B3;&#x22B4;&#x22B5;&#x22B6;&#x22B7;',
+          '&#x22B8;&#x22B9;&#x22BA;&#x22BB;&#x22BC;&#x22BD;&#x22C0;&#x22C1;&#x22C2;&#x22C3;&#x22C4;&#x22C5;',
+          '&#x22C6;&#x22C7;&#x22C8;&#x22C9;&#x22CA;&#x22CB;&#x22CC;&#x22CD;&#x22CE;&#x22CF;&#x22D0;&#x22D1;',
+          '&#x22D2;&#x22D3;&#x22D4;&#x22D5;&#x22D6;&#x22D7;&#x22D8;&#x22D9;&#x22DA;&#x22DB;&#x22DC;&#x22DD;',
+          '&#x22DE;&#x22DF;&#x22E0;&#x22E1;&#x22E2;&#x22E3;&#x22E4;&#x22E5;&#x22E6;&#x22E7;&#x22E8;&#x22E9;',
+          '&#x22EA;&#x22EB;&#x22EC;&#x22ED;&#x22EE;&#x22EF;&#x22F0;&#x22F1;&#x22F2;&#x22F3;&#x22F4;&#x22F5;',
+          '&#x22F6;&#x22F7;&#x22F8;&#x22F9;&#x22FA;&#x22FB;&#x22FC;&#x22FD;&#x22FE;&#x22FF;&#x2305;&#x2306;',
+          '&#x2308;&#x2309;&#x230A;&#x230B;&#x231C;&#x231D;&#x231E;&#x231F;&#x2322;&#x2323;&#x2329;&#x232A;',
+          '&#x233D;&#x233F;&#x23B0;&#x23B1;&#x23DC;&#x23DD;&#x23DE;&#x23DF;&#x23E0;&#x2502;&#x251C;&#x2524;',
+          '&#x252C;&#x2534;&#x2581;&#x2588;&#x2592;&#x25A0;&#x25A1;&#x25AD;&#x25B2;&#x25B3;&#x25B4;&#x25B5;',
+          '&#x25B6;&#x25B7;&#x25B8;&#x25B9;&#x25BC;&#x25BD;&#x25BE;&#x25BF;&#x25C0;&#x25C1;&#x25C2;&#x25C3;',
+          '&#x25C4;&#x25C5;&#x25CA;&#x25CB;&#x25E6;&#x25EB;&#x25EC;&#x25F8;&#x25F9;&#x25FA;&#x25FB;&#x25FC;',
+          '&#x25FD;&#x25FE;&#x25FF;&#x2605;&#x2606;&#x2772;&#x2773;&#x27D1;&#x27D2;&#x27D3;&#x27D4;&#x27D5;',
+          '&#x27D6;&#x27D7;&#x27D8;&#x27D9;&#x27DA;&#x27DB;&#x27DC;&#x27DD;&#x27DE;&#x27DF;&#x27E0;&#x27E1;',
+          '&#x27E2;&#x27E3;&#x27E4;&#x27E5;&#x27E6;&#x27E7;&#x27E8;&#x27E9;&#x27EA;&#x27EB;&#x27F0;&#x27F1;',
+          '&#x27F2;&#x27F3;&#x27F4;&#x27F5;&#x27F6;&#x27F7;&#x27F8;&#x27F9;&#x27FA;&#x27FB;&#x27FC;&#x27FD;',
+          '&#x27FE;&#x27FF;&#x2900;&#x2901;&#x2902;&#x2903;&#x2904;&#x2905;&#x2906;&#x2907;&#x2908;&#x2909;',
+          '&#x290A;&#x290B;&#x290C;&#x290D;&#x290E;&#x290F;&#x2910;&#x2911;&#x2912;&#x2913;&#x2914;&#x2915;',
+          '&#x2916;&#x2917;&#x2918;&#x2919;&#x291A;&#x291B;&#x291C;&#x291D;&#x291E;&#x291F;&#x2920;&#x2921;',
+          '&#x2922;&#x2923;&#x2924;&#x2925;&#x2926;&#x2927;&#x2928;&#x2929;&#x292A;&#x292B;&#x292C;&#x292D;',
+          '&#x292E;&#x292F;&#x2930;&#x2931;&#x2932;&#x2933;&#x2934;&#x2935;&#x2936;&#x2937;&#x2938;&#x2939;',
+          '&#x293A;&#x293B;&#x293C;&#x293D;&#x293E;&#x293F;&#x2940;&#x2941;&#x2942;&#x2943;&#x2944;&#x2945;',
+          '&#x2946;&#x2947;&#x2948;&#x2949;&#x294A;&#x294B;&#x294C;&#x294D;&#x294E;&#x294F;&#x2950;&#x2951;',
+          '&#x2952;&#x2953;&#x2954;&#x2955;&#x2956;&#x2957;&#x2958;&#x2959;&#x295A;&#x295B;&#x295C;&#x295D;',
+          '&#x295E;&#x295F;&#x2960;&#x2961;&#x2962;&#x2963;&#x2964;&#x2965;&#x2966;&#x2967;&#x2968;&#x2969;',
+          '&#x296A;&#x296B;&#x296C;&#x296D;&#x296E;&#x296F;&#x2970;&#x2971;&#x2972;&#x2973;&#x2974;&#x2975;',
+          '&#x2976;&#x2977;&#x2978;&#x2979;&#x297A;&#x297B;&#x297C;&#x297D;&#x297E;&#x297F;&#x2980;&#x2982;',
+          '&#x2983;&#x2984;&#x2985;&#x2986;&#x2987;&#x2988;&#x2989;&#x298A;&#x298B;&#x298C;&#x298D;&#x298E;',
+          '&#x298F;&#x2990;&#x2991;&#x2992;&#x2993;&#x2994;&#x2995;&#x2996;&#x2997;&#x2998;&#x2999;&#x299A;',
+          '&#x29B6;&#x29B7;&#x29B8;&#x29B9;&#x29C0;&#x29C1;&#x29C4;&#x29C5;&#x29C6;&#x29C7;&#x29C8;&#x29CE;',
+          '&#x29CF;&#x29D0;&#x29D1;&#x29D2;&#x29D3;&#x29D4;&#x29D5;&#x29D6;&#x29D7;&#x29D8;&#x29D9;&#x29DA;',
+          '&#x29DB;&#x29DF;&#x29E1;&#x29E2;&#x29E3;&#x29E4;&#x29E5;&#x29E6;&#x29EB;&#x29F4;&#x29F5;&#x29F6;',
+          '&#x29F7;&#x29F8;&#x29F9;&#x29FA;&#x29FB;&#x29FC;&#x29FD;&#x29FE;&#x29FF;&#x2A00;&#x2A01;&#x2A02;',
+          '&#x2A03;&#x2A04;&#x2A05;&#x2A06;&#x2A07;&#x2A08;&#x2A09;&#x2A0A;&#x2A0B;&#x2A0C;&#x2A0D;&#x2A0E;',
+          '&#x2A0F;&#x2A10;&#x2A11;&#x2A12;&#x2A13;&#x2A14;&#x2A15;&#x2A16;&#x2A17;&#x2A18;&#x2A19;&#x2A1A;',
+          '&#x2A1B;&#x2A1C;&#x2A1D;&#x2A1E;&#x2A1F;&#x2A20;&#x2A21;&#x2A22;&#x2A23;&#x2A24;&#x2A25;&#x2A26;',
+          '&#x2A27;&#x2A28;&#x2A29;&#x2A2A;&#x2A2B;&#x2A2C;&#x2A2D;&#x2A2E;&#x2A2F;&#x2A30;&#x2A31;&#x2A32;',
+          '&#x2A33;&#x2A34;&#x2A35;&#x2A36;&#x2A37;&#x2A38;&#x2A39;&#x2A3A;&#x2A3B;&#x2A3C;&#x2A3D;&#x2A3E;',
+          '&#x2A3F;&#x2A40;&#x2A41;&#x2A42;&#x2A43;&#x2A44;&#x2A45;&#x2A46;&#x2A47;&#x2A48;&#x2A49;&#x2A4A;',
+          '&#x2A4B;&#x2A4C;&#x2A4D;&#x2A4E;&#x2A4F;&#x2A50;&#x2A51;&#x2A52;&#x2A53;&#x2A54;&#x2A55;&#x2A56;',
+          '&#x2A57;&#x2A58;&#x2A59;&#x2A5A;&#x2A5B;&#x2A5C;&#x2A5D;&#x2A5E;&#x2A5F;&#x2A60;&#x2A61;&#x2A62;',
+          '&#x2A63;&#x2A64;&#x2A65;&#x2A66;&#x2A67;&#x2A68;&#x2A69;&#x2A6A;&#x2A6B;&#x2A6C;&#x2A6D;&#x2A6E;',
+          '&#x2A6F;&#x2A70;&#x2A71;&#x2A72;&#x2A73;&#x2A74;&#x2A75;&#x2A76;&#x2A77;&#x2A78;&#x2A79;&#x2A7A;',
+          '&#x2A7B;&#x2A7C;&#x2A7D;&#x2A7E;&#x2A7F;&#x2A80;&#x2A81;&#x2A82;&#x2A83;&#x2A84;&#x2A85;&#x2A86;',
+          '&#x2A87;&#x2A88;&#x2A89;&#x2A8A;&#x2A8B;&#x2A8C;&#x2A8D;&#x2A8E;&#x2A8F;&#x2A90;&#x2A91;&#x2A92;',
+          '&#x2A93;&#x2A94;&#x2A95;&#x2A96;&#x2A97;&#x2A98;&#x2A99;&#x2A9A;&#x2A9B;&#x2A9C;&#x2A9D;&#x2A9E;',
+          '&#x2A9F;&#x2AA0;&#x2AA1;&#x2AA2;&#x2AA3;&#x2AA4;&#x2AA5;&#x2AA6;&#x2AA7;&#x2AA8;&#x2AA9;&#x2AAA;',
+          '&#x2AAB;&#x2AAC;&#x2AAD;&#x2AAE;&#x2AAF;&#x2AB0;&#x2AB1;&#x2AB2;&#x2AB3;&#x2AB4;&#x2AB5;&#x2AB6;',
+          '&#x2AB7;&#x2AB8;&#x2AB9;&#x2ABA;&#x2ABB;&#x2ABC;&#x2ABD;&#x2ABE;&#x2ABF;&#x2AC0;&#x2AC1;&#x2AC2;',
+          '&#x2AC3;&#x2AC4;&#x2AC5;&#x2AC6;&#x2AC7;&#x2AC8;&#x2AC9;&#x2ACA;&#x2ACB;&#x2ACC;&#x2ACD;&#x2ACE;',
+          '&#x2ACF;&#x2AD0;&#x2AD1;&#x2AD2;&#x2AD3;&#x2AD4;&#x2AD5;&#x2AD6;&#x2AD7;&#x2AD8;&#x2AD9;&#x2ADA;',
+          '&#x2ADB;&#x2ADC;&#x2ADD;&#x2ADE;&#x2ADF;&#x2AE0;&#x2AE2;&#x2AE3;&#x2AE4;&#x2AE5;&#x2AE6;&#x2AE7;',
+          '&#x2AE8;&#x2AE9;&#x2AEA;&#x2AEB;&#x2AEC;&#x2AED;&#x2AEE;&#x2AEF;&#x2AF0;&#x2AF2;&#x2AF3;&#x2AF4;',
+          '&#x2AF5;&#x2AF6;&#x2AF7;&#x2AF8;&#x2AF9;&#x2AFA;&#x2AFB;&#x2AFC;&#x2AFD;&#x2AFE;&#x2AFF;&#x2B04;',
+          '&#x2B06;&#x2B07;&#x2B0C;&#x2B0D;&#x3014;&#x3015;&#x3016;&#x3017;&#x3018;&#x3019;&#xFF01;&#xFF06;',
+          '&#xFF08;&#xFF09;&#xFF0B;&#xFF0C;&#xFF0D;&#xFF0E;&#xFF0F;&#xFF1A;&#xFF1B;&#xFF1C;&#xFF1D;&#xFF1E;',
+          '&#xFF1F;&#xFF20;&#xFF3B;&#xFF3C;&#xFF3D;&#xFF3E;&#xFF3F;&#xFF5B;&#xFF5C;&#xFF5D;')" />
+
+  <!-- A string of '-'s repeated exactly as many times as the operators above -->
+  <xsl:variable name="sMinuses">
+    <xsl:call-template name="SRepeatChar">
+      <xsl:with-param name="cchRequired" select="string-length($sOperators)" />
+      <xsl:with-param name="ch" select="'-'" />
+    </xsl:call-template>
+  </xsl:variable>
+
+  <!-- Every single unicode character that is recognized by OMML as a number -->
+  <xsl:variable name="sNumbers" select="'0123456789'" />
+
+  <!-- A string of '0's repeated exactly as many times as the list of numbers above -->
+  <xsl:variable name="sZeros">
+    <xsl:call-template name="SRepeatChar">
+      <xsl:with-param name="cchRequired" select="string-length($sNumbers)" />
+      <xsl:with-param name="ch" select="'0'" />
+    </xsl:call-template>
+  </xsl:variable>
+
+  <!-- %%Template: SReplace
+
+		Replace all occurences of sOrig in sInput with sReplacement
+		and return the resulting string. -->
+  <xsl:template name="SReplace">
+    <xsl:param name="sInput" />
+    <xsl:param name="sOrig" />
+    <xsl:param name="sReplacement" />
+
+    <xsl:choose>
+      <xsl:when test="not(contains($sInput, $sOrig))">
+        <xsl:value-of select="$sInput" />
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="sBefore" select="substring-before($sInput, $sOrig)" />
+        <xsl:variable name="sAfter" select="substring-after($sInput, $sOrig)" />
+        <xsl:variable name="sAfterProcessed">
+          <xsl:call-template name="SReplace">
+            <xsl:with-param name="sInput" select="$sAfter" />
+            <xsl:with-param name="sOrig" select="$sOrig" />
+            <xsl:with-param name="sReplacement" select="$sReplacement" />
+          </xsl:call-template>
+        </xsl:variable>
+
+        <xsl:value-of select="concat($sBefore, concat($sReplacement, $sAfterProcessed))" />
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Templates -->
+  <xsl:template match="/">
+    <mml:math>
+      <xsl:apply-templates select="*" />
+    </mml:math>
+  </xsl:template>
+
+  <xsl:template match="m:borderBox">
+
+    <!-- Get Lowercase versions of properties -->
+    <xsl:variable name="sLowerCaseHideTop" select="translate(m:borderBoxPr[last()]/m:hideTop[last()]/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseHideBot" select="translate(m:borderBoxPr[last()]/m:hideBot[last()]/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseHideLeft" select="translate(m:borderBoxPr[last()]/m:hideLeft[last()]/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseHideRight" select="translate(m:borderBoxPr[last()]/m:hideRight[last()]/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseStrikeH" select="translate(m:borderBoxPr[last()]/m:strikeH[last()]/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseStrikeV" select="translate(m:borderBoxPr[last()]/m:strikeV[last()]/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseStrikeBLTR" select="translate(m:borderBoxPr[last()]/m:strikeBLTR[last()]/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseStrikeTLBR" select="translate(m:borderBoxPr[last()]/m:strikeTLBR[last()]/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="fHideTop">
+      <xsl:call-template name="ForceTrueStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseHideTop" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="fHideBot">
+      <xsl:call-template name="ForceTrueStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseHideBot" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="fHideLeft">
+      <xsl:call-template name="ForceTrueStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseHideLeft" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="fHideRight">
+      <xsl:call-template name="ForceTrueStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseHideRight" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="fStrikeH">
+      <xsl:call-template name="ForceTrueStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseStrikeH" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="fStrikeV">
+      <xsl:call-template name="ForceTrueStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseStrikeV" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="fStrikeBLTR">
+      <xsl:call-template name="ForceTrueStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseStrikeBLTR" />
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="fStrikeTLBR">
+      <xsl:call-template name="ForceTrueStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseStrikeTLBR" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:choose>
+      <xsl:when test="$fHideTop=1 
+                      and $fHideBot=1 
+                      and $fHideLeft=1 
+                      and $fHideRight=1 
+                      and $fStrikeH=0 
+                      and $fStrikeV=0 
+                      and $fStrikeBLTR=0 
+                      and $fStrikeTLBR=0">
+        <mml:mrow>
+          <xsl:apply-templates select="m:e[1]" />
+        </mml:mrow>
+      </xsl:when>
+      <xsl:otherwise>
+        <mml:menclose>
+          <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+            <xsl:with-param name="fHideTop" select="$fHideTop" />
+            <xsl:with-param name="fHideBot" select="$fHideBot" />
+            <xsl:with-param name="fHideLeft" select="$fHideLeft" />
+            <xsl:with-param name="fHideRight" select="$fHideRight" />
+            <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+            <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+            <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+            <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+          </xsl:call-template>
+          <xsl:apply-templates select="m:e[1]" />
+        </mml:menclose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="*">
+    <xsl:apply-templates select="*" />
+  </xsl:template>
+
+  <!--
+      { Non-combining, Upper-combining, Lower-combining }
+      {U+02D8, U+0306, U+032E}, // BREVE
+      {U+00B8, U+0312, U+0327}, // CEDILLA
+      {U+0060, U+0300, U+0316}, // GRAVE ACCENT
+      {U+002D, U+0305, U+0332}, // HYPHEN-MINUS/OVERLINE
+      {U+2212, U+0305, U+0332}, // MINUS SIGN/OVERLINE
+      {U+002E, U+0305, U+0323}, // FULL STOP/DOT ABOVE
+      {U+02D9, U+0307, U+0323}, // DOT ABOVE
+      {U+02DD, U+030B, U+02DD}, // DOUBLE ACUTE ACCENT
+      {U+00B4, U+0301, U+0317}, // ACUTE ACCENT
+      {U+007E, U+0303, U+0330}, // TILDE
+      {U+02DC, U+0303, U+0330}, // SMALL TILDE
+      {U+00A8, U+0308, U+0324}, // DIAERESIS
+      {U+02C7, U+030C, U+032C}, // CARON
+      {U+005E, U+0302, U+032D}, // CIRCUMFLEX ACCENT
+      {U+00AF, U+0305, ::::::}, // MACRON
+      {U+005F, ::::::, U+0332}, // LOW LINE
+      {U+2192, U+20D7, U+20EF}, // RIGHTWARDS ARROW
+      {U+27F6, U+20D7, U+20EF}, // LONG RIGHTWARDS ARROW
+      {U+2190, U+20D6, U+20EE}, // LEFT ARROW
+  -->
+  <xsl:template name="ToNonCombining">
+    <xsl:param name="ch" />
+    <xsl:choose>
+      <!-- BREVE -->
+      <xsl:when test="$ch='&#x0306;' or $ch='&#x032e;'">&#x02D8;</xsl:when>
+      <!-- CEDILLA -->
+      <xsl:when test="$ch='&#x0312;' or $ch='&#x0327;'">&#x00B8;</xsl:when>
+      <!-- GRAVE ACCENT -->
+      <xsl:when test="$ch='&#x0300;' or $ch='&#x0316;'">&#x0060;</xsl:when>
+      <!-- HYPHEN-MINUS/OVERLINE -->
+      <xsl:when test="$ch='&#x0305;' or $ch='&#x0332;'">&#x002D;</xsl:when>
+      <!-- MINUS SIGN/OVERLINE -->
+      <xsl:when test="$ch='&#x0305;' or $ch='&#x0332;'">&#x2212;</xsl:when>
+      <!-- FULL STOP/DOT ABOVE -->
+      <xsl:when test="$ch='&#x0305;' or $ch='&#x0323;'">&#x002E;</xsl:when>
+      <!-- DOT ABOVE -->
+      <xsl:when test="$ch='&#x0307;' or $ch='&#x0323;'">&#x02D9;</xsl:when>
+      <!-- DOUBLE ACUTE ACCENT -->
+      <xsl:when test="$ch='&#x030B;' or $ch='&#x02DD;'">&#x02DD;</xsl:when>
+      <!-- ACUTE ACCENT -->
+      <xsl:when test="$ch='&#x0301;' or $ch='&#x0317;'">&#x00B4;</xsl:when>
+      <!-- TILDE -->
+      <xsl:when test="$ch='&#x0303;' or $ch='&#x0330;'">&#x007E;</xsl:when>
+      <!-- SMALL TILDE -->
+      <xsl:when test="$ch='&#x0303;' or $ch='&#x0330;'">&#x02DC;</xsl:when>
+      <!-- DIAERESIS -->
+      <xsl:when test="$ch='&#x0308;' or $ch='&#x0324;'">&#x00A8;</xsl:when>
+      <!-- CARON -->
+      <xsl:when test="$ch='&#x030C;' or $ch='&#x032C;'">&#x02C7;</xsl:when>
+      <!-- CIRCUMFLEX ACCENT -->
+      <xsl:when test="$ch='&#x0302;' or $ch='&#x032D;'">&#x005E;</xsl:when>
+      <!-- MACRON -->
+      <xsl:when test="$ch='&#x0305;'                   ">&#x00AF;</xsl:when>
+      <!-- LOW LINE -->
+      <xsl:when test="                   $ch='&#x0332;'">&#x005F;</xsl:when>
+      <!-- RIGHTWARDS ARROW -->
+      <xsl:when test="$ch='&#x20D7;' or $ch='&#x20EF;'">&#x2192;</xsl:when>
+      <!-- LONG RIGHTWARDS ARROW -->
+      <xsl:when test="$ch='&#x20D7;' or $ch='&#x20EF;'">&#x27F6;</xsl:when>
+      <!-- LEFT ARROW -->
+      <xsl:when test="$ch='&#x20D6;' or $ch='&#x20EE;'">&#x2190;</xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$ch"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="m:acc">
+    <mml:mover>
+      <xsl:attribute name="accent">true</xsl:attribute>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e[1]" />
+      </mml:mrow>
+      <xsl:variable name="chAcc">
+        <xsl:choose>
+          <xsl:when test="not(m:accPr[last()]/m:chr)">
+            <xsl:value-of select="'&#x0302;'" />
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="substring(m:accPr/m:chr/@m:val,1,1)" />
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+      <xsl:variable name="chNonComb">
+        <xsl:call-template name="ToNonCombining">
+          <xsl:with-param name="ch" select="$chAcc" />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="string-length($chAcc)=0">
+          <mml:mo/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="ParseMt">
+            <xsl:with-param name="sToParse" select="$chNonComb" />
+            <xsl:with-param name="scr" select="m:e[1]/*/m:rPr[last()]/m:scr/@m:val" />
+            <xsl:with-param name="sty" select="m:e[1]/*/m:rPr[last()]/m:sty/@m:val" />
+            <xsl:with-param name="nor">
+              <xsl:choose>
+                <xsl:when test="count(m:e[1]/*/m:rPr[last()]/m:nor) = 0">0</xsl:when>
+                <xsl:otherwise>
+                  <xsl:call-template name="ForceFalseStrVal">
+                    <xsl:with-param name="str" select="translate(m:e[1]/*/m:rPr[last()]/m:nor/@m:val, 
+                                                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                                 'abcdefghijklmnopqrstuvwxyz')" />
+                  </xsl:call-template>
+                </xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </mml:mover>
+  </xsl:template>
+
+  <xsl:template name="OutputScript">
+    <xsl:param name="ndCur" select="." />
+    <xsl:choose>
+      <!-- Only output contents of $ndCur if $ndCur exists
+           and $ndCur has children -->
+      <xsl:when test="count($ndCur/*) &gt; 0">
+        <mml:mrow>
+          <xsl:apply-templates select="$ndCur" />
+        </mml:mrow>
+      </xsl:when>
+      <xsl:otherwise>
+        <mml:none />
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="m:sPre">
+    <mml:mmultiscripts>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e[1]" />
+      </mml:mrow>
+      <mml:mprescripts />
+      <xsl:call-template name="OutputScript">
+        <xsl:with-param name="ndCur" select="m:sub[1]"/>
+      </xsl:call-template>
+      <xsl:call-template name="OutputScript">
+        <xsl:with-param name="ndCur" select="m:sup[1]" />
+      </xsl:call-template>
+    </mml:mmultiscripts>
+  </xsl:template>
+
+  <xsl:template match="m:m">
+    <mml:mtable>
+      <xsl:call-template name="CreateMathMLMatrixAttr">
+        <xsl:with-param name="mcJc" select="m:mPr[last()]/m:mcs/m:mc/m:mcPr[last()]/m:mcJc/@m:val" />
+      </xsl:call-template>
+      <xsl:for-each select="m:mr">
+        <mml:mtr>
+          <xsl:for-each select="m:e">
+            <mml:mtd>
+              <xsl:apply-templates select="." />
+            </mml:mtd>
+          </xsl:for-each>
+        </mml:mtr>
+      </xsl:for-each>
+    </mml:mtable>
+  </xsl:template>
+
+  <xsl:template name="CreateMathMLMatrixAttr">
+    <xsl:param name="mcJc" />
+    <xsl:variable name="sLowerCaseMcjc" select="translate($mcJc, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                             'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:choose>
+      <xsl:when test="$sLowerCaseMcjc='left'">
+        <xsl:attribute name="columnalign">left</xsl:attribute>
+      </xsl:when>
+      <xsl:when test="$sLowerCaseMcjc='right'">
+        <xsl:attribute name="columnalign">right</xsl:attribute>
+      </xsl:when>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="m:phant">
+    <xsl:variable name="sLowerCaseZeroWidVal" select="translate(m:phantPr[last()]/m:zeroWid[last()]/@m:val, 
+		                                                       'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                       'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseZeroAscVal" select="translate(m:phantPr[last()]/m:zeroAsc[last()]/@m:val, 
+		                                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                     'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseZeroDescVal" select="translate(m:phantPr[last()]/m:zeroDesc[last()]/@m:val, 
+		                                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                     'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="sLowerCaseShowVal" select="translate(m:phantPr[last()]/m:show[last()]/@m:val, 
+		                                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                     'abcdefghijklmnopqrstuvwxyz')" />
+
+
+    <!-- The following properties default to 'yes' unless the last value equals 'no' or there isn't any node for 
+         the property -->
+
+    <xsl:variable name="fZeroWid">
+      <xsl:choose>
+        <xsl:when test="count(m:phantPr[last()]/m:zeroWid[last()]) = 0">0</xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="ForceFalseStrVal">
+            <xsl:with-param name="str" select="$sLowerCaseZeroWidVal" />
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="fZeroAsc">
+      <xsl:choose>
+        <xsl:when test="count(m:phantPr[last()]/m:zeroAsc[last()]) = 0">0</xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="ForceFalseStrVal">
+            <xsl:with-param name="str" select="$sLowerCaseZeroAscVal" />
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="fZeroDesc">
+      <xsl:choose>
+        <xsl:when test="count(m:phantPr[last()]/m:zeroDesc[last()]) = 0">0</xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="ForceFalseStrVal">
+            <xsl:with-param name="str" select="$sLowerCaseZeroDescVal" />
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <!-- The show property defaults to 'on' unless there exists a show property and its value is 'off' -->
+
+    <xsl:variable name="fShow">
+      <xsl:call-template name="ForceFalseStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseShowVal" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:choose>
+      <!-- Show the phantom contents, therefore, just use mpadded. -->
+      <xsl:when test="$fShow = 1">
+        <xsl:element name="mml:mpadded">
+          <xsl:call-template name="CreateMpaddedAttributes">
+            <xsl:with-param name="fZeroWid" select="$fZeroWid" />
+            <xsl:with-param name="fZeroAsc" select="$fZeroAsc" />
+            <xsl:with-param name="fZeroDesc" select="$fZeroDesc" />
+          </xsl:call-template>
+          <mml:mrow>
+            <xsl:apply-templates select="m:e" />
+          </mml:mrow>
+        </xsl:element>
+      </xsl:when>
+      <!-- Don't show phantom contents, but don't smash anything, therefore, just 
+           use mphantom -->
+      <xsl:when test="$fZeroWid=0 and $fZeroAsc=0 and $fZeroDesc=0">
+        <xsl:element name="mml:mphantom">
+          <mml:mrow>
+            <xsl:apply-templates select="m:e" />
+          </mml:mrow>
+        </xsl:element>
+      </xsl:when>
+      <!-- Combination -->
+      <xsl:otherwise>
+        <xsl:element name="mml:mphantom">
+          <xsl:element name="mml:mpadded">
+            <xsl:call-template name="CreateMpaddedAttributes">
+              <xsl:with-param name="fZeroWid" select="$fZeroWid" />
+              <xsl:with-param name="fZeroAsc" select="$fZeroAsc" />
+              <xsl:with-param name="fZeroDesc" select="$fZeroDesc" />
+            </xsl:call-template>
+            <mml:mrow>
+              <xsl:apply-templates select="m:e" />
+            </mml:mrow>
+          </xsl:element>
+        </xsl:element>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="CreateMpaddedAttributes">
+    <xsl:param name="fZeroWid" />
+    <xsl:param name="fZeroAsc" />
+    <xsl:param name="fZeroDesc" />
+
+    <xsl:if test="$fZeroWid=1">
+      <xsl:attribute name="width">0in</xsl:attribute>
+    </xsl:if>
+    <xsl:if test="$fZeroAsc=1">
+      <xsl:attribute name="height">0in</xsl:attribute>
+    </xsl:if>
+    <xsl:if test="$fZeroDesc=1">
+      <xsl:attribute name="depth">0in</xsl:attribute>
+    </xsl:if>
+  </xsl:template>
+
+
+
+  <xsl:template match="m:rad">
+    <xsl:variable name="fDegHide">
+      <xsl:choose>
+        <xsl:when test="count(m:radPr[last()]/m:degHide)=0">0</xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="ForceFalseStrVal">
+            <xsl:with-param name="str" select="translate(m:radPr[last()]/m:degHide/@m:val, 
+		                                                          'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                          'abcdefghijklmnopqrstuvwxyz')" />
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fDegHide=1">
+        <mml:msqrt>
+          <xsl:apply-templates select="m:e[1]" />
+        </mml:msqrt>
+      </xsl:when>
+      <xsl:otherwise>
+        <mml:mroot>
+          <mml:mrow>
+            <xsl:apply-templates select="m:e[1]" />
+          </mml:mrow>
+          <mml:mrow>
+            <xsl:apply-templates select="m:deg[1]" />
+          </mml:mrow>
+        </mml:mroot>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="OutputNaryMo">
+    <xsl:param name="ndCur" select="." />
+    <xsl:param name="fGrow" select="0" />
+    <mml:mo>
+      <xsl:choose>
+        <xsl:when test="$fGrow=1">
+          <xsl:attribute name="stretchy">true</xsl:attribute>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:attribute name="stretchy">false</xsl:attribute>
+        </xsl:otherwise>
+      </xsl:choose>
+      <xsl:choose>
+        <xsl:when test="not($ndCur/m:naryPr[last()]/m:chr/@m:val) or
+			                            $ndCur/m:naryPr[last()]/m:chr/@m:val=''">
+          <xsl:text>&#x222b;</xsl:text>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="$ndCur/m:naryPr[last()]/m:chr/@m:val" />
+        </xsl:otherwise>
+      </xsl:choose>
+    </mml:mo>
+  </xsl:template>
+
+  <!-- %%Template match m:nary 
+		Process an n-ary. 
+		
+		Decides, based on which arguments are supplied, between
+		using an mo, msup, msub, or msubsup for the n-ary operator		
+	-->
+  <xsl:template match="m:nary">
+    <xsl:variable name="sLowerCaseSubHide">
+      <xsl:choose>
+        <xsl:when test="count(m:naryPr[last()]/m:subHide) = 0">
+          <xsl:text>off</xsl:text>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="translate(m:naryPr[last()]/m:subHide/@m:val, 
+	                                  'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+	                                  'abcdefghijklmnopqrstuvwxyz')" />
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="sLowerCaseSupHide">
+      <xsl:choose>
+        <xsl:when test="count(m:naryPr[last()]/m:supHide) = 0">
+          <xsl:text>off</xsl:text>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="translate(m:naryPr[last()]/m:supHide/@m:val, 
+	                                  'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+	                                  'abcdefghijklmnopqrstuvwxyz')" />
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="sLowerCaseLimLoc">
+      <xsl:value-of select="translate(m:naryPr[last()]/m:limLoc/@m:val, 
+	                                  'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+	                                  'abcdefghijklmnopqrstuvwxyz')" />
+    </xsl:variable>
+
+    <xsl:variable name="sLowerGrow">
+      <xsl:choose>
+        <xsl:when test="count(m:naryPr[last()]/m:grow)=0">off</xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="translate(m:naryPr[last()]/m:grow/@m:val, 
+	                                  'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+	                                  'abcdefghijklmnopqrstuvwxyz')" />
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="fLimLocSubSup">
+      <xsl:choose>
+        <xsl:when test="count(m:naryPr[last()]/m:limLoc)=0 or $sLowerCaseLimLoc='subsup'">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:variable name="fGrow">
+      <xsl:call-template name="ForceFalseStrVal">
+        <xsl:with-param name="str" select="$sLowerGrow" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:variable name="fSupHide">
+      <xsl:call-template name="ForceFalseStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseSupHide" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:variable name="fSubHide">
+      <xsl:call-template name="ForceFalseStrVal">
+        <xsl:with-param name="str" select="$sLowerCaseSubHide" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <mml:mrow>
+      <xsl:choose>
+        <xsl:when test="$fSupHide=1 and $fSubHide=1">
+          <xsl:call-template name="OutputNaryMo">
+            <xsl:with-param name="ndCur" select="." />
+            <xsl:with-param name="fGrow" select="$fGrow" />
+          </xsl:call-template>
+        </xsl:when>
+        <xsl:when test="$fSubHide=1">
+          <xsl:choose>
+            <xsl:when test="$fLimLocSubSup=1">
+              <mml:msup>
+                <xsl:call-template name="OutputNaryMo">
+                  <xsl:with-param name="ndCur" select="." />
+                  <xsl:with-param name="fGrow" select="$fGrow" />
+                </xsl:call-template>
+                <mml:mrow>
+                  <xsl:apply-templates select="m:sup[1]" />
+                </mml:mrow>
+              </mml:msup>
+            </xsl:when>
+            <xsl:otherwise>
+              <mml:mover>
+                <xsl:call-template name="OutputNaryMo">
+                  <xsl:with-param name="ndCur" select="." />
+                  <xsl:with-param name="fGrow" select="$fGrow" />
+                </xsl:call-template>
+                <mml:mrow>
+                  <xsl:apply-templates select="m:sup[1]" />
+                </mml:mrow>
+              </mml:mover>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+        <xsl:when test="$fSupHide=1">
+          <xsl:choose>
+            <xsl:when test="$fLimLocSubSup=1">
+              <mml:msub>
+                <xsl:call-template name="OutputNaryMo">
+                  <xsl:with-param name="ndCur" select="." />
+                  <xsl:with-param name="fGrow" select="$fGrow" />
+                </xsl:call-template>
+                <mml:mrow>
+                  <xsl:apply-templates select="m:sub[1]" />
+                </mml:mrow>
+              </mml:msub>
+            </xsl:when>
+            <xsl:otherwise>
+              <mml:munder>
+                <xsl:call-template name="OutputNaryMo">
+                  <xsl:with-param name="ndCur" select="." />
+                  <xsl:with-param name="fGrow" select="$fGrow" />
+                </xsl:call-template>
+                <mml:mrow>
+                  <xsl:apply-templates select="m:sub[1]" />
+                </mml:mrow>
+              </mml:munder>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:choose>
+            <xsl:when test="$fLimLocSubSup=1">
+              <mml:msubsup>
+                <xsl:call-template name="OutputNaryMo">
+                  <xsl:with-param name="ndCur" select="." />
+                  <xsl:with-param name="fGrow" select="$fGrow" />
+                </xsl:call-template>
+                <mml:mrow>
+                  <xsl:apply-templates select="m:sub[1]" />
+                </mml:mrow>
+                <mml:mrow>
+                  <xsl:apply-templates select="m:sup[1]" />
+                </mml:mrow>
+              </mml:msubsup>
+            </xsl:when>
+            <xsl:otherwise>
+              <mml:munderover>
+                <xsl:call-template name="OutputNaryMo">
+                  <xsl:with-param name="ndCur" select="." />
+                  <xsl:with-param name="fGrow" select="$fGrow" />
+                </xsl:call-template>
+                <mml:mrow>
+                  <xsl:apply-templates select="m:sub[1]" />
+                </mml:mrow>
+                <mml:mrow>
+                  <xsl:apply-templates select="m:sup[1]" />
+                </mml:mrow>
+              </mml:munderover>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:otherwise>
+      </xsl:choose>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e[1]" />
+      </mml:mrow>
+    </mml:mrow>
+  </xsl:template>
+
+  <xsl:template match="m:limLow">
+    <mml:munder>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e[1]" />
+      </mml:mrow>
+      <mml:mrow>
+        <xsl:apply-templates select="m:lim[1]" />
+      </mml:mrow>
+    </mml:munder>
+  </xsl:template>
+
+  <xsl:template match="m:limUpp">
+    <mml:mover>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e[1]" />
+      </mml:mrow>
+      <mml:mrow>
+        <xsl:apply-templates select="m:lim[1]" />
+      </mml:mrow>
+    </mml:mover>
+  </xsl:template>
+
+  <xsl:template match="m:sSub">
+    <mml:msub>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e[1]" />
+      </mml:mrow>
+      <mml:mrow>
+        <xsl:apply-templates select="m:sub[1]" />
+      </mml:mrow>
+    </mml:msub>
+  </xsl:template>
+
+  <xsl:template match="m:sSup">
+    <mml:msup>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e[1]" />
+      </mml:mrow>
+      <mml:mrow>
+        <xsl:apply-templates select="m:sup[1]" />
+      </mml:mrow>
+    </mml:msup>
+  </xsl:template>
+
+  <xsl:template match="m:sSubSup">
+    <mml:msubsup>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e[1]" />
+      </mml:mrow>
+      <mml:mrow>
+        <xsl:apply-templates select="m:sub[1]" />
+      </mml:mrow>
+      <mml:mrow>
+        <xsl:apply-templates select="m:sup[1]" />
+      </mml:mrow>
+    </mml:msubsup>
+  </xsl:template>
+
+  <xsl:template match="m:groupChr">
+    <xsl:variable name="ndLastGroupChrPr" select="m:groupChrPr[last()]" />
+    <xsl:variable name="sLowerCasePos" select="translate($ndLastGroupChrPr/m:pos/@m:val, 
+		                                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                     'abcdefghijklmnopqrstuvwxyz')" />
+
+    <xsl:variable name="sLowerCaseVertJc" select="translate($ndLastGroupChrPr/m:vertJc/@m:val, 
+		                                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                     'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:variable name="ndLastChr" select="$ndLastGroupChrPr/m:chr" />
+
+    <xsl:variable name="chr">
+      <xsl:choose>
+        <xsl:when test="$ndLastChr and (not($ndLastChr/@m:val) or string-length($ndLastChr/@m:val) = 0)"></xsl:when>
+        <xsl:when test="string-length($ndLastChr/@m:val) &gt;= 1">
+          <xsl:value-of select="substring($ndLastChr/@m:val,1,1)" />
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:text>&#x023DF;</xsl:text>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$sLowerCasePos = 'top'">
+        <xsl:choose>
+          <xsl:when test="$sLowerCaseVertJc = 'bot'">
+            <mml:mover accent="false">
+              <mml:mrow>
+                <xsl:apply-templates select="m:e[1]" />
+              </mml:mrow>
+              <mml:mo>
+                <xsl:value-of select="$chr" />
+              </mml:mo>
+            </mml:mover>
+          </xsl:when>
+          <xsl:otherwise>
+            <mml:munder accentunder="false">
+              <mml:mo>
+                <xsl:value-of select="$chr" />
+              </mml:mo>
+              <mml:mrow>
+                <xsl:apply-templates select="m:e[1]" />
+              </mml:mrow>
+            </mml:munder>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:choose>
+          <xsl:when test="$sLowerCaseVertJc = 'bot'">
+            <mml:mover accent="false">
+              <mml:mo>
+                <xsl:value-of select="$chr" />
+              </mml:mo>
+              <mml:mrow>
+                <xsl:apply-templates select="m:e[1]" />
+              </mml:mrow>
+            </mml:mover>
+          </xsl:when>
+          <xsl:otherwise>
+            <mml:munder accentunder="false">
+              <mml:mrow>
+                <xsl:apply-templates select="m:e[1]" />
+              </mml:mrow>
+              <mml:mo>
+                <xsl:value-of select="$chr" />
+              </mml:mo>
+            </mml:munder>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="fName">
+    <xsl:for-each select="m:fName/*">
+      <xsl:apply-templates select="." />
+    </xsl:for-each>
+  </xsl:template>
+
+  <xsl:template match="m:func">
+    <mml:mrow>
+      <mml:mrow>
+        <xsl:call-template name="fName" />
+      </mml:mrow>
+      <mml:mo>&#x02061;</mml:mo>
+      <mml:mrow>
+        <xsl:apply-templates select="m:e" />
+      </mml:mrow>
+    </mml:mrow>
+  </xsl:template>
+
+  <!-- %%Template: match m:f 
+		
+		m:f maps directly to mfrac. 
+	-->
+  <xsl:template match="m:f">
+    <xsl:variable name="sLowerCaseType" select="translate(m:fPr[last()]/m:type/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
+    <xsl:choose>
+      <xsl:when test="$sLowerCaseType='lin'">
+        <mml:mrow>
+          <mml:mrow>
+            <xsl:apply-templates select="m:num[1]" />
+          </mml:mrow>
+          <mml:mo>/</mml:mo>
+          <mml:mrow>
+            <xsl:apply-templates select="m:den[1]" />
+          </mml:mrow>
+        </mml:mrow>
+      </xsl:when>
+      <xsl:otherwise>
+        <mml:mfrac>
+          <xsl:call-template name="CreateMathMLFracProp">
+            <xsl:with-param name="type" select="$sLowerCaseType" />
+          </xsl:call-template>
+          <mml:mrow>
+            <xsl:apply-templates select="m:num[1]" />
+          </mml:mrow>
+          <mml:mrow>
+            <xsl:apply-templates select="m:den[1]" />
+          </mml:mrow>
+        </mml:mfrac>
+      </xsl:otherwise>
+    </xsl:choose>
+
+  </xsl:template>
+
+
+  <!-- %%Template: CreateMathMLFracProp 
+		
+			Make fraction properties based on supplied parameters.
+			OMML differentiates between a linear fraction and a skewed
+			one. For MathML, we write both as bevelled.
+	-->
+  <xsl:template name="CreateMathMLFracProp">
+    <xsl:param name="type" />
+    <xsl:variable name="sLowerCaseType" select="translate($type, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')" />
+
+    <xsl:if test="$sLowerCaseType='skw' or $sLowerCaseType='lin'">
+      <xsl:attribute name="bevelled">true</xsl:attribute>
+    </xsl:if>
+    <xsl:if test="$sLowerCaseType='nobar'">
+      <xsl:attribute name="linethickness">0pt</xsl:attribute>
+    </xsl:if>
+    <xsl:choose>
+      <xsl:when test="sLowerCaseNumJc='right'">
+        <xsl:attribute name="numalign">right</xsl:attribute>
+      </xsl:when>
+      <xsl:when test="sLowerCaseNumJc='left'">
+        <xsl:attribute name="numalign">left</xsl:attribute>
+      </xsl:when>
+    </xsl:choose>
+    <xsl:choose>
+      <xsl:when test="sLowerCaseDenJc='right'">
+        <xsl:attribute name="numalign">right</xsl:attribute>
+      </xsl:when>
+      <xsl:when test="sLowerCaseDenJc='left'">
+        <xsl:attribute name="numalign">left</xsl:attribute>
+      </xsl:when>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: match m:e | m:den | m:num | m:lim | m:sup | m:sub 
+		
+		These element delinate parts of an expression (like the numerator).  -->
+  <xsl:template match="m:e | m:den | m:num | m:lim | m:sup | m:sub">
+    <xsl:choose>
+
+      <!-- If there is no scriptLevel specified, just call through -->
+      <xsl:when test="not(m:argPr[last()]/m:scrLvl/@m:val)">
+        <xsl:apply-templates select="*" />
+      </xsl:when>
+
+      <!-- Otherwise, create an mstyle and set the script level -->
+      <xsl:otherwise>
+        <mml:mstyle>
+          <xsl:attribute name="scriptlevel">
+            <xsl:value-of select="m:argPr[last()]/m:scrLvl/@m:val" />
+          </xsl:attribute>
+          <xsl:apply-templates select="*" />
+        </mml:mstyle>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="m:bar">
+    <xsl:variable name="sLowerCasePos" select="translate(m:barPr/m:pos/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                                       'abcdefghijklmnopqrstuvwxyz')" />
+
+    <xsl:variable name="fTop">
+
+      <xsl:choose>
+        <xsl:when test="$sLowerCasePos='top'">1</xsl:when>
+        <xsl:otherwise>0</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$fTop=1">
+        <mml:mover accent="false">
+          <mml:mrow>
+            <xsl:apply-templates select="m:e[1]" />
+          </mml:mrow>
+          <mml:mo>
+            <xsl:text>&#x00AF;</xsl:text>
+          </mml:mo>
+        </mml:mover>
+      </xsl:when>
+      <xsl:otherwise>
+        <mml:munder underaccent="false">
+          <mml:mrow>
+            <xsl:apply-templates select="m:e[1]" />
+          </mml:mrow>
+          <mml:mo>
+            <xsl:text>&#x005F;</xsl:text>
+          </mml:mo>
+        </mml:munder>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template match m:d
+
+		Process a delimiter. 
+	-->
+  <xsl:template match="m:d">
+    <mml:mfenced>
+      <!-- open: default is '(' for both OMML and MathML -->
+      <xsl:if test="m:dPr[1]/m:begChr/@m:val and not(m:dPr[1]/m:begChr/@m:val ='(')">
+        <xsl:attribute name="open">
+          <xsl:value-of select="m:dPr[1]/m:begChr/@m:val" />
+        </xsl:attribute>
+      </xsl:if>
+
+      <!-- close: default is ')' for both OMML and MathML -->
+      <xsl:if test="m:dPr[1]/m:endChr/@m:val and not(m:dPr[1]/m:endChr/@m:val =')')">
+        <xsl:attribute name="close">
+          <xsl:value-of select="m:dPr[1]/m:endChr/@m:val" />
+        </xsl:attribute>
+      </xsl:if>
+
+      <!-- separator: the default is ',' for MathML, and '|' for OMML -->
+      <xsl:choose>
+        <!-- Matches MathML default. Write nothing -->
+        <xsl:when test="m:dPr[1]/m:sepChr/@m:val = ','" />
+
+        <!-- OMML default: | -->
+        <xsl:when test="not(m:dPr[1]/m:sepChr/@m:val)">
+          <xsl:attribute name="separators">
+            <xsl:value-of select="'|'" />
+          </xsl:attribute>
+        </xsl:when>
+
+        <xsl:otherwise>
+          <xsl:attribute name="separators">
+            <xsl:value-of select="m:dPr[1]/m:sepChr/@m:val" />
+          </xsl:attribute>
+        </xsl:otherwise>
+      </xsl:choose>
+
+      <!-- now write all the children. Put each one into an mrow
+			just in case it produces multiple runs, etc -->
+      <xsl:for-each select="m:e">
+        <mml:mrow>
+          <xsl:apply-templates select="." />
+        </mml:mrow>
+      </xsl:for-each>
+    </mml:mfenced>
+  </xsl:template>
+
+  <xsl:template match="m:r">
+    <xsl:variable name="fNor">
+      <xsl:choose>
+        <xsl:when test="count(child::m:rPr[last()]/m:nor) = 0">0</xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="ForceFalseStrVal">
+            <xsl:with-param name="str" select="translate(child::m:rPr[last()]/m:nor/@m:val, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                                       'abcdefghijklmnopqrstuvwxyz')" />
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+
+    <xsl:choose>
+      <xsl:when test="$fNor=1">
+        <mml:mtext>
+          <xsl:variable name="sOutput" select="translate(.//m:t, ' ', '&#xa0;')" />
+          <xsl:value-of select="$sOutput" />
+        </mml:mtext>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:for-each select=".//m:t">
+          <xsl:call-template name="ParseMt">
+            <xsl:with-param name="sToParse" select="text()" />
+            <xsl:with-param name="scr" select="../m:rPr[last()]/m:scr/@m:val" />
+            <xsl:with-param name="sty" select="../m:rPr[last()]/m:sty/@m:val" />
+            <xsl:with-param name="nor">0</xsl:with-param>
+          </xsl:call-template>
+        </xsl:for-each>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <xsl:template name="CreateTokenAttributes">
+    <xsl:param name="scr" />
+    <xsl:param name="sty" />
+    <xsl:param name="nor" />
+    <xsl:param name="nCharToPrint" />
+    <xsl:param name="sTokenType" />
+
+    <xsl:choose>
+      <xsl:when test="$nor=1">
+        <xsl:attribute name="mathvariant">normal</xsl:attribute>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="mathvariant">
+          <xsl:choose>
+            <!-- numbers don't care -->
+            <xsl:when test="$sTokenType='mn'" />
+
+            <xsl:when test="$scr='monospace'">monospace</xsl:when>
+            <xsl:when test="$scr='sans-serif' and $sty='i'">sans-serif-italic</xsl:when>
+            <xsl:when test="$scr='sans-serif' and $sty='b'">bold-sans-serif</xsl:when>
+            <xsl:when test="$scr='sans-serif' and $sty='bi'">sans-serif-bold-italic</xsl:when>
+            <xsl:when test="$scr='sans-serif'">sans-serif</xsl:when>
+            <xsl:when test="$scr='fraktur' and ($sty='b' or $sty='bi')">bold-fraktur</xsl:when>
+            <xsl:when test="$scr='fraktur'">fraktur</xsl:when>
+            <xsl:when test="$scr='double-struck'">double-struck</xsl:when>
+            <xsl:when test="$scr='script' and ($sty='b' or $sty='bi')">bold-script</xsl:when>
+            <xsl:when test="$scr='script'">script</xsl:when>
+            <xsl:when test="($scr='roman' or not($scr) or $scr='') and $sty='b'">bold</xsl:when>
+            <xsl:when test="($scr='roman' or not($scr) or $scr='') and $sty='i'">italic</xsl:when>
+            <xsl:when test="($scr='roman' or not($scr) or $scr='') and $sty='p'">normal</xsl:when>
+            <xsl:when test="($scr='roman' or not($scr) or $scr='') and $sty='bi'">bold-italic</xsl:when>
+            <xsl:otherwise />
+          </xsl:choose>
+        </xsl:variable>
+        <xsl:variable name="fontweight">
+          <xsl:choose>
+            <xsl:when test="$sty='b' or $sty='bi'">bold</xsl:when>
+            <xsl:otherwise>normal</xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+        <xsl:variable name="fontstyle">
+          <xsl:choose>
+            <xsl:when test="$sty='p' or $sty='b'">normal</xsl:when>
+            <xsl:otherwise>italic</xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+
+        <!-- Writing of attributes begins here -->
+        <xsl:choose>
+          <!-- Don't write mathvariant for operators unless they want to be normal -->
+          <xsl:when test="$sTokenType='mo' and $mathvariant!='normal'" />
+
+          <!-- A single character within an mi is already italics, don't write -->
+          <xsl:when test="$sTokenType='mi' and $nCharToPrint=1 and ($mathvariant='' or $mathvariant='italic')" />
+
+          <xsl:when test="$sTokenType='mi' and $nCharToPrint &gt; 1 and ($mathvariant='' or $mathvariant='italic')">
+            <xsl:attribute name="mathvariant">
+              <xsl:value-of select="'italic'" />
+            </xsl:attribute>
+          </xsl:when>
+          <xsl:when test="$mathvariant!='italic' and $mathvariant!=''">
+            <xsl:attribute name="mathvariant">
+              <xsl:value-of select="$mathvariant" />
+            </xsl:attribute>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:if test="not($sTokenType='mi' and $nCharToPrint=1) and $fontstyle='italic'">
+              <xsl:attribute name="fontstyle">italic</xsl:attribute>
+            </xsl:if>
+            <xsl:if test="$fontweight='bold'">
+              <xsl:attribute name="fontweight">bold</xsl:attribute>
+            </xsl:if>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="m:eqArr">
+    <mml:mtable>
+      <xsl:for-each select="m:e">
+        <mml:mtr>
+          <mml:mtd>
+            <xsl:choose>
+              <xsl:when test="m:argPr[last()]/m:scrLvl/@m:val!='0' or 
+					            not(m:argPr[last()]/m:scrLvl/@m:val)  or 
+					            m:argPr[last()]/m:scrLvl/@m:val=''">
+                <mml:mrow>
+                  <mml:maligngroup />
+                  <xsl:call-template name="CreateEqArrRow">
+                    <xsl:with-param name="align" select="1" />
+                    <xsl:with-param name="ndCur" select="*[1]" />
+                  </xsl:call-template>
+                </mml:mrow>
+              </xsl:when>
+              <xsl:otherwise>
+                <mml:mstyle>
+                  <xsl:attribute name="scriptlevel">
+                    <xsl:value-of select="m:argPr[last()]/m:scrLvl/@m:val" />
+                  </xsl:attribute>
+                  <mml:maligngroup />
+                  <xsl:call-template name="CreateEqArrRow">
+                    <xsl:with-param name="align" select="1" />
+                    <xsl:with-param name="ndCur" select="*[1]" />
+                  </xsl:call-template>
+                </mml:mstyle>
+              </xsl:otherwise>
+            </xsl:choose>
+          </mml:mtd>
+        </mml:mtr>
+      </xsl:for-each>
+    </mml:mtable>
+  </xsl:template>
+
+  <xsl:template name="CreateEqArrRow">
+    <xsl:param name="align" />
+    <xsl:param name="ndCur" />
+    <xsl:variable name="sAllMt">
+      <xsl:for-each select="$ndCur/m:t">
+        <xsl:value-of select="." />
+      </xsl:for-each>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$ndCur/self::m:r">
+        <xsl:call-template name="ParseEqArrMr">
+          <xsl:with-param name="sToParse" select="$sAllMt" />
+          <xsl:with-param name="scr" select="../m:rPr[last()]/m:scr/@m:val" />
+          <xsl:with-param name="sty" select="../m:rPr[last()]/m:sty/@m:val" />
+          <xsl:with-param name="nor">
+            <xsl:choose>
+              <xsl:when test="count($ndCur/m:rPr[last()]/m:nor) = 0">0</xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="ForceFalseStrVal">
+                  <xsl:with-param name="str" select="translate($ndCur/m:rPr[last()]/m:nor/@m:val, 
+                                                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
+		                                                                 'abcdefghijklmnopqrstuvwxyz')" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:with-param>
+          <xsl:with-param name="align" select="$align" />
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:apply-templates select="$ndCur" />
+      </xsl:otherwise>
+    </xsl:choose>
+    <xsl:if test="count($ndCur/following-sibling::*) &gt; 0">
+      <xsl:variable name="cAmp">
+        <xsl:call-template name="CountAmp">
+          <xsl:with-param name="sAllMt" select="$sAllMt" />
+          <xsl:with-param name="cAmp" select="0" />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:call-template name="CreateEqArrRow">
+        <xsl:with-param name="align" select="($align+($cAmp mod 2)) mod 2" />
+        <xsl:with-param name="ndCur" select="$ndCur/following-sibling::*[1]" />
+      </xsl:call-template>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template name="CountAmp">
+    <xsl:param name="sAllMt" />
+    <xsl:param name="cAmp" />
+    <xsl:choose>
+      <xsl:when test="string-length(substring-after($sAllMt, '&amp;')) &gt; 0 or 
+			                substring($sAllMt, string-length($sAllMt))='&#x0026;'">
+        <xsl:call-template name="CountAmp">
+          <xsl:with-param name="sAllMt" select="substring-after($sAllMt, '&#x0026;')" />
+          <xsl:with-param name="cAmp" select="$cAmp+1" />
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$cAmp" />
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template: ParseEqArrMr
+			
+			Similar to ParseMt, but this one has to do more for an equation array. 
+      In equation arrays &amp; is a special character which denotes alignment.
+      
+      The &amp; in an equation works by alternating between meaning insert alignment spacing
+      and insert alignment mark.  For each equation in the equation array
+      there is an implied align space at the beginning of the equation.  Within each equation,
+      the first &amp; means alignmark, the second, align space, the third, alignmark, etc.
+      
+      For this reason when parsing m:r's in equation arrays it is important to keep track of what
+      the next ampersand will mean.
+      
+      $align=0 => Omml's align space, which is similar to MathML's maligngroup.
+      $align=1 => Omml's alignment mark, which is similar to MathML's malignmark.
+	-->
+  <xsl:template name="ParseEqArrMr">
+    <xsl:param name="sToParse" />
+    <xsl:param name="sty" />
+    <xsl:param name="scr" />
+    <xsl:param name="nor" />
+    <xsl:param name="align" />
+
+    <xsl:if test="string-length($sToParse) &gt; 0">
+      <xsl:choose>
+        <xsl:when test="substring($sToParse,1,1) = '&amp;'">
+          <xsl:choose>
+            <xsl:when test="$align='0'">
+              <mml:maligngroup />
+            </xsl:when>
+            <xsl:when test="$align='1'">
+              <mml:malignmark />
+            </xsl:when>
+          </xsl:choose>
+          <xsl:call-template name="ParseEqArrMr">
+            <xsl:with-param name="sToParse" select="substring($sToParse,2)" />
+            <xsl:with-param name="scr" select="$scr" />
+            <xsl:with-param name="sty" select="$sty" />
+            <xsl:with-param name="nor" select="$nor" />
+            <xsl:with-param name="align">
+              <xsl:choose>
+                <xsl:when test="$align='1'">0</xsl:when>
+                <xsl:otherwise>1</xsl:otherwise>
+              </xsl:choose>
+            </xsl:with-param>
+          </xsl:call-template>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:variable name="sRepNumWith0">
+            <xsl:call-template name="SReplaceNumWithZero">
+              <xsl:with-param name="sToParse" select="$sToParse" />
+            </xsl:call-template>
+          </xsl:variable>
+          <xsl:variable name="sRepOperWith-">
+            <xsl:call-template name="SReplaceOperWithMinus">
+              <xsl:with-param name="sToParse" select="$sRepNumWith0" />
+            </xsl:call-template>
+          </xsl:variable>
+
+          <xsl:variable name="iFirstOper" select="string-length($sRepOperWith-) - string-length(substring-after($sRepOperWith-, '-'))" />
+          <xsl:variable name="iFirstNum" select="string-length($sRepOperWith-) - string-length(substring-after($sRepOperWith-, '0'))" />
+          <xsl:variable name="iFirstAmp" select="string-length($sRepOperWith-) - string-length(substring-after($sRepOperWith-, '&#x0026;'))" />
+          <xsl:variable name="fNumAtPos1">
+            <xsl:choose>
+              <xsl:when test="substring($sRepOperWith-,1,1)='0'">1</xsl:when>
+              <xsl:otherwise>0</xsl:otherwise>
+            </xsl:choose>
+          </xsl:variable>
+          <xsl:variable name="fOperAtPos1">
+            <xsl:choose>
+              <xsl:when test="substring($sRepOperWith-,1,1)='-'">1</xsl:when>
+              <xsl:otherwise>0</xsl:otherwise>
+            </xsl:choose>
+          </xsl:variable>
+          <xsl:choose>
+
+            <!-- Case I: The string begins with neither a number, nor an operator -->
+            <xsl:when test="$fNumAtPos1='0' and $fOperAtPos1='0'">
+              <xsl:choose>
+                <xsl:when test="$nor = 0">
+                  <mml:mi>
+                    <xsl:call-template name="CreateTokenAttributes">
+                      <xsl:with-param name="scr" select="$scr" />
+                      <xsl:with-param name="sty" select="$sty" />
+                      <xsl:with-param name="nor" select="$nor" />
+                      <xsl:with-param name="nCharToPrint" select="1" />
+                      <xsl:with-param name="sTokenType" select="'mi'" />
+                    </xsl:call-template>
+                    <xsl:variable name="sOutput" select="translate(substring($sToParse, 1, 1), ' ', '&#xa0;')" />
+                    <xsl:value-of select="$sOutput" />
+                  </mml:mi>
+                </xsl:when>
+                <xsl:otherwise>
+                  <mml:mtext>
+                    <xsl:variable name="sOutput" select="translate(substring($sToParse, 1, 1), ' ', '&#xa0;')" />
+                    <xsl:value-of select="$sOutput" />
+                  </mml:mtext>
+                </xsl:otherwise>
+              </xsl:choose>
+              <xsl:call-template name="ParseEqArrMr">
+                <xsl:with-param name="sToParse" select="substring($sToParse, 2)" />
+                <xsl:with-param name="scr" select="$scr" />
+                <xsl:with-param name="sty" select="$sty" />
+                <xsl:with-param name="nor" select="$nor" />
+                <xsl:with-param name="align" select="$align" />
+              </xsl:call-template>
+            </xsl:when>
+
+            <!-- Case II: There is an operator at position 1 -->
+            <xsl:when test="$fOperAtPos1='1'">
+              <xsl:choose>
+                <xsl:when test="$nor = 0">
+                  <mml:mo>
+                    <xsl:call-template name="CreateTokenAttributes">
+                      <xsl:with-param name="scr" />
+                      <xsl:with-param name="sty" />
+                      <xsl:with-param name="nor" select="$nor" />
+                      <xsl:with-param name="sTokenType" select="'mo'" />
+                    </xsl:call-template>
+                    <xsl:value-of select="substring($sToParse,1,1)" />
+                  </mml:mo>
+                </xsl:when>
+                <xsl:otherwise>
+                  <mml:mtext>
+                    <xsl:value-of select="substring($sToParse,1,1)" />
+                  </mml:mtext>                  
+                </xsl:otherwise>
+              </xsl:choose>
+              <xsl:call-template name="ParseEqArrMr">
+                <xsl:with-param name="sToParse" select="substring($sToParse, 2)" />
+                <xsl:with-param name="scr" select="$scr" />
+                <xsl:with-param name="sty" select="$sty" />
+                <xsl:with-param name="nor" select="$nor" />
+                <xsl:with-param name="align" select="$align" />
+              </xsl:call-template>
+            </xsl:when>
+
+            <!-- Case III: There is a number at position 1 -->
+            <xsl:otherwise>
+              <xsl:variable name="sConsecNum">
+                <xsl:call-template name="SNumStart">
+                  <xsl:with-param name="sToParse" select="$sToParse" />
+                  <xsl:with-param name="sPattern" select="$sRepNumWith0" />
+                </xsl:call-template>
+              </xsl:variable>
+              <xsl:choose>
+                <xsl:when test="$nor = 0">
+                  <mml:mn>
+                    <xsl:call-template name="CreateTokenAttributes">
+                      <xsl:with-param name="scr" />
+                      <xsl:with-param name="sty" select="'p'"/>
+                      <xsl:with-param name="nor" select="$nor" />
+                      <xsl:with-param name="sTokenType" select="'mn'" />
+                    </xsl:call-template>
+                    <xsl:value-of select="$sConsecNum" />
+                  </mml:mn>
+                </xsl:when>
+                <xsl:otherwise>
+                  <mml:mtext>
+                    <xsl:value-of select="$sConsecNum" />
+                  </mml:mtext>
+                </xsl:otherwise>
+              </xsl:choose>
+              <xsl:call-template name="ParseEqArrMr">
+                <xsl:with-param name="sToParse" select="substring-after($sToParse, $sConsecNum)" />
+                <xsl:with-param name="scr" select="$scr" />
+                <xsl:with-param name="sty" select="$sty" />
+                <xsl:with-param name="nor" select="$nor" />
+                <xsl:with-param name="align" select="$align" />
+              </xsl:call-template>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:if>
+  </xsl:template>
+
+  <!-- %%Template: ParseMt
+
+			Produce a run of text. Technically, OMML makes no distinction 
+			between numbers, operators, and other characters in a run. For 
+			MathML we need to break these into mi, mn, or mo elements. 
+			
+			See also ParseEqArrMr
+	-->
+  <xsl:template name="ParseMt">
+    <xsl:param name="sToParse" />
+    <xsl:param name="sty" />
+    <xsl:param name="scr" />
+    <xsl:param name="nor" />
+    <xsl:if test="string-length($sToParse) &gt; 0">
+      <xsl:variable name="sRepNumWith0">
+        <xsl:call-template name="SReplaceNumWithZero">
+          <xsl:with-param name="sToParse" select="$sToParse" />
+        </xsl:call-template>
+      </xsl:variable>
+      <xsl:variable name="sRepOperWith-">
+        <xsl:call-template name="SReplaceOperWithMinus">
+          <xsl:with-param name="sToParse" select="$sRepNumWith0" />
+        </xsl:call-template>
+      </xsl:variable>
+
+      <xsl:variable name="iFirstOper" select="string-length($sRepOperWith-) - string-length(substring-after($sRepOperWith-, '-'))" />
+      <xsl:variable name="iFirstNum" select="string-length($sRepOperWith-) - string-length(substring-after($sRepOperWith-, '0'))" />
+      <xsl:variable name="fNumAtPos1">
+        <xsl:choose>
+          <xsl:when test="substring($sRepOperWith-,1,1)='0'">1</xsl:when>
+          <xsl:otherwise>0</xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+      <xsl:variable name="fOperAtPos1">
+        <xsl:choose>
+          <xsl:when test="substring($sRepOperWith-,1,1)='-'">1</xsl:when>
+          <xsl:otherwise>0</xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+
+      <xsl:choose>
+
+        <!-- Case I: The string begins with neither a number, nor an operator -->
+        <xsl:when test="$fOperAtPos1='0' and $fNumAtPos1='0'">
+          <xsl:variable name="nCharToPrint">
+            <xsl:choose>
+              <xsl:when test="ancestor::m:fName">
+                <xsl:choose>
+                  <xsl:when test="($iFirstOper=$iFirstNum) and 
+											($iFirstOper=string-length($sToParse)) and
+							                (substring($sRepOperWith-, string-length($sRepOperWith-))!='0') and 
+							                (substring($sRepOperWith-, string-length($sRepOperWith-))!='-')">
+                    <xsl:value-of select="string-length($sToParse)" />
+                  </xsl:when>
+                  <xsl:when test="$iFirstOper &lt; $iFirstNum">
+                    <xsl:value-of select="$iFirstOper - 1" />
+                  </xsl:when>
+                  <xsl:otherwise>
+                    <xsl:value-of select="$iFirstNum - 1" />
+                  </xsl:otherwise>
+                </xsl:choose>
+              </xsl:when>
+              <xsl:otherwise>1</xsl:otherwise>
+            </xsl:choose>
+          </xsl:variable>
+
+          <mml:mi>
+            <xsl:call-template name="CreateTokenAttributes">
+              <xsl:with-param name="scr" select="$scr" />
+              <xsl:with-param name="sty" select="$sty" />
+              <xsl:with-param name="nor" select="$nor" />
+              <xsl:with-param name="nCharToPrint" select="$nCharToPrint" />
+              <xsl:with-param name="sTokenType" select="'mi'" />
+            </xsl:call-template>
+            <xsl:variable name="sWrite" select="translate(substring($sToParse, 1, $nCharToPrint), ' ', '&#xa0;')" />
+            <xsl:value-of select="$sWrite" />
+          </mml:mi>
+          <xsl:call-template name="ParseMt">
+            <xsl:with-param name="sToParse" select="substring($sToParse, $nCharToPrint+1)" />
+            <xsl:with-param name="scr" select="$scr" />
+            <xsl:with-param name="sty" select="$sty" />
+            <xsl:with-param name="nor" select="$nor" />
+          </xsl:call-template>
+        </xsl:when>
+
+        <!-- Case II: There is an operator at position 1 -->
+        <xsl:when test="$fOperAtPos1='1'">
+          <mml:mo>
+            <xsl:call-template name="CreateTokenAttributes">
+              <xsl:with-param name="scr" />
+              <xsl:with-param name="sty" />
+              <xsl:with-param name="nor" select="$nor" />
+              <xsl:with-param name="sTokenType" select="'mo'" />
+            </xsl:call-template>
+            <xsl:value-of select="substring($sToParse,1,1)" />
+          </mml:mo>
+          <xsl:call-template name="ParseMt">
+            <xsl:with-param name="sToParse" select="substring($sToParse, 2)" />
+            <xsl:with-param name="scr" select="$scr" />
+            <xsl:with-param name="sty" select="$sty" />
+            <xsl:with-param name="nor" select="$nor" />
+          </xsl:call-template>
+        </xsl:when>
+
+        <!-- Case III: There is a number at position 1 -->
+        <xsl:otherwise>
+          <xsl:variable name="sConsecNum">
+            <xsl:call-template name="SNumStart">
+              <xsl:with-param name="sToParse" select="$sToParse" />
+              <xsl:with-param name="sPattern" select="$sRepNumWith0" />
+            </xsl:call-template>
+          </xsl:variable>
+          <mml:mn>
+            <xsl:call-template name="CreateTokenAttributes">
+              <xsl:with-param name="scr" select="$scr" />
+              <xsl:with-param name="sty" select="'p'" />
+              <xsl:with-param name="nor" select="$nor" />
+              <xsl:with-param name="sTokenType" select="'mn'" />
+            </xsl:call-template>
+            <xsl:value-of select="$sConsecNum" />
+          </mml:mn>
+          <xsl:call-template name="ParseMt">
+            <xsl:with-param name="sToParse" select="substring-after($sToParse, $sConsecNum)" />
+            <xsl:with-param name="scr" select="$scr" />
+            <xsl:with-param name="sty" select="$sty" />
+            <xsl:with-param name="nor" select="$nor" />
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:if>
+  </xsl:template>
+
+  <!-- %%Template: SNumStart 
+	
+		Return the longest substring of sToParse starting from the 
+		start of sToParse that is a number. In addition, it takes the
+		pattern string, which is sToParse with all of its numbers 
+		replaced with a 0. sPattern should be the same length 
+		as sToParse		
+	-->
+  <xsl:template name="SNumStart">
+    <xsl:param name="sToParse" select="''" />
+    <!-- if we don't get anything, take the string itself -->
+    <xsl:param name="sPattern" select="'$sToParse'" />
+
+
+    <xsl:choose>
+      <!-- the pattern says this is a number, recurse with the rest -->
+      <xsl:when test="substring($sPattern, 1, 1) = '0'">
+        <xsl:call-template name="SNumStart">
+          <xsl:with-param name="sToParse" select="$sToParse" />
+          <xsl:with-param name="sPattern" select="substring($sPattern, 2)" />
+        </xsl:call-template>
+      </xsl:when>
+
+      <!-- the pattern says we've run out of numbers. Take as many
+				characters from sToParse as we shaved off sPattern -->
+      <xsl:otherwise>
+        <xsl:value-of select="substring($sToParse, 1, string-length($sToParse) - string-length($sPattern))" />
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- %%Template SRepeatCharAcc
+	
+			The core of SRepeatChar with an accumulator. The current
+			string is in param $acc, and we will double and recurse,
+			if we're less than half of the required length or else just 
+			add the right amount of characters to the accumulator and
+			return
+	-->
+  <xsl:template name="SRepeatCharAcc">
+    <xsl:param name="cchRequired" select="1" />
+    <xsl:param name="ch" select="'-'" />
+    <xsl:param name="acc" select="$ch" />
+
+    <xsl:variable name="cchAcc" select="string-length($acc)" />
+    <xsl:choose>
+      <xsl:when test="(2 * $cchAcc) &lt; $cchRequired">
+        <xsl:call-template name="SRepeatCharAcc">
+          <xsl:with-param name="cchRequired" select="$cchRequired" />
+          <xsl:with-param name="ch" select="$ch" />
+          <xsl:with-param name="acc" select="concat($acc, $acc)" />
+        </xsl:call-template>
+      </xsl:when>
+
+      <xsl:otherwise>
+        <xsl:value-of select="concat($acc, substring($acc, 1, $cchRequired - $cchAcc))" />
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- %%Template SRepeatChar
+	
+			Generates a string nchRequired long by repeating the given character ch
+	-->
+  <xsl:template name="SRepeatChar">
+    <xsl:param name="cchRequired" select="1" />
+    <xsl:param name="ch" select="'-'" />
+
+    <xsl:call-template name="SRepeatCharAcc">
+      <xsl:with-param name="cchRequired" select="$cchRequired" />
+      <xsl:with-param name="ch" select="$ch" />
+      <xsl:with-param name="acc" select="$ch" />
+    </xsl:call-template>
+  </xsl:template>
+
+  <!-- %%Template SReplaceOperWithMinus
+	
+		Go through the given string and replace every instance
+		of an operator with a minus '-'. This helps quickly identify
+		the first instance of an operator.  
+	-->
+  <xsl:template name="SReplaceOperWithMinus">
+    <xsl:param name="sToParse" select="''" />
+
+    <xsl:value-of select="translate($sToParse, $sOperators, $sMinuses)" />
+  </xsl:template>
+
+  <!-- %%Template SReplaceNumWithZero
+	
+		Go through the given string and replace every instance
+		of an number with a zero '0'. This helps quickly identify
+		the first occurence of a number. 
+		
+		Considers the '.' and ',' part of a number iff they are sandwiched 
+		between two other numbers. 0.3 will be recognized as a number,
+		x.3 will not be. Since these characters can also be an operator, this 
+		should be called before SReplaceOperWithMinus.
+	-->
+  <xsl:template name="SReplaceNumWithZero">
+    <xsl:param name="sToParse" select="''" />
+
+    <!-- First do a simple replace. Numbers will all be come 0's.
+			After this point, the pattern involving the . or , that 
+			we are looking for will become 0.0 or 0,0 -->
+    <xsl:variable name="sSimpleReplace" select="translate($sToParse, $sNumbers, $sZeros)" />
+
+    <!-- And then, replace 0.0 with just 000. This means that the . will 
+			become part of the number -->
+    <xsl:variable name="sReplacePeriod">
+      <xsl:call-template name="SReplace">
+        <xsl:with-param name="sInput" select="$sSimpleReplace" />
+        <xsl:with-param name="sOrig" select="'0.0'" />
+        <xsl:with-param name="sReplacement" select="'000'" />
+      </xsl:call-template>
+    </xsl:variable>
+
+    <!-- And then, replace 0,0 with just 000. This means that the , will 
+			become part of the number -->
+    <xsl:call-template name="SReplace">
+      <xsl:with-param name="sInput" select="$sReplacePeriod" />
+      <xsl:with-param name="sOrig" select="'0,0'" />
+      <xsl:with-param name="sReplacement" select="'000'" />
+    </xsl:call-template>
+  </xsl:template>
+
+  <!-- Template to translate Word's borderBox properties into the menclose notation attribute
+       The initial call to this SHOULD NOT pass an sAttribute.  Subsequent calls to 
+       CreateMencloseNotationAttrFromBorderBoxAttr by CreateMencloseNotationAttrFromBorderBoxAttr will
+       update the sAttribute as appropriate.
+       
+       CreateMencloseNotationAttrFromBorderBoxAttr looks at each attribute (fHideTop, fHideBot, etc.) one at a time
+       in the order they are listed and passes a modified sAttribute to CreateMencloseNotationAttrFromBorderBoxAttr.
+       Each successive call to CreateMencloseNotationAttrFromBorderBoxAttr knows which attribute to look at because 
+       the previous call should have omitted passing the attribute it just analyzed.  This is why as you read lower 
+       and lower in the template that each call to CreateMencloseNotationAttrFromBorderBoxAttr has fewer and fewer attributes.
+       -->
+  <xsl:template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+    <xsl:param name="fHideTop" />
+    <xsl:param name="fHideBot" />
+    <xsl:param name="fHideLeft" />
+    <xsl:param name="fHideRight" />
+    <xsl:param name="fStrikeH" />
+    <xsl:param name="fStrikeV" />
+    <xsl:param name="fStrikeBLTR" />
+    <xsl:param name="fStrikeTLBR" />
+    <xsl:param name="sAttribute" />
+
+    <xsl:choose>
+      <xsl:when test="string-length($sAttribute) = 0">
+        <xsl:choose>
+          <xsl:when test="string-length($fHideTop) &gt; 0
+                      and string-length($fHideBot) &gt; 0 
+                      and string-length($fHideLeft) &gt; 0
+                      and string-length($fHideRight) &gt; 0">
+
+            <xsl:choose>
+              <xsl:when test="$fHideTop = 0 
+                              and $fHideBot = 0
+                              and $fHideLeft = 0 
+                              and $fHideRight = 0">
+                <!-- We can use 'box' instead of top, bot, left, and right.  Therefore,
+                  replace sAttribute with 'box' and begin analyzing params fStrikeH
+                  and below. -->
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute">
+                    <xsl:text>box</xsl:text>
+                  </xsl:with-param>
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <!-- Can't use 'box', theremore, must analyze all attributes -->
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fHideTop" select="$fHideTop" />
+                  <xsl:with-param name="fHideBot" select="$fHideBot" />
+                  <xsl:with-param name="fHideLeft" select="$fHideLeft" />
+                  <xsl:with-param name="fHideRight" select="$fHideRight" />
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute">
+                    <!-- Assume using all four (left right top bottom).  Subsequent calls
+                         will remove the sides which aren't to be includes. -->
+                    <xsl:text>left right top bottom</xsl:text>
+                  </xsl:with-param>
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:choose>
+          <xsl:when test="string-length($fHideTop) &gt; 0">
+            <xsl:choose>
+              <xsl:when test="$fHideTop=1">
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fHideBot" select="$fHideBot" />
+                  <xsl:with-param name="fHideLeft" select="$fHideLeft" />
+                  <xsl:with-param name="fHideRight" select="$fHideRight" />
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute">
+                    <xsl:call-template name="SReplace">
+                      <xsl:with-param name="sInput" select="$sAttribute" />
+                      <xsl:with-param name="sOrig" select="'top'" />
+                      <xsl:with-param name="sReplacement" select="''" />
+                    </xsl:call-template>
+                  </xsl:with-param>
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fHideBot" select="$fHideBot" />
+                  <xsl:with-param name="fHideLeft" select="$fHideLeft" />
+                  <xsl:with-param name="fHideRight" select="$fHideRight" />
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="$sAttribute" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:when test="string-length($fHideBot) &gt; 0">
+            <xsl:choose>
+              <xsl:when test="$fHideBot=1">
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fHideLeft" select="$fHideLeft" />
+                  <xsl:with-param name="fHideRight" select="$fHideRight" />
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute">
+                    <xsl:call-template name="SReplace">
+                      <xsl:with-param name="sInput" select="$sAttribute" />
+                      <xsl:with-param name="sOrig" select="'bottom'" />
+                      <xsl:with-param name="sReplacement" select="''" />
+                    </xsl:call-template>
+                  </xsl:with-param>
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fHideLeft" select="$fHideLeft" />
+                  <xsl:with-param name="fHideRight" select="$fHideRight" />
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="$sAttribute" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:when test="string-length($fHideLeft) &gt; 0">
+            <xsl:choose>
+              <xsl:when test="$fHideLeft=1">
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fHideRight" select="$fHideRight" />
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute">
+                    <xsl:call-template name="SReplace">
+                      <xsl:with-param name="sInput" select="$sAttribute" />
+                      <xsl:with-param name="sOrig" select="'left'" />
+                      <xsl:with-param name="sReplacement" select="''" />
+                    </xsl:call-template>
+                  </xsl:with-param>
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fHideRight" select="$fHideRight" />
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="$sAttribute" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:when test="string-length($fHideRight) &gt; 0">
+            <xsl:choose>
+              <xsl:when test="$fHideRight=1">
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute">
+                    <xsl:call-template name="SReplace">
+                      <xsl:with-param name="sInput" select="$sAttribute" />
+                      <xsl:with-param name="sOrig" select="'right'" />
+                      <xsl:with-param name="sReplacement" select="''" />
+                    </xsl:call-template>
+                  </xsl:with-param>
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeH" select="$fStrikeH" />
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="$sAttribute" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:when test="string-length($fStrikeH) &gt; 0">
+            <xsl:choose>
+              <xsl:when test="$fStrikeH=1">
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="concat($sAttribute, ' horizontalstrike')" />
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeV" select="$fStrikeV" />
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="$sAttribute" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:when test="string-length($fStrikeV) &gt; 0">
+            <xsl:choose>
+              <xsl:when test="$fStrikeV=1">
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="concat($sAttribute, ' verticalstrike')" />
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeBLTR" select="$fStrikeBLTR" />
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="$sAttribute" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:when test="string-length($fStrikeBLTR) &gt; 0">
+            <xsl:choose>
+              <xsl:when test="$fStrikeBLTR=1">
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="concat($sAttribute, ' updiagonalstrike')" />
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="fStrikeTLBR" select="$fStrikeTLBR" />
+                  <xsl:with-param name="sAttribute" select="$sAttribute" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:when test="string-length($fStrikeTLBR) &gt; 0">
+            <xsl:choose>
+              <xsl:when test="$fStrikeTLBR=1">
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="sAttribute" select="concat($sAttribute, ' downdiagonalstrike')" />
+                </xsl:call-template>
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:call-template name="CreateMencloseNotationAttrFromBorderBoxAttr">
+                  <xsl:with-param name="sAttribute" select="$sAttribute" />
+                </xsl:call-template>
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:attribute name="notation">
+              <xsl:value-of select="normalize-space($sAttribute)" />
+            </xsl:attribute>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Tristate (true, false, neither) from string value -->
+  <xsl:template name="TFromStrVal">
+    <xsl:param name="str" />
+    <xsl:choose>
+      <xsl:when test="$str = 'on' or $str = '1' or $str = 'true'">1</xsl:when>
+      <xsl:when test="$str = 'off' or $str = '0' or $str = 'false'">0</xsl:when>
+      <xsl:otherwise>-1</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Return 0 iff $str is explicitly set to a false value.  
+       Return true otherwise -->
+  <xsl:template name="ForceFalseStrVal">
+    <xsl:param name="str" />
+    <xsl:variable name="tValue">
+      <xsl:call-template name="TFromStrVal">
+        <xsl:with-param name="str" select="$str"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$tValue = '0'">0</xsl:when>
+      <xsl:otherwise>1</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Return 1 iff $str is explicitly set to a true value.  
+       Return false otherwise -->
+  <xsl:template name="ForceTrueStrVal">
+    <xsl:param name="str" />
+    <xsl:variable name="tValue">
+      <xsl:call-template name="TFromStrVal">
+        <xsl:with-param name="str" select="$str"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$tValue = '1'">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+</xsl:stylesheet>

+ 1 - 0
cqb-comm-utils/src/main/resources/common.properties

@@ -0,0 +1 @@
+tmp_root_path=/Users/songyue/

+ 6 - 0
cqb-comm-utils/src/main/resources/log4j.properties

@@ -0,0 +1,6 @@
+log4j.rootCategory=OFF
+#log4j.rootLogger=DEBUG, stdout
+#
+#log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+#log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

+ 1613 - 0
cqb-comm-utils/src/main/resources/paper_template.ftl

@@ -0,0 +1,1613 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<?mso-application progid="Word.Document"?>
+<pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage">
+    <pkg:part pkg:name="/_rels/.rels" pkg:contentType="application/vnd.openxmlformats-package.relationships+xml" pkg:padding="512">
+        <pkg:xmlData>
+            <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
+                <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
+                <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
+                <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
+            </Relationships>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/_rels/document.xml.rels" pkg:contentType="application/vnd.openxmlformats-package.relationships+xml" pkg:padding="256">
+        <pkg:xmlData>
+            <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
+                <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>
+                <Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Target="webSettings.xml"/>
+                <Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Target="footnotes.xml"/>
+                <Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes" Target="endnotes.xml"/>
+                <Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/>
+                <Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/>
+                <Relationship Id="rId9" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/>
+                <Relationship Id="rId10" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
+                <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
+                <Relationship Id="rId2" Type="http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects" Target="stylesWithEffects.xml"/>
+            </Relationships>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/document.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml">
+        <pkg:xmlData>
+            <w:document mc:Ignorable="w14 wp14" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
+                <w:body>
+                    <w:p w14:paraId="7BAF7CA4" w14:textId="77777777" w:rsidR="00097880" w:rsidRPr="00F17E43" w:rsidRDefault="00097880" w:rsidP="00097880">
+                        <w:pPr>
+                            <w:rPr>
+                                <w:rFonts w:eastAsia="黑体"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                        </w:pPr>
+                        <w:r w:rsidRPr="00F17E43">
+                            <w:rPr>
+                                <w:rFonts w:ascii="黑体" w:eastAsia="黑体" w:hAnsi="黑体"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:t>绝密★启用前</w:t>
+                        </w:r>
+                    </w:p>
+                    <w:p w14:paraId="3A033879" w14:textId="38B2CCD4" w:rsidR="00097880" w:rsidRPr="00FD0974" w:rsidRDefault="00F24E78" w:rsidP="008239B8">
+                        <w:pPr>
+                            <w:spacing w:beforeLines="50" w:before="217"/>
+                            <w:jc w:val="center"/>
+                            <w:rPr>
+                                <w:rFonts w:eastAsia="方正小标宋_GBK"/>
+                                <w:b/>
+                                <w:sz w:val="44"/>
+                                <w:szCs w:val="44"/>
+                            </w:rPr>
+                        </w:pPr>
+                        <w:r>
+                            <w:rPr>
+                                <w:rFonts w:eastAsia="方正小标宋_GBK" w:hint="eastAsia"/>
+                                <w:b/>
+                                <w:sz w:val="44"/>
+                                <w:szCs w:val="44"/>
+                            </w:rPr>
+                            <w:t>${paper.params.courseName}</w:t>
+                        </w:r>
+                        <w:r w:rsidR="00097880" w:rsidRPr="00FD0974">
+                            <w:rPr>
+                                <w:rFonts w:eastAsia="方正小标宋_GBK"/>
+                                <w:b/>
+                                <w:sz w:val="44"/>
+                                <w:szCs w:val="44"/>
+                            </w:rPr>
+                            <w:t>试卷</w:t>
+                        </w:r>
+                    </w:p>
+                    <w:p w14:paraId="289A3FF1" w14:textId="77777777" w:rsidR="00097880" w:rsidRPr="007E01D1" w:rsidRDefault="00097880" w:rsidP="00EA765B">
+                        <w:pPr>
+                            <w:spacing w:beforeLines="50" w:before="217" w:afterLines="50" w:after="217"/>
+                            <w:jc w:val="center"/>
+                            <w:rPr>
+                                <w:bCs/>
+                                <w:sz w:val="28"/>
+                                <w:szCs w:val="28"/>
+                            </w:rPr>
+                        </w:pPr>
+                        <w:r w:rsidRPr="007E01D1">
+                            <w:rPr>
+                                <w:bCs/>
+                                <w:sz w:val="28"/>
+                                <w:szCs w:val="28"/>
+                            </w:rPr>
+                            <w:t>(课程代码</w:t>
+                        </w:r>
+                        <w:r w:rsidR="00F24E78">
+                            <w:rPr>
+                                <w:rFonts w:hint="eastAsia"/>
+                                <w:bCs/>
+                                <w:sz w:val="28"/>
+                                <w:szCs w:val="28"/>
+                            </w:rPr>
+                            <w:t>${paper.params.courseNo}</w:t>
+                        </w:r>
+                        <w:r w:rsidRPr="007E01D1">
+                            <w:rPr>
+                                <w:bCs/>
+                                <w:sz w:val="28"/>
+                                <w:szCs w:val="28"/>
+                            </w:rPr>
+                            <w:t>)</w:t>
+                        </w:r>
+                    </w:p>
+                    <w:p w14:paraId="4093CD0E" w14:textId="77777777" w:rsidR="00097880" w:rsidRPr="00F17E43" w:rsidRDefault="00097880" w:rsidP="00F17E43">
+                        <w:pPr>
+                            <w:ind w:firstLineChars="50" w:firstLine="105"/>
+                            <w:rPr>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                        </w:pPr>
+                        <w:r w:rsidRPr="00F17E43">
+                            <w:rPr>
+                                <w:rFonts w:eastAsia="黑体"/>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:t>本试卷共 页,满分</w:t>
+                        </w:r>
+                        <w:r w:rsidRPr="00F17E43">
+                            <w:rPr>
+                                <w:rFonts w:eastAsia="黑体"/>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:t>100</w:t>
+                        </w:r>
+                        <w:r w:rsidR="00F24E78">
+                            <w:rPr>
+                                <w:rFonts w:eastAsia="黑体"/>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:t>分</w:t>
+                        </w:r>
+                        <w:r w:rsidRPr="00F17E43">
+                            <w:rPr>
+                                <w:rFonts w:eastAsia="黑体"/>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:t>。</w:t>
+                        </w:r>
+                    </w:p>
+                    <w:p w14:paraId="012E5706" w14:textId="77777777" w:rsidR="005E6C64" w:rsidRDefault="005E6C64"/>
+                    <!--循环大题-->
+                    <#if paper.paperDetails?exists>
+                    <#list paper.paperDetails as paperDetail>
+                    <w:p w14:paraId="69CD38D9" w14:textId="19BE6F21" w:rsidR="00097880" w:rsidRDefault="00C62FAC" w:rsidP="00430FE2">
+                        <w:pPr>
+                            <w:adjustRightInd w:val="0"/>
+                            <w:snapToGrid w:val="0"/>
+                            <w:spacing w:beforeLines="30" w:before="130" w:line="320" w:lineRule="exact"/>
+                            <w:rPr>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                        </w:pPr>
+                        <w:r>
+                            <w:rPr>
+                                <w:rFonts w:hint="eastAsia"/>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:t>${paperDetail.cnNum}</w:t>
+                        </w:r>
+                        <w:r w:rsidR="00574041" w:rsidRPr="00574041">
+                            <w:rPr>
+                                <w:rFonts w:hint="eastAsia"/>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:t>.</w:t>
+                        </w:r>
+                        <w:r w:rsidR="00EC5025">
+                            <w:rPr>
+                                <w:rFonts w:hint="eastAsia"/>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:t>${paperDetail.name}</w:t>
+                        </w:r>
+                    </w:p>
+                    <w:p w14:paraId="58E61D59" w14:textId="77777777" w:rsidR="00A8194A" w:rsidRDefault="00A8194A" w:rsidP="00430FE2">
+                        <w:pPr>
+                            <w:adjustRightInd w:val="0"/>
+                            <w:snapToGrid w:val="0"/>
+                            <w:spacing w:beforeLines="30" w:before="130" w:line="320" w:lineRule="exact"/>
+                            <w:rPr>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                        </w:pPr>
+                    </w:p>
+                    <!--循环小题-->
+                    <#if paperDetail.paperDetailUnits?exists>
+                    <#list paperDetail.paperDetailUnits as paperDetailUnit>
+
+                        ${paperDetailUnit.question.quesBodyWord}
+
+                    <#if paperDetailUnit.question.subQuestions?exists>
+                    <#list paperDetailUnit.question.subQuestions as subQuestion>
+
+                        ${subQuestion.quesBodyWord}
+
+                        <#if subQuestion.quesOptions?exists>
+                        <#list subQuestion.quesOptions as subQuesOption>
+                            ${subQuesOption.optionBodyWord}
+                        </#list>
+                        </#if>
+
+                    </#list>
+                    </#if>
+
+                    <#if paperDetailUnit.question.quesOptions?exists>
+                    <#list paperDetailUnit.question.quesOptions as quesOption>
+                        ${quesOption.optionBodyWord}
+                     </#list>
+                    </#if>
+                    <w:p w14:paraId="15CFB5D6" w14:textId="77777777" w:rsidR="003D5A89" w:rsidRDefault="003D5A89" w:rsidP="00757E54">
+                        <w:pPr>
+                            <w:adjustRightInd w:val="0"/>
+                            <w:snapToGrid w:val="0"/>
+                            <w:spacing w:line="320" w:lineRule="exact"/>
+                            <w:rPr>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                        </w:pPr>
+                    </w:p>
+                    <w:p w14:paraId="5C7F80BF" w14:textId="77777777" w:rsidR="003D5A89" w:rsidRDefault="003D5A89" w:rsidP="00757E54">
+                        <w:pPr>
+                            <w:adjustRightInd w:val="0"/>
+                            <w:snapToGrid w:val="0"/>
+                            <w:spacing w:line="320" w:lineRule="exact"/>
+                            <w:rPr>
+                                <w:color w:val="000000"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                        </w:pPr>
+                    </w:p>
+                    </#list>
+                    </#if>
+                    </#list>
+                    </#if>
+                    <w:sectPr w:rsidR="003D5A89" w:rsidSect="00097880">
+                        <w:headerReference w:type="default" r:id="rId7"/>
+                        <w:footerReference w:type="default" r:id="rId8"/>
+                        <w:pgSz w:w="11906" w:h="16838" w:code="9"/>
+                        <w:pgMar w:top="2098" w:right="1814" w:bottom="2098" w:left="1814" w:header="851" w:footer="1814" w:gutter="0"/>
+                        <w:cols w:space="425"/>
+                        <w:docGrid w:type="lines" w:linePitch="435"/>
+                    </w:sectPr>
+                </w:body>
+            </w:document>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/footnotes.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml">
+        <pkg:xmlData>
+            <w:footnotes mc:Ignorable="w14 wp14" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
+                <w:footnote w:type="separator" w:id="-1">
+                    <w:p w14:paraId="3933DA74" w14:textId="77777777" w:rsidR="005E6C64" w:rsidRDefault="005E6C64">
+                        <w:r>
+                            <w:separator/>
+                        </w:r>
+                    </w:p>
+                </w:footnote>
+                <w:footnote w:type="continuationSeparator" w:id="0">
+                    <w:p w14:paraId="45E4E26E" w14:textId="77777777" w:rsidR="005E6C64" w:rsidRDefault="005E6C64">
+                        <w:r>
+                            <w:continuationSeparator/>
+                        </w:r>
+                    </w:p>
+                </w:footnote>
+            </w:footnotes>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/endnotes.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml">
+        <pkg:xmlData>
+            <w:endnotes mc:Ignorable="w14 wp14" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
+                <w:endnote w:type="separator" w:id="-1">
+                    <w:p w14:paraId="4AB009BF" w14:textId="77777777" w:rsidR="005E6C64" w:rsidRDefault="005E6C64">
+                        <w:r>
+                            <w:separator/>
+                        </w:r>
+                    </w:p>
+                </w:endnote>
+                <w:endnote w:type="continuationSeparator" w:id="0">
+                    <w:p w14:paraId="72409104" w14:textId="77777777" w:rsidR="005E6C64" w:rsidRDefault="005E6C64">
+                        <w:r>
+                            <w:continuationSeparator/>
+                        </w:r>
+                    </w:p>
+                </w:endnote>
+            </w:endnotes>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/header1.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml">
+        <pkg:xmlData>
+            <w:hdr mc:Ignorable="w14 wp14" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
+                <w:p w14:paraId="01C235D6" w14:textId="77777777" w:rsidR="005E6C64" w:rsidRDefault="005E6C64" w:rsidP="00097880">
+                    <w:pPr>
+                        <w:pStyle w:val="a3"/>
+                        <w:pBdr>
+                            <w:bottom w:val="none" w:sz="0" w:space="0" w:color="auto"/>
+                        </w:pBdr>
+                    </w:pPr>
+                </w:p>
+            </w:hdr>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/footer1.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml">
+        <pkg:xmlData>
+            <w:ftr mc:Ignorable="w14 wp14" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
+                <w:p w14:paraId="6B6A5894" w14:textId="13CDC3DA" w:rsidR="005E6C64" w:rsidRPr="00070B9E" w:rsidRDefault="005E6C64" w:rsidP="00070B9E">
+                    <w:pPr>
+                        <w:pStyle w:val="a4"/>
+                        <w:jc w:val="center"/>
+                    </w:pPr>
+                    <w:r w:rsidRPr="00070B9E">
+                        <w:rPr>
+                            <w:rFonts w:hint="eastAsia"/>
+                            <w:kern w:val="0"/>
+                            <w:sz w:val="21"/>
+                            <w:szCs w:val="21"/>
+                        </w:rPr>
+                        <w:t>试卷第</w:t>
+                    </w:r>
+                    <w:sdt>
+                        <w:sdtPr>
+                            <w:rPr>
+                                <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                <w:sz w:val="21"/>
+                                <w:szCs w:val="21"/>
+                            </w:rPr>
+                            <w:id w:val="-1918230034"/>
+                            <w:docPartObj>
+                                <w:docPartGallery w:val="Page Numbers (Bottom of Page)"/>
+                                <w:docPartUnique/>
+                            </w:docPartObj>
+                        </w:sdtPr>
+                        <w:sdtEndPr/>
+                        <w:sdtContent>
+                            <w:sdt>
+                                <w:sdtPr>
+                                    <w:rPr>
+                                        <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                        <w:sz w:val="21"/>
+                                        <w:szCs w:val="21"/>
+                                    </w:rPr>
+                                    <w:id w:val="98381352"/>
+                                    <w:docPartObj>
+                                        <w:docPartGallery w:val="Page Numbers (Top of Page)"/>
+                                        <w:docPartUnique/>
+                                    </w:docPartObj>
+                                </w:sdtPr>
+                                <w:sdtEndPr/>
+                                <w:sdtContent>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:fldChar w:fldCharType="begin"/>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:instrText>PAGE</w:instrText>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:fldChar w:fldCharType="separate"/>
+                                    </w:r>
+                                    <w:r w:rsidR="0007685A">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:noProof/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:t>1</w:t>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:fldChar w:fldCharType="end"/>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:kern w:val="0"/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:t>页(共</w:t>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:fldChar w:fldCharType="begin"/>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:instrText>NUMPAGES</w:instrText>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:fldChar w:fldCharType="separate"/>
+                                    </w:r>
+                                    <w:r w:rsidR="0007685A">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:noProof/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:t>1</w:t>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:bCs/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:fldChar w:fldCharType="end"/>
+                                    </w:r>
+                                    <w:r w:rsidRPr="007D3C9C">
+                                        <w:rPr>
+                                            <w:rFonts w:eastAsiaTheme="minorEastAsia"/>
+                                            <w:kern w:val="0"/>
+                                            <w:sz w:val="21"/>
+                                            <w:szCs w:val="21"/>
+                                        </w:rPr>
+                                        <w:t>页)</w:t>
+                                    </w:r>
+                                </w:sdtContent>
+                            </w:sdt>
+                        </w:sdtContent>
+                    </w:sdt>
+                </w:p>
+            </w:ftr>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/theme/theme1.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.theme+xml">
+        <pkg:xmlData>
+            <a:theme name="Office 主题​​" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
+                <a:themeElements>
+                    <a:clrScheme name="Office">
+                        <a:dk1>
+                            <a:sysClr val="windowText" lastClr="000000"/>
+                        </a:dk1>
+                        <a:lt1>
+                            <a:sysClr val="window" lastClr="FFFFFF"/>
+                        </a:lt1>
+                        <a:dk2>
+                            <a:srgbClr val="1F497D"/>
+                        </a:dk2>
+                        <a:lt2>
+                            <a:srgbClr val="EEECE1"/>
+                        </a:lt2>
+                        <a:accent1>
+                            <a:srgbClr val="4F81BD"/>
+                        </a:accent1>
+                        <a:accent2>
+                            <a:srgbClr val="C0504D"/>
+                        </a:accent2>
+                        <a:accent3>
+                            <a:srgbClr val="9BBB59"/>
+                        </a:accent3>
+                        <a:accent4>
+                            <a:srgbClr val="8064A2"/>
+                        </a:accent4>
+                        <a:accent5>
+                            <a:srgbClr val="4BACC6"/>
+                        </a:accent5>
+                        <a:accent6>
+                            <a:srgbClr val="F79646"/>
+                        </a:accent6>
+                        <a:hlink>
+                            <a:srgbClr val="0000FF"/>
+                        </a:hlink>
+                        <a:folHlink>
+                            <a:srgbClr val="800080"/>
+                        </a:folHlink>
+                    </a:clrScheme>
+                    <a:fontScheme name="Office">
+                        <a:majorFont>
+                            <a:latin typeface="Cambria"/>
+                            <a:ea typeface=""/>
+                            <a:cs typeface=""/>
+                            <a:font script="Jpan" typeface="MS ゴシック"/>
+                            <a:font script="Hang" typeface="맑은 고딕"/>
+                            <a:font script="Hans" typeface="宋体"/>
+                            <a:font script="Hant" typeface="新細明體"/>
+                            <a:font script="Arab" typeface="Times New Roman"/>
+                            <a:font script="Hebr" typeface="Times New Roman"/>
+                            <a:font script="Thai" typeface="Angsana New"/>
+                            <a:font script="Ethi" typeface="Nyala"/>
+                            <a:font script="Beng" typeface="Vrinda"/>
+                            <a:font script="Gujr" typeface="Shruti"/>
+                            <a:font script="Khmr" typeface="MoolBoran"/>
+                            <a:font script="Knda" typeface="Tunga"/>
+                            <a:font script="Guru" typeface="Raavi"/>
+                            <a:font script="Cans" typeface="Euphemia"/>
+                            <a:font script="Cher" typeface="Plantagenet Cherokee"/>
+                            <a:font script="Yiii" typeface="Microsoft Yi Baiti"/>
+                            <a:font script="Tibt" typeface="Microsoft Himalaya"/>
+                            <a:font script="Thaa" typeface="MV Boli"/>
+                            <a:font script="Deva" typeface="Mangal"/>
+                            <a:font script="Telu" typeface="Gautami"/>
+                            <a:font script="Taml" typeface="Latha"/>
+                            <a:font script="Syrc" typeface="Estrangelo Edessa"/>
+                            <a:font script="Orya" typeface="Kalinga"/>
+                            <a:font script="Mlym" typeface="Kartika"/>
+                            <a:font script="Laoo" typeface="DokChampa"/>
+                            <a:font script="Sinh" typeface="Iskoola Pota"/>
+                            <a:font script="Mong" typeface="Mongolian Baiti"/>
+                            <a:font script="Viet" typeface="Times New Roman"/>
+                            <a:font script="Uigh" typeface="Microsoft Uighur"/>
+                            <a:font script="Geor" typeface="Sylfaen"/>
+                        </a:majorFont>
+                        <a:minorFont>
+                            <a:latin typeface="Calibri"/>
+                            <a:ea typeface=""/>
+                            <a:cs typeface=""/>
+                            <a:font script="Jpan" typeface="MS 明朝"/>
+                            <a:font script="Hang" typeface="맑은 고딕"/>
+                            <a:font script="Hans" typeface="宋体"/>
+                            <a:font script="Hant" typeface="新細明體"/>
+                            <a:font script="Arab" typeface="Arial"/>
+                            <a:font script="Hebr" typeface="Arial"/>
+                            <a:font script="Thai" typeface="Cordia New"/>
+                            <a:font script="Ethi" typeface="Nyala"/>
+                            <a:font script="Beng" typeface="Vrinda"/>
+                            <a:font script="Gujr" typeface="Shruti"/>
+                            <a:font script="Khmr" typeface="DaunPenh"/>
+                            <a:font script="Knda" typeface="Tunga"/>
+                            <a:font script="Guru" typeface="Raavi"/>
+                            <a:font script="Cans" typeface="Euphemia"/>
+                            <a:font script="Cher" typeface="Plantagenet Cherokee"/>
+                            <a:font script="Yiii" typeface="Microsoft Yi Baiti"/>
+                            <a:font script="Tibt" typeface="Microsoft Himalaya"/>
+                            <a:font script="Thaa" typeface="MV Boli"/>
+                            <a:font script="Deva" typeface="Mangal"/>
+                            <a:font script="Telu" typeface="Gautami"/>
+                            <a:font script="Taml" typeface="Latha"/>
+                            <a:font script="Syrc" typeface="Estrangelo Edessa"/>
+                            <a:font script="Orya" typeface="Kalinga"/>
+                            <a:font script="Mlym" typeface="Kartika"/>
+                            <a:font script="Laoo" typeface="DokChampa"/>
+                            <a:font script="Sinh" typeface="Iskoola Pota"/>
+                            <a:font script="Mong" typeface="Mongolian Baiti"/>
+                            <a:font script="Viet" typeface="Arial"/>
+                            <a:font script="Uigh" typeface="Microsoft Uighur"/>
+                            <a:font script="Geor" typeface="Sylfaen"/>
+                        </a:minorFont>
+                    </a:fontScheme>
+                    <a:fmtScheme name="Office">
+                        <a:fillStyleLst>
+                            <a:solidFill>
+                                <a:schemeClr val="phClr"/>
+                            </a:solidFill>
+                            <a:gradFill rotWithShape="1">
+                                <a:gsLst>
+                                    <a:gs pos="0">
+                                        <a:schemeClr val="phClr">
+                                            <a:tint val="50000"/>
+                                            <a:satMod val="300000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                    <a:gs pos="35000">
+                                        <a:schemeClr val="phClr">
+                                            <a:tint val="37000"/>
+                                            <a:satMod val="300000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                    <a:gs pos="100000">
+                                        <a:schemeClr val="phClr">
+                                            <a:tint val="15000"/>
+                                            <a:satMod val="350000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                </a:gsLst>
+                                <a:lin ang="16200000" scaled="1"/>
+                            </a:gradFill>
+                            <a:gradFill rotWithShape="1">
+                                <a:gsLst>
+                                    <a:gs pos="0">
+                                        <a:schemeClr val="phClr">
+                                            <a:shade val="51000"/>
+                                            <a:satMod val="130000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                    <a:gs pos="80000">
+                                        <a:schemeClr val="phClr">
+                                            <a:shade val="93000"/>
+                                            <a:satMod val="130000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                    <a:gs pos="100000">
+                                        <a:schemeClr val="phClr">
+                                            <a:shade val="94000"/>
+                                            <a:satMod val="135000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                </a:gsLst>
+                                <a:lin ang="16200000" scaled="0"/>
+                            </a:gradFill>
+                        </a:fillStyleLst>
+                        <a:lnStyleLst>
+                            <a:ln w="9525" cap="flat" cmpd="sng" algn="ctr">
+                                <a:solidFill>
+                                    <a:schemeClr val="phClr">
+                                        <a:shade val="95000"/>
+                                        <a:satMod val="105000"/>
+                                    </a:schemeClr>
+                                </a:solidFill>
+                                <a:prstDash val="solid"/>
+                            </a:ln>
+                            <a:ln w="25400" cap="flat" cmpd="sng" algn="ctr">
+                                <a:solidFill>
+                                    <a:schemeClr val="phClr"/>
+                                </a:solidFill>
+                                <a:prstDash val="solid"/>
+                            </a:ln>
+                            <a:ln w="38100" cap="flat" cmpd="sng" algn="ctr">
+                                <a:solidFill>
+                                    <a:schemeClr val="phClr"/>
+                                </a:solidFill>
+                                <a:prstDash val="solid"/>
+                            </a:ln>
+                        </a:lnStyleLst>
+                        <a:effectStyleLst>
+                            <a:effectStyle>
+                                <a:effectLst>
+                                    <a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="0">
+                                        <a:srgbClr val="000000">
+                                            <a:alpha val="38000"/>
+                                        </a:srgbClr>
+                                    </a:outerShdw>
+                                </a:effectLst>
+                            </a:effectStyle>
+                            <a:effectStyle>
+                                <a:effectLst>
+                                    <a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0">
+                                        <a:srgbClr val="000000">
+                                            <a:alpha val="35000"/>
+                                        </a:srgbClr>
+                                    </a:outerShdw>
+                                </a:effectLst>
+                            </a:effectStyle>
+                            <a:effectStyle>
+                                <a:effectLst>
+                                    <a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0">
+                                        <a:srgbClr val="000000">
+                                            <a:alpha val="35000"/>
+                                        </a:srgbClr>
+                                    </a:outerShdw>
+                                </a:effectLst>
+                                <a:scene3d>
+                                    <a:camera prst="orthographicFront">
+                                        <a:rot lat="0" lon="0" rev="0"/>
+                                    </a:camera>
+                                    <a:lightRig rig="threePt" dir="t">
+                                        <a:rot lat="0" lon="0" rev="1200000"/>
+                                    </a:lightRig>
+                                </a:scene3d>
+                                <a:sp3d>
+                                    <a:bevelT w="63500" h="25400"/>
+                                </a:sp3d>
+                            </a:effectStyle>
+                        </a:effectStyleLst>
+                        <a:bgFillStyleLst>
+                            <a:solidFill>
+                                <a:schemeClr val="phClr"/>
+                            </a:solidFill>
+                            <a:gradFill rotWithShape="1">
+                                <a:gsLst>
+                                    <a:gs pos="0">
+                                        <a:schemeClr val="phClr">
+                                            <a:tint val="40000"/>
+                                            <a:satMod val="350000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                    <a:gs pos="40000">
+                                        <a:schemeClr val="phClr">
+                                            <a:tint val="45000"/>
+                                            <a:shade val="99000"/>
+                                            <a:satMod val="350000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                    <a:gs pos="100000">
+                                        <a:schemeClr val="phClr">
+                                            <a:shade val="20000"/>
+                                            <a:satMod val="255000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                </a:gsLst>
+                                <a:path path="circle">
+                                    <a:fillToRect l="50000" t="-80000" r="50000" b="180000"/>
+                                </a:path>
+                            </a:gradFill>
+                            <a:gradFill rotWithShape="1">
+                                <a:gsLst>
+                                    <a:gs pos="0">
+                                        <a:schemeClr val="phClr">
+                                            <a:tint val="80000"/>
+                                            <a:satMod val="300000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                    <a:gs pos="100000">
+                                        <a:schemeClr val="phClr">
+                                            <a:shade val="30000"/>
+                                            <a:satMod val="200000"/>
+                                        </a:schemeClr>
+                                    </a:gs>
+                                </a:gsLst>
+                                <a:path path="circle">
+                                    <a:fillToRect l="50000" t="50000" r="50000" b="50000"/>
+                                </a:path>
+                            </a:gradFill>
+                        </a:bgFillStyleLst>
+                    </a:fmtScheme>
+                </a:themeElements>
+                <a:objectDefaults/>
+                <a:extraClrSchemeLst/>
+            </a:theme>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/settings.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml">
+        <pkg:xmlData>
+            <w:settings mc:Ignorable="w14" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main">
+                <w:zoom w:percent="150"/>
+                <w:bordersDoNotSurroundHeader/>
+                <w:bordersDoNotSurroundFooter/>
+                <w:proofState w:spelling="clean" w:grammar="clean"/>
+                <w:stylePaneFormatFilter w:val="3F01" w:allStyles="1" w:customStyles="0" w:latentStyles="0" w:stylesInUse="0" w:headingStyles="0" w:numberingStyles="0" w:tableStyles="0" w:directFormattingOnRuns="1" w:directFormattingOnParagraphs="1" w:directFormattingOnNumbering="1" w:directFormattingOnTables="1" w:clearFormatting="1" w:top3HeadingStyles="1" w:visibleStyles="0" w:alternateStyleNames="0"/>
+                <w:defaultTabStop w:val="420"/>
+                <w:drawingGridHorizontalSpacing w:val="160"/>
+                <w:drawingGridVerticalSpacing w:val="435"/>
+                <w:displayHorizontalDrawingGridEvery w:val="0"/>
+                <w:characterSpacingControl w:val="compressPunctuation"/>
+                <w:hdrShapeDefaults>
+                    <o:shapedefaults v:ext="edit" spidmax="2050"/>
+                </w:hdrShapeDefaults>
+                <w:footnotePr>
+                    <w:footnote w:id="-1"/>
+                    <w:footnote w:id="0"/>
+                </w:footnotePr>
+                <w:endnotePr>
+                    <w:endnote w:id="-1"/>
+                    <w:endnote w:id="0"/>
+                </w:endnotePr>
+                <w:compat>
+                    <w:spaceForUL/>
+                    <w:balanceSingleByteDoubleByteWidth/>
+                    <w:doNotLeaveBackslashAlone/>
+                    <w:ulTrailSpace/>
+                    <w:doNotExpandShiftReturn/>
+                    <w:adjustLineHeightInTable/>
+                    <w:useFELayout/>
+                    <w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="14"/>
+                    <w:compatSetting w:name="overrideTableStyleFontSizeAndJustification" w:uri="http://schemas.microsoft.com/office/word" w:val="1"/>
+                    <w:compatSetting w:name="enableOpenTypeFeatures" w:uri="http://schemas.microsoft.com/office/word" w:val="1"/>
+                    <w:compatSetting w:name="doNotFlipMirrorIndents" w:uri="http://schemas.microsoft.com/office/word" w:val="1"/>
+                </w:compat>
+                <w:rsids>
+                    <w:rsidRoot w:val="00097880"/>
+                    <w:rsid w:val="00032C9E"/>
+                    <w:rsid w:val="00040F2F"/>
+                    <w:rsid w:val="0006124A"/>
+                    <w:rsid w:val="00063B9B"/>
+                    <w:rsid w:val="00070B9E"/>
+                    <w:rsid w:val="00075B8D"/>
+                    <w:rsid w:val="0007685A"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:rsid w:val="000D4AC3"/>
+                    <w:rsid w:val="000F4283"/>
+                    <w:rsid w:val="00110C92"/>
+                    <w:rsid w:val="00153753"/>
+                    <w:rsid w:val="00177009"/>
+                    <w:rsid w:val="00195A56"/>
+                    <w:rsid w:val="00226D45"/>
+                    <w:rsid w:val="0028721C"/>
+                    <w:rsid w:val="002B6566"/>
+                    <w:rsid w:val="00324193"/>
+                    <w:rsid w:val="003A479C"/>
+                    <w:rsid w:val="003B5EF6"/>
+                    <w:rsid w:val="003B7191"/>
+                    <w:rsid w:val="003D5A89"/>
+                    <w:rsid w:val="003D7262"/>
+                    <w:rsid w:val="00423EE5"/>
+                    <w:rsid w:val="00430FE2"/>
+                    <w:rsid w:val="00460051"/>
+                    <w:rsid w:val="00467132"/>
+                    <w:rsid w:val="00497D71"/>
+                    <w:rsid w:val="004B69E8"/>
+                    <w:rsid w:val="004E66B2"/>
+                    <w:rsid w:val="004F543C"/>
+                    <w:rsid w:val="00517A21"/>
+                    <w:rsid w:val="00574041"/>
+                    <w:rsid w:val="00576D0C"/>
+                    <w:rsid w:val="005C192C"/>
+                    <w:rsid w:val="005C592F"/>
+                    <w:rsid w:val="005D30EC"/>
+                    <w:rsid w:val="005E6C64"/>
+                    <w:rsid w:val="006256AF"/>
+                    <w:rsid w:val="0063380F"/>
+                    <w:rsid w:val="00681035"/>
+                    <w:rsid w:val="00692287"/>
+                    <w:rsid w:val="006C2185"/>
+                    <w:rsid w:val="00703B43"/>
+                    <w:rsid w:val="0071469F"/>
+                    <w:rsid w:val="007224D1"/>
+                    <w:rsid w:val="007253D9"/>
+                    <w:rsid w:val="00757B9C"/>
+                    <w:rsid w:val="00757E54"/>
+                    <w:rsid w:val="007760B2"/>
+                    <w:rsid w:val="00776F80"/>
+                    <w:rsid w:val="007B25AC"/>
+                    <w:rsid w:val="007B656F"/>
+                    <w:rsid w:val="007C044A"/>
+                    <w:rsid w:val="007C31D0"/>
+                    <w:rsid w:val="007C551B"/>
+                    <w:rsid w:val="007E01D1"/>
+                    <w:rsid w:val="008239B8"/>
+                    <w:rsid w:val="00852C57"/>
+                    <w:rsid w:val="00852E4F"/>
+                    <w:rsid w:val="0089447C"/>
+                    <w:rsid w:val="008E795C"/>
+                    <w:rsid w:val="0094646F"/>
+                    <w:rsid w:val="00950F33"/>
+                    <w:rsid w:val="00965B17"/>
+                    <w:rsid w:val="00985EFB"/>
+                    <w:rsid w:val="009A14B0"/>
+                    <w:rsid w:val="009A1711"/>
+                    <w:rsid w:val="00A052CD"/>
+                    <w:rsid w:val="00A31E04"/>
+                    <w:rsid w:val="00A32E54"/>
+                    <w:rsid w:val="00A42ED9"/>
+                    <w:rsid w:val="00A74712"/>
+                    <w:rsid w:val="00A8194A"/>
+                    <w:rsid w:val="00A87B57"/>
+                    <w:rsid w:val="00A913BA"/>
+                    <w:rsid w:val="00A945C6"/>
+                    <w:rsid w:val="00AA358F"/>
+                    <w:rsid w:val="00AA630E"/>
+                    <w:rsid w:val="00AC5FB3"/>
+                    <w:rsid w:val="00AD27CB"/>
+                    <w:rsid w:val="00AF49C6"/>
+                    <w:rsid w:val="00B10706"/>
+                    <w:rsid w:val="00B262C2"/>
+                    <w:rsid w:val="00B46ADE"/>
+                    <w:rsid w:val="00B963C7"/>
+                    <w:rsid w:val="00BA4604"/>
+                    <w:rsid w:val="00BD30D2"/>
+                    <w:rsid w:val="00C00E2B"/>
+                    <w:rsid w:val="00C14CC9"/>
+                    <w:rsid w:val="00C40249"/>
+                    <w:rsid w:val="00C5483B"/>
+                    <w:rsid w:val="00C62FAC"/>
+                    <w:rsid w:val="00C66982"/>
+                    <w:rsid w:val="00C854BB"/>
+                    <w:rsid w:val="00CA2F5E"/>
+                    <w:rsid w:val="00D05D1D"/>
+                    <w:rsid w:val="00D21C3F"/>
+                    <w:rsid w:val="00D52CCC"/>
+                    <w:rsid w:val="00D9781C"/>
+                    <w:rsid w:val="00DB0CB3"/>
+                    <w:rsid w:val="00DE5559"/>
+                    <w:rsid w:val="00DF790F"/>
+                    <w:rsid w:val="00E20128"/>
+                    <w:rsid w:val="00E441A6"/>
+                    <w:rsid w:val="00E470C7"/>
+                    <w:rsid w:val="00E57B71"/>
+                    <w:rsid w:val="00E60449"/>
+                    <w:rsid w:val="00EA765B"/>
+                    <w:rsid w:val="00EB33B3"/>
+                    <w:rsid w:val="00EC5025"/>
+                    <w:rsid w:val="00EF1006"/>
+                    <w:rsid w:val="00F07FBD"/>
+                    <w:rsid w:val="00F17E43"/>
+                    <w:rsid w:val="00F24E78"/>
+                    <w:rsid w:val="00F325CF"/>
+                    <w:rsid w:val="00F44AF9"/>
+                    <w:rsid w:val="00FB74AE"/>
+                    <w:rsid w:val="00FC5A19"/>
+                    <w:rsid w:val="00FD0974"/>
+                    <w:rsid w:val="00FE31B1"/>
+                </w:rsids>
+                <m:mathPr>
+                    <m:mathFont m:val="Cambria Math"/>
+                    <m:brkBin m:val="before"/>
+                    <m:brkBinSub m:val="--"/>
+                    <m:smallFrac m:val="0"/>
+                    <m:dispDef/>
+                    <m:lMargin m:val="0"/>
+                    <m:rMargin m:val="0"/>
+                    <m:defJc m:val="centerGroup"/>
+                    <m:wrapIndent m:val="1440"/>
+                    <m:intLim m:val="subSup"/>
+                    <m:naryLim m:val="undOvr"/>
+                </m:mathPr>
+                <w:themeFontLang w:val="en-US" w:eastAsia="zh-CN"/>
+                <w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink"/>
+                <w:doNotIncludeSubdocsInStats/>
+                <w:doNotAutoCompressPictures/>
+                <w:shapeDefaults>
+                    <o:shapedefaults v:ext="edit" spidmax="2050"/>
+                    <o:shapelayout v:ext="edit">
+                        <o:idmap v:ext="edit" data="1"/>
+                    </o:shapelayout>
+                </w:shapeDefaults>
+                <w:decimalSymbol w:val="."/>
+                <w:listSeparator w:val=","/>
+                <w14:docId w14:val="1601E0DE"/>
+            </w:settings>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/webSettings.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml">
+        <pkg:xmlData>
+            <w:webSettings mc:Ignorable="w14" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml">
+                <w:optimizeForBrowser/>
+                <w:doNotSaveAsSingleFile/>
+            </w:webSettings>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/stylesWithEffects.xml" pkg:contentType="application/vnd.ms-word.stylesWithEffects+xml">
+        <pkg:xmlData>
+            <w:styles mc:Ignorable="w14 wp14" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
+                <w:docDefaults>
+                    <w:rPrDefault>
+                        <w:rPr>
+                            <w:rFonts w:ascii="Times New Roman" w:eastAsia="宋体" w:hAnsi="Times New Roman" w:cs="Times New Roman"/>
+                            <w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA"/>
+                        </w:rPr>
+                    </w:rPrDefault>
+                    <w:pPrDefault/>
+                </w:docDefaults>
+                <w:latentStyles w:defLockedState="0" w:defUIPriority="0" w:defSemiHidden="0" w:defUnhideWhenUsed="0" w:defQFormat="0" w:count="276">
+                    <w:lsdException w:name="Normal" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 2" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 3" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 4" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 5" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 6" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 7" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 8" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 9" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="footer" w:uiPriority="99"/>
+                    <w:lsdException w:name="caption" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="Title" w:qFormat="1"/>
+                    <w:lsdException w:name="Subtitle" w:qFormat="1"/>
+                    <w:lsdException w:name="Strong" w:qFormat="1"/>
+                    <w:lsdException w:name="Emphasis" w:qFormat="1"/>
+                    <w:lsdException w:name="Placeholder Text" w:semiHidden="1" w:uiPriority="99"/>
+                    <w:lsdException w:name="No Spacing" w:uiPriority="1" w:qFormat="1"/>
+                    <w:lsdException w:name="Light Shading" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 1" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 1" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 1" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 1" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 1" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 1" w:uiPriority="65"/>
+                    <w:lsdException w:name="Revision" w:semiHidden="1" w:uiPriority="99"/>
+                    <w:lsdException w:name="List Paragraph" w:uiPriority="34" w:qFormat="1"/>
+                    <w:lsdException w:name="Quote" w:uiPriority="29" w:qFormat="1"/>
+                    <w:lsdException w:name="Intense Quote" w:uiPriority="30" w:qFormat="1"/>
+                    <w:lsdException w:name="Medium List 2 Accent 1" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 1" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 1" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 1" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 1" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 1" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 1" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 1" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 2" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 2" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 2" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 2" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 2" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 2" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 2" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 2" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 2" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 2" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 2" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 2" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 2" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 2" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 3" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 3" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 3" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 3" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 3" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 3" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 3" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 3" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 3" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 3" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 3" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 3" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 3" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 3" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 4" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 4" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 4" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 4" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 4" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 4" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 4" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 4" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 4" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 4" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 4" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 4" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 4" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 4" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 5" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 5" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 5" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 5" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 5" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 5" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 5" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 5" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 5" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 5" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 5" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 5" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 5" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 5" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 6" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 6" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 6" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 6" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 6" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 6" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 6" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 6" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 6" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 6" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 6" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 6" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 6" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 6" w:uiPriority="73"/>
+                    <w:lsdException w:name="Subtle Emphasis" w:uiPriority="19" w:qFormat="1"/>
+                    <w:lsdException w:name="Intense Emphasis" w:uiPriority="21" w:qFormat="1"/>
+                    <w:lsdException w:name="Subtle Reference" w:uiPriority="31" w:qFormat="1"/>
+                    <w:lsdException w:name="Intense Reference" w:uiPriority="32" w:qFormat="1"/>
+                    <w:lsdException w:name="Book Title" w:uiPriority="33" w:qFormat="1"/>
+                    <w:lsdException w:name="Bibliography" w:semiHidden="1" w:uiPriority="37" w:unhideWhenUsed="1"/>
+                    <w:lsdException w:name="TOC Heading" w:semiHidden="1" w:uiPriority="39" w:unhideWhenUsed="1" w:qFormat="1"/>
+                </w:latentStyles>
+                <w:style w:type="paragraph" w:default="1" w:styleId="a">
+                    <w:name w:val="Normal"/>
+                    <w:qFormat/>
+                    <w:rsid w:val="00097880"/>
+                    <w:pPr>
+                        <w:widowControl w:val="0"/>
+                        <w:jc w:val="both"/>
+                    </w:pPr>
+                    <w:rPr>
+                        <w:kern w:val="2"/>
+                        <w:sz w:val="21"/>
+                        <w:szCs w:val="24"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="character" w:default="1" w:styleId="a0">
+                    <w:name w:val="Default Paragraph Font"/>
+                    <w:uiPriority w:val="1"/>
+                    <w:semiHidden/>
+                    <w:unhideWhenUsed/>
+                </w:style>
+                <w:style w:type="table" w:default="1" w:styleId="a1">
+                    <w:name w:val="Normal Table"/>
+                    <w:uiPriority w:val="99"/>
+                    <w:semiHidden/>
+                    <w:unhideWhenUsed/>
+                    <w:tblPr>
+                        <w:tblInd w:w="0" w:type="dxa"/>
+                        <w:tblCellMar>
+                            <w:top w:w="0" w:type="dxa"/>
+                            <w:left w:w="108" w:type="dxa"/>
+                            <w:bottom w:w="0" w:type="dxa"/>
+                            <w:right w:w="108" w:type="dxa"/>
+                        </w:tblCellMar>
+                    </w:tblPr>
+                </w:style>
+                <w:style w:type="numbering" w:default="1" w:styleId="a2">
+                    <w:name w:val="No List"/>
+                    <w:uiPriority w:val="99"/>
+                    <w:semiHidden/>
+                    <w:unhideWhenUsed/>
+                </w:style>
+                <w:style w:type="paragraph" w:styleId="a3">
+                    <w:name w:val="header"/>
+                    <w:basedOn w:val="a"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:pPr>
+                        <w:pBdr>
+                            <w:bottom w:val="single" w:sz="6" w:space="1" w:color="auto"/>
+                        </w:pBdr>
+                        <w:tabs>
+                            <w:tab w:val="center" w:pos="4153"/>
+                            <w:tab w:val="right" w:pos="8306"/>
+                        </w:tabs>
+                        <w:snapToGrid w:val="0"/>
+                        <w:jc w:val="center"/>
+                    </w:pPr>
+                    <w:rPr>
+                        <w:sz w:val="18"/>
+                        <w:szCs w:val="18"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="paragraph" w:styleId="a4">
+                    <w:name w:val="footer"/>
+                    <w:basedOn w:val="a"/>
+                    <w:link w:val="a5"/>
+                    <w:uiPriority w:val="99"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:pPr>
+                        <w:tabs>
+                            <w:tab w:val="center" w:pos="4153"/>
+                            <w:tab w:val="right" w:pos="8306"/>
+                        </w:tabs>
+                        <w:snapToGrid w:val="0"/>
+                        <w:jc w:val="left"/>
+                    </w:pPr>
+                    <w:rPr>
+                        <w:sz w:val="18"/>
+                        <w:szCs w:val="18"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="paragraph" w:styleId="a6">
+                    <w:name w:val="Plain Text"/>
+                    <w:basedOn w:val="a"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:rPr>
+                        <w:rFonts w:ascii="宋体" w:hAnsi="Courier New" w:cs="Courier New"/>
+                        <w:szCs w:val="21"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="paragraph" w:customStyle="1" w:styleId="MSMincho">
+                    <w:name w:val="MS Mincho"/>
+                    <w:basedOn w:val="a"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:rPr>
+                        <w:rFonts w:ascii="MS Mincho" w:eastAsia="MS Mincho" w:hAnsi="MS Mincho"/>
+                        <w:sz w:val="24"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="paragraph" w:customStyle="1" w:styleId="1">
+                    <w:name w:val="1"/>
+                    <w:basedOn w:val="a"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:pPr>
+                        <w:widowControl/>
+                        <w:jc w:val="left"/>
+                    </w:pPr>
+                    <w:rPr>
+                        <w:noProof/>
+                        <w:kern w:val="0"/>
+                        <w:sz w:val="24"/>
+                        <w:lang w:eastAsia="de-DE"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="character" w:customStyle="1" w:styleId="a5">
+                    <w:name w:val="页脚字符"/>
+                    <w:basedOn w:val="a0"/>
+                    <w:link w:val="a4"/>
+                    <w:uiPriority w:val="99"/>
+                    <w:rsid w:val="00070B9E"/>
+                    <w:rPr>
+                        <w:kern w:val="2"/>
+                        <w:sz w:val="18"/>
+                        <w:szCs w:val="18"/>
+                    </w:rPr>
+                </w:style>
+            </w:styles>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/fontTable.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml">
+        <pkg:xmlData>
+            <w:fonts mc:Ignorable="w14" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml">
+                <w:font w:name="Times New Roman">
+                    <w:panose1 w:val="02020603050405020304"/>
+                    <w:charset w:val="00"/>
+                    <w:family w:val="auto"/>
+                    <w:pitch w:val="variable"/>
+                    <w:sig w:usb0="E0002AFF" w:usb1="C0007841" w:usb2="00000009" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/>
+                </w:font>
+                <w:font w:name="宋体">
+                    <w:panose1 w:val="02010600030101010101"/>
+                    <w:charset w:val="50"/>
+                    <w:family w:val="auto"/>
+                    <w:pitch w:val="variable"/>
+                    <w:sig w:usb0="00000003" w:usb1="288F0000" w:usb2="00000016" w:usb3="00000000" w:csb0="00040001" w:csb1="00000000"/>
+                </w:font>
+                <w:font w:name="Courier New">
+                    <w:panose1 w:val="02070309020205020404"/>
+                    <w:charset w:val="00"/>
+                    <w:family w:val="auto"/>
+                    <w:pitch w:val="variable"/>
+                    <w:sig w:usb0="E0002AFF" w:usb1="C0007843" w:usb2="00000009" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/>
+                </w:font>
+                <w:font w:name="MS Mincho">
+                    <w:altName w:val="MS 明朝"/>
+                    <w:charset w:val="80"/>
+                    <w:family w:val="modern"/>
+                    <w:pitch w:val="fixed"/>
+                    <w:sig w:usb0="E00002FF" w:usb1="6AC7FDFB" w:usb2="00000012" w:usb3="00000000" w:csb0="0002009F" w:csb1="00000000"/>
+                </w:font>
+                <w:font w:name="黑体">
+                    <w:panose1 w:val="02010609060101010101"/>
+                    <w:charset w:val="50"/>
+                    <w:family w:val="auto"/>
+                    <w:pitch w:val="variable"/>
+                    <w:sig w:usb0="800002BF" w:usb1="38CF7CFA" w:usb2="00000016" w:usb3="00000000" w:csb0="00040001" w:csb1="00000000"/>
+                </w:font>
+                <w:font w:name="方正小标宋_GBK">
+                    <w:altName w:val="Arial Unicode MS"/>
+                    <w:charset w:val="86"/>
+                    <w:family w:val="script"/>
+                    <w:pitch w:val="fixed"/>
+                    <w:sig w:usb0="00000000" w:usb1="080E0000" w:usb2="00000010" w:usb3="00000000" w:csb0="00040000" w:csb1="00000000"/>
+                </w:font>
+                <w:font w:name="Arial">
+                    <w:panose1 w:val="020B0604020202020204"/>
+                    <w:charset w:val="00"/>
+                    <w:family w:val="auto"/>
+                    <w:pitch w:val="variable"/>
+                    <w:sig w:usb0="E0002AFF" w:usb1="C0007843" w:usb2="00000009" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/>
+                </w:font>
+                <w:font w:name="Cambria">
+                    <w:panose1 w:val="02040503050406030204"/>
+                    <w:charset w:val="00"/>
+                    <w:family w:val="auto"/>
+                    <w:pitch w:val="variable"/>
+                    <w:sig w:usb0="E00002FF" w:usb1="400004FF" w:usb2="00000000" w:usb3="00000000" w:csb0="0000019F" w:csb1="00000000"/>
+                </w:font>
+                <w:font w:name="Calibri">
+                    <w:panose1 w:val="020F0502020204030204"/>
+                    <w:charset w:val="00"/>
+                    <w:family w:val="auto"/>
+                    <w:pitch w:val="variable"/>
+                    <w:sig w:usb0="E10002FF" w:usb1="4000ACFF" w:usb2="00000009" w:usb3="00000000" w:csb0="0000019F" w:csb1="00000000"/>
+                </w:font>
+            </w:fonts>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/docProps/core.xml" pkg:contentType="application/vnd.openxmlformats-package.core-properties+xml" pkg:padding="256">
+        <pkg:xmlData>
+            <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+                <dc:title>绝密★启用前</dc:title>
+                <dc:creator>QMTH</dc:creator>
+                <cp:lastModifiedBy>悦 宋</cp:lastModifiedBy>
+                <cp:revision>16</cp:revision>
+                <cp:lastPrinted>2010-11-01T11:38:00Z</cp:lastPrinted>
+                <dcterms:created xsi:type="dcterms:W3CDTF">2017-03-14T10:02:00Z</dcterms:created>
+                <dcterms:modified xsi:type="dcterms:W3CDTF">2017-03-14T10:19:00Z</dcterms:modified>
+            </cp:coreProperties>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/word/styles.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml">
+        <pkg:xmlData>
+            <w:styles mc:Ignorable="w14" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml">
+                <w:docDefaults>
+                    <w:rPrDefault>
+                        <w:rPr>
+                            <w:rFonts w:ascii="Times New Roman" w:eastAsia="宋体" w:hAnsi="Times New Roman" w:cs="Times New Roman"/>
+                            <w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA"/>
+                        </w:rPr>
+                    </w:rPrDefault>
+                    <w:pPrDefault/>
+                </w:docDefaults>
+                <w:latentStyles w:defLockedState="0" w:defUIPriority="0" w:defSemiHidden="0" w:defUnhideWhenUsed="0" w:defQFormat="0" w:count="276">
+                    <w:lsdException w:name="Normal" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 2" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 3" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 4" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 5" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 6" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 7" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 8" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="heading 9" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="footer" w:uiPriority="99"/>
+                    <w:lsdException w:name="caption" w:semiHidden="1" w:unhideWhenUsed="1" w:qFormat="1"/>
+                    <w:lsdException w:name="Title" w:qFormat="1"/>
+                    <w:lsdException w:name="Subtitle" w:qFormat="1"/>
+                    <w:lsdException w:name="Strong" w:qFormat="1"/>
+                    <w:lsdException w:name="Emphasis" w:qFormat="1"/>
+                    <w:lsdException w:name="Placeholder Text" w:semiHidden="1" w:uiPriority="99"/>
+                    <w:lsdException w:name="No Spacing" w:uiPriority="1" w:qFormat="1"/>
+                    <w:lsdException w:name="Light Shading" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 1" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 1" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 1" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 1" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 1" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 1" w:uiPriority="65"/>
+                    <w:lsdException w:name="Revision" w:semiHidden="1" w:uiPriority="99"/>
+                    <w:lsdException w:name="List Paragraph" w:uiPriority="34" w:qFormat="1"/>
+                    <w:lsdException w:name="Quote" w:uiPriority="29" w:qFormat="1"/>
+                    <w:lsdException w:name="Intense Quote" w:uiPriority="30" w:qFormat="1"/>
+                    <w:lsdException w:name="Medium List 2 Accent 1" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 1" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 1" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 1" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 1" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 1" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 1" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 1" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 2" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 2" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 2" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 2" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 2" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 2" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 2" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 2" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 2" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 2" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 2" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 2" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 2" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 2" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 3" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 3" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 3" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 3" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 3" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 3" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 3" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 3" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 3" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 3" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 3" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 3" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 3" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 3" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 4" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 4" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 4" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 4" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 4" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 4" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 4" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 4" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 4" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 4" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 4" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 4" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 4" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 4" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 5" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 5" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 5" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 5" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 5" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 5" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 5" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 5" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 5" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 5" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 5" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 5" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 5" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 5" w:uiPriority="73"/>
+                    <w:lsdException w:name="Light Shading Accent 6" w:uiPriority="60"/>
+                    <w:lsdException w:name="Light List Accent 6" w:uiPriority="61"/>
+                    <w:lsdException w:name="Light Grid Accent 6" w:uiPriority="62"/>
+                    <w:lsdException w:name="Medium Shading 1 Accent 6" w:uiPriority="63"/>
+                    <w:lsdException w:name="Medium Shading 2 Accent 6" w:uiPriority="64"/>
+                    <w:lsdException w:name="Medium List 1 Accent 6" w:uiPriority="65"/>
+                    <w:lsdException w:name="Medium List 2 Accent 6" w:uiPriority="66"/>
+                    <w:lsdException w:name="Medium Grid 1 Accent 6" w:uiPriority="67"/>
+                    <w:lsdException w:name="Medium Grid 2 Accent 6" w:uiPriority="68"/>
+                    <w:lsdException w:name="Medium Grid 3 Accent 6" w:uiPriority="69"/>
+                    <w:lsdException w:name="Dark List Accent 6" w:uiPriority="70"/>
+                    <w:lsdException w:name="Colorful Shading Accent 6" w:uiPriority="71"/>
+                    <w:lsdException w:name="Colorful List Accent 6" w:uiPriority="72"/>
+                    <w:lsdException w:name="Colorful Grid Accent 6" w:uiPriority="73"/>
+                    <w:lsdException w:name="Subtle Emphasis" w:uiPriority="19" w:qFormat="1"/>
+                    <w:lsdException w:name="Intense Emphasis" w:uiPriority="21" w:qFormat="1"/>
+                    <w:lsdException w:name="Subtle Reference" w:uiPriority="31" w:qFormat="1"/>
+                    <w:lsdException w:name="Intense Reference" w:uiPriority="32" w:qFormat="1"/>
+                    <w:lsdException w:name="Book Title" w:uiPriority="33" w:qFormat="1"/>
+                    <w:lsdException w:name="Bibliography" w:semiHidden="1" w:uiPriority="37" w:unhideWhenUsed="1"/>
+                    <w:lsdException w:name="TOC Heading" w:semiHidden="1" w:uiPriority="39" w:unhideWhenUsed="1" w:qFormat="1"/>
+                </w:latentStyles>
+                <w:style w:type="paragraph" w:default="1" w:styleId="a">
+                    <w:name w:val="Normal"/>
+                    <w:qFormat/>
+                    <w:rsid w:val="00097880"/>
+                    <w:pPr>
+                        <w:widowControl w:val="0"/>
+                        <w:jc w:val="both"/>
+                    </w:pPr>
+                    <w:rPr>
+                        <w:kern w:val="2"/>
+                        <w:sz w:val="21"/>
+                        <w:szCs w:val="24"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="character" w:default="1" w:styleId="a0">
+                    <w:name w:val="Default Paragraph Font"/>
+                    <w:uiPriority w:val="1"/>
+                    <w:semiHidden/>
+                    <w:unhideWhenUsed/>
+                </w:style>
+                <w:style w:type="table" w:default="1" w:styleId="a1">
+                    <w:name w:val="Normal Table"/>
+                    <w:uiPriority w:val="99"/>
+                    <w:semiHidden/>
+                    <w:unhideWhenUsed/>
+                    <w:tblPr>
+                        <w:tblInd w:w="0" w:type="dxa"/>
+                        <w:tblCellMar>
+                            <w:top w:w="0" w:type="dxa"/>
+                            <w:left w:w="108" w:type="dxa"/>
+                            <w:bottom w:w="0" w:type="dxa"/>
+                            <w:right w:w="108" w:type="dxa"/>
+                        </w:tblCellMar>
+                    </w:tblPr>
+                </w:style>
+                <w:style w:type="numbering" w:default="1" w:styleId="a2">
+                    <w:name w:val="No List"/>
+                    <w:uiPriority w:val="99"/>
+                    <w:semiHidden/>
+                    <w:unhideWhenUsed/>
+                </w:style>
+                <w:style w:type="paragraph" w:styleId="a3">
+                    <w:name w:val="header"/>
+                    <w:basedOn w:val="a"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:pPr>
+                        <w:pBdr>
+                            <w:bottom w:val="single" w:sz="6" w:space="1" w:color="auto"/>
+                        </w:pBdr>
+                        <w:tabs>
+                            <w:tab w:val="center" w:pos="4153"/>
+                            <w:tab w:val="right" w:pos="8306"/>
+                        </w:tabs>
+                        <w:snapToGrid w:val="0"/>
+                        <w:jc w:val="center"/>
+                    </w:pPr>
+                    <w:rPr>
+                        <w:sz w:val="18"/>
+                        <w:szCs w:val="18"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="paragraph" w:styleId="a4">
+                    <w:name w:val="footer"/>
+                    <w:basedOn w:val="a"/>
+                    <w:link w:val="a5"/>
+                    <w:uiPriority w:val="99"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:pPr>
+                        <w:tabs>
+                            <w:tab w:val="center" w:pos="4153"/>
+                            <w:tab w:val="right" w:pos="8306"/>
+                        </w:tabs>
+                        <w:snapToGrid w:val="0"/>
+                        <w:jc w:val="left"/>
+                    </w:pPr>
+                    <w:rPr>
+                        <w:sz w:val="18"/>
+                        <w:szCs w:val="18"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="paragraph" w:styleId="a6">
+                    <w:name w:val="Plain Text"/>
+                    <w:basedOn w:val="a"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:rPr>
+                        <w:rFonts w:ascii="宋体" w:hAnsi="Courier New" w:cs="Courier New"/>
+                        <w:szCs w:val="21"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="paragraph" w:customStyle="1" w:styleId="MSMincho">
+                    <w:name w:val="MS Mincho"/>
+                    <w:basedOn w:val="a"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:rPr>
+                        <w:rFonts w:ascii="MS Mincho" w:eastAsia="MS Mincho" w:hAnsi="MS Mincho"/>
+                        <w:sz w:val="24"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="paragraph" w:customStyle="1" w:styleId="1">
+                    <w:name w:val="1"/>
+                    <w:basedOn w:val="a"/>
+                    <w:rsid w:val="00097880"/>
+                    <w:pPr>
+                        <w:widowControl/>
+                        <w:jc w:val="left"/>
+                    </w:pPr>
+                    <w:rPr>
+                        <w:noProof/>
+                        <w:kern w:val="0"/>
+                        <w:sz w:val="24"/>
+                        <w:lang w:eastAsia="de-DE"/>
+                    </w:rPr>
+                </w:style>
+                <w:style w:type="character" w:customStyle="1" w:styleId="a5">
+                    <w:name w:val="页脚字符"/>
+                    <w:basedOn w:val="a0"/>
+                    <w:link w:val="a4"/>
+                    <w:uiPriority w:val="99"/>
+                    <w:rsid w:val="00070B9E"/>
+                    <w:rPr>
+                        <w:kern w:val="2"/>
+                        <w:sz w:val="18"/>
+                        <w:szCs w:val="18"/>
+                    </w:rPr>
+                </w:style>
+            </w:styles>
+        </pkg:xmlData>
+    </pkg:part>
+    <pkg:part pkg:name="/docProps/app.xml" pkg:contentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" pkg:padding="256">
+        <pkg:xmlData>
+            <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
+                <Template>Normal.dotm</Template>
+                <TotalTime>4</TotalTime>
+                <Pages>1</Pages>
+                <Words>36</Words>
+                <Characters>210</Characters>
+                <Application>Microsoft Macintosh Word</Application>
+                <DocSecurity>0</DocSecurity>
+                <Lines>1</Lines>
+                <Paragraphs>1</Paragraphs>
+                <ScaleCrop>false</ScaleCrop>
+                <Company>Lenovo (Beijing) Limited</Company>
+                <LinksUpToDate>false</LinksUpToDate>
+            <CharactersWithSpaces>245</CharactersWithSpaces>
+            <SharedDoc>false</SharedDoc>
+            <HyperlinksChanged>false</HyperlinksChanged>
+            <AppVersion>14.0000</AppVersion>
+        </Properties>
+    </pkg:xmlData>
+</pkg:part>
+</pkg:package>

+ 0 - 11
cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/dao/GenPaperRepo.java

@@ -1,11 +0,0 @@
-package com.qmth.cqb.genpaper.dao;
-
-import com.qmth.cqb.genpaper.model.GenPaper;
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.data.repository.query.QueryByExampleExecutor;
-
-/**
- * Created by songyue on 16/12/28.
- */
-public interface GenPaperRepo extends MongoRepository<GenPaper,String>,QueryByExampleExecutor<GenPaper>{
-}

+ 0 - 128
cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/model/GenPaper.java

@@ -1,128 +0,0 @@
-package com.qmth.cqb.genpaper.model;
-
-import com.qmth.cqb.base.model.Course;
-import com.qmth.cqb.base.model.User;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * 生成试卷实体类
- * Created by songyue on 16/12/27.
- */
-public class GenPaper implements Serializable{
-    private static final long serialVersionUID = 423546337699869114L;
-
-    @Id
-    private String id;
-
-    private String paperNo;//试卷编号
-
-    private String paperName;//试卷名称
-
-    private String createTime;//创建时间
-
-    private String updateTime;//更新时间
-
-    private GenPaperRule genPaperRule;//组卷规则
-
-    private List<GenPaperResource> genPaperResource;//试卷资源库(试卷、答案、网评卷)
-
-    @DBRef
-    private List<GenPaperDetail> genPaperDetails;//试卷明细
-
-    @DBRef
-    private Course course;//课程信息
-
-    @DBRef
-    private User user;//用户信息
-
-    public static long getSerialVersionUID() {
-        return serialVersionUID;
-    }
-
-    public String getId() {
-        return id;
-    }
-
-    public void setId(String id) {
-        this.id = id;
-    }
-
-    public String getPaperNo() {
-        return paperNo;
-    }
-
-    public void setPaperNo(String paperNo) {
-        this.paperNo = paperNo;
-    }
-
-    public String getPaperName() {
-        return paperName;
-    }
-
-    public void setPaperName(String paperName) {
-        this.paperName = paperName;
-    }
-
-    public GenPaperRule getGenPaperRule() {
-        return genPaperRule;
-    }
-
-    public void setGenPaperRule(GenPaperRule genPaperRule) {
-        this.genPaperRule = genPaperRule;
-    }
-
-    public List<GenPaperDetail> getGenPaperDetails() {
-        return genPaperDetails;
-    }
-
-    public void setGenPaperDetails(List<GenPaperDetail> genPaperDetails) {
-        this.genPaperDetails = genPaperDetails;
-    }
-
-    public Course getCourse() {
-        return course;
-    }
-
-    public void setCourse(Course course) {
-        this.course = course;
-    }
-
-    public User getUser() {
-        return user;
-    }
-
-    public void setUser(User user) {
-        this.user = user;
-    }
-
-    public String getCreateTime() {
-        return createTime;
-    }
-
-    public void setCreateTime(String createTime) {
-        this.createTime = createTime;
-    }
-
-    public String getUpdateTime() {
-        return updateTime;
-    }
-
-    public void setUpdateTime(String updateTime) {
-        this.updateTime = updateTime;
-    }
-
-    public List<GenPaperResource> getGenPaperResource() {
-        return genPaperResource;
-    }
-
-    public void setGenPaperResource(List<GenPaperResource> genPaperResource) {
-        this.genPaperResource = genPaperResource;
-    }
-
-    public GenPaper() {
-    }
-}

+ 0 - 73
cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/model/GenPaperDetail.java

@@ -1,73 +0,0 @@
-package com.qmth.cqb.genpaper.model;
-
-import com.qmth.cqb.question.model.Question;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-
-import java.io.Serializable;
-
-/**
- * 试卷明细类,记录试题的题组信息
- * Created by songyue on 16/12/27.
- */
-public class GenPaperDetail implements Serializable{
-    private static final long serialVersionUID = -8132174228626243138L;
-    @Id
-    private String id;
-
-    private String mainNo;//大题号
-
-    private String subNo;//小题号
-
-    private int sort;//排序
-
-    @DBRef
-    private Question question;//关联试题
-
-    public static long getSerialVersionUID() {
-        return serialVersionUID;
-    }
-
-    public String getId() {
-        return id;
-    }
-
-    public void setId(String id) {
-        this.id = id;
-    }
-
-    public String getMainNo() {
-        return mainNo;
-    }
-
-    public void setMainNo(String mainNo) {
-        this.mainNo = mainNo;
-    }
-
-    public String getSubNo() {
-        return subNo;
-    }
-
-    public void setSubNo(String subNo) {
-        this.subNo = subNo;
-    }
-
-    public int getSort() {
-        return sort;
-    }
-
-    public void setSort(int sort) {
-        this.sort = sort;
-    }
-
-    public Question getQuestion() {
-        return question;
-    }
-
-    public void setQuestion(Question question) {
-        this.question = question;
-    }
-
-    public GenPaperDetail() {
-    }
-}

+ 0 - 79
cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/model/GenPaperResource.java

@@ -1,79 +0,0 @@
-package com.qmth.cqb.genpaper.model;
-
-import org.bson.types.ObjectId;
-
-import java.io.Serializable;
-
-/**
- * Created by songyue on 16/12/28.
- */
-public class GenPaperResource implements Serializable{
-    private static final long serialVersionUID = -8009449548977861957L;
-
-    private String resourceNo;//资源编号
-
-    private String resourceType;//资源类型(试卷、答案、网评卷等)
-
-    private String fileType;//文件类型(word、html)
-
-    private int sort;//排序
-
-    private ObjectId fileId;//GridFs中存储地址
-
-    private byte[] resourseData;
-
-    public String getResourceNo() {
-        return resourceNo;
-    }
-
-    public void setResourceNo(String resourceNo) {
-        this.resourceNo = resourceNo;
-    }
-
-    public String getResourceType() {
-        return resourceType;
-    }
-
-    public void setResourceType(String resourceType) {
-        this.resourceType = resourceType;
-    }
-
-    public String getFileType() {
-        return fileType;
-    }
-
-    public void setFileType(String fileType) {
-        this.fileType = fileType;
-    }
-
-    public int getSort() {
-        return sort;
-    }
-
-    public void setSort(int sort) {
-        this.sort = sort;
-    }
-
-    public ObjectId getFileId() {
-        return fileId;
-    }
-
-    public void setFileId(ObjectId fileId) {
-        this.fileId = fileId;
-    }
-
-    public static long getSerialVersionUID() {
-        return serialVersionUID;
-    }
-
-    public byte[] getResourseData() {
-        return resourseData;
-    }
-
-    public void setResourseData(byte[] resourseData) {
-        this.resourseData = resourseData;
-    }
-
-    public GenPaperResource() {
-    }
-}

+ 0 - 53
cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/model/GenPaperRule.java

@@ -1,53 +0,0 @@
-package com.qmth.cqb.genpaper.model;
-
-
-import com.qmth.cqb.question.model.Question;
-import java.util.List;
-
-import java.io.Serializable;
-import java.util.Map;
-
-/**
- * 组卷规则类
- * Created by songyue on 16/12/27.
- */
-public class GenPaperRule implements Serializable{
-    private static final long serialVersionUID = 6015250738786576931L;
-
-    private String ruleName;//规则名称
-
-    private List<Question> choseQuestions;//选择试题集合
-
-    private Map params;//组卷动态规则
-
-    public static long getSerialVersionUID() {
-        return serialVersionUID;
-    }
-
-    public String getRuleName() {
-        return ruleName;
-    }
-
-    public void setRuleName(String ruleName) {
-        this.ruleName = ruleName;
-    }
-
-    public List<Question> getChoseQuestions() {
-        return choseQuestions;
-    }
-
-    public void setChoseQuestions(List<Question> choseQuestions) {
-        this.choseQuestions = choseQuestions;
-    }
-
-    public Map getParams() {
-        return params;
-    }
-
-    public void setParams(Map params) {
-        this.params = params;
-    }
-
-    public GenPaperRule() {
-    }
-}

+ 0 - 17
cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/service/GenPaperService.java

@@ -1,17 +0,0 @@
-package com.qmth.cqb.genpaper.service;
-
-import com.qmth.cqb.genpaper.dao.GenPaperRepo;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-/**
- * Created by songyue on 16/12/28.
- */
-@Service
-public class GenPaperService {
-    @Autowired
-    GenPaperRepo genPaperRepo;
-    
-    
-    
-}

+ 1 - 7
cqb-gen-paper/src/main/java/com/qmth/cqb/genpaper/web/GenPaperController.java

@@ -1,7 +1,5 @@
 package com.qmth.cqb.genpaper.web;
 
-import com.qmth.cqb.genpaper.dao.GenPaperRepo;
-import com.qmth.cqb.genpaper.service.GenPaperService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
@@ -10,9 +8,5 @@ import org.springframework.stereotype.Controller;
  */
 @Controller
 public class GenPaperController {
-    @Autowired
-    GenPaperService genPaperService;
-
-    @Autowired
-    GenPaperRepo genPaperRepo;
+   
 }

+ 3 - 1
cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperDetailRepo.java

@@ -1,9 +1,11 @@
 package com.qmth.cqb.paper.dao;
 
+import com.qmth.cqb.paper.model.Paper;
 import org.springframework.data.mongodb.repository.MongoRepository;
 import org.springframework.data.repository.query.QueryByExampleExecutor;
 import com.qmth.cqb.paper.model.PaperDetail;
+import java.util.List;
 
 public interface PaperDetailRepo extends MongoRepository<PaperDetail, String>,QueryByExampleExecutor<PaperDetail> {
-	//PaperDetail findByNumber(int number);
+	List<PaperDetail> findByPaper(Paper paper);
 }

+ 0 - 12
cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperDetailStructureRepo.java

@@ -1,12 +0,0 @@
-package com.qmth.cqb.paper.dao;
-
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.data.repository.query.QueryByExampleExecutor;
-
-import com.qmth.cqb.paper.model.PaperDetailStructure;
-import com.qmth.cqb.paper.model.PaperDetailUnit;
-
-
-public interface PaperDetailStructureRepo extends MongoRepository<PaperDetailStructure, String>,QueryByExampleExecutor<PaperDetailStructure> {
-	//PaperDetailStructure findByNumber(int number);
-}

+ 6 - 1
cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperDetailUnitRepo.java

@@ -1,11 +1,16 @@
 package com.qmth.cqb.paper.dao;
 
+import com.qmth.cqb.paper.model.Paper;
+import com.qmth.cqb.paper.model.PaperDetail;
 import org.springframework.data.mongodb.repository.MongoRepository;
 import org.springframework.data.repository.query.QueryByExampleExecutor;
 
 import com.qmth.cqb.paper.model.PaperDetailUnit;
 
+import java.util.List;
+
 
 public interface PaperDetailUnitRepo extends MongoRepository<PaperDetailUnit, String>,QueryByExampleExecutor<PaperDetailUnit> {
-	
+    List<PaperDetailUnit> findByPaperDetail(PaperDetail paperDetail);
+    List<PaperDetailUnit> findByPaper(Paper paper);
 }

+ 9 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperStructDetailRepo.java

@@ -0,0 +1,9 @@
+package com.qmth.cqb.paper.dao;
+
+import com.qmth.cqb.paper.model.PaperStructDetail;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.repository.query.QueryByExampleExecutor;
+
+
+public interface PaperStructDetailRepo extends MongoRepository<PaperStructDetail, String>,QueryByExampleExecutor<PaperStructDetail> {
+}

+ 10 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperStructRepo.java

@@ -0,0 +1,10 @@
+package com.qmth.cqb.paper.dao;
+
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.repository.query.QueryByExampleExecutor;
+
+import com.qmth.cqb.paper.model.PaperStruct;
+
+public interface PaperStructRepo extends MongoRepository<PaperStruct, String>,QueryByExampleExecutor<PaperStruct> {
+	
+}

+ 0 - 12
cqb-paper/src/main/java/com/qmth/cqb/paper/dao/PaperStructureRepo.java

@@ -1,12 +0,0 @@
-package com.qmth.cqb.paper.dao;
-
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.data.repository.query.QueryByExampleExecutor;
-
-import com.qmth.cqb.paper.model.Paper;
-import com.qmth.cqb.paper.model.PaperDetailStructure;
-import com.qmth.cqb.paper.model.PaperStructure;
-
-public interface PaperStructureRepo extends MongoRepository<PaperStructure, String>,QueryByExampleExecutor<PaperStructure> {
-	
-}

+ 87 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/dto/PaperDetailDto.java

@@ -0,0 +1,87 @@
+package com.qmth.cqb.paper.dto;
+
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * Created by songyue on 17/3/15.
+ */
+public class PaperDetailDto implements Serializable {
+    private static final long serialVersionUID = -3520871668728091404L;
+
+    private String id;
+
+    private int number;//大题序号
+
+    private String cnNum;//中文序号
+
+    private String name;//大题名称
+
+    private double score;//大题分数
+
+    private int unitCount;//大题下的小题数量
+
+    private List<PaperDetailUnitDto> paperDetailUnits;
+
+    public static long getSerialVersionUID() {
+        return serialVersionUID;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public int getNumber() {
+        return number;
+    }
+
+    public void setNumber(int number) {
+        this.number = number;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public double getScore() {
+        return score;
+    }
+
+    public void setScore(double score) {
+        this.score = score;
+    }
+
+    public int getUnitCount() {
+        return unitCount;
+    }
+
+    public void setUnitCount(int unitCount) {
+        this.unitCount = unitCount;
+    }
+
+    public List<PaperDetailUnitDto> getPaperDetailUnits() {
+        return paperDetailUnits;
+    }
+
+    public String getCnNum() {
+        return cnNum;
+    }
+
+    public void setCnNum(String cnNum) {
+        this.cnNum = cnNum;
+    }
+
+    public void setPaperDetailUnits(List<PaperDetailUnitDto> paperDetailUnits) {
+        this.paperDetailUnits = paperDetailUnits;
+    }
+}
+

+ 67 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/dto/PaperDetailUnitDto.java

@@ -0,0 +1,67 @@
+package com.qmth.cqb.paper.dto;
+
+import com.qmth.cqb.question.model.Question;
+import com.qmth.cqb.question.model.QuestionType;
+
+import java.io.Serializable;
+
+/**
+ * Created by songyue on 17/3/15.
+ */
+public class PaperDetailUnitDto implements Serializable {
+    private static final long serialVersionUID = 6507445685386413261L;
+
+    private String id;
+
+    private int number;//小题序号
+
+    private double score;//小题分数
+
+    private QuestionType questionType;//小题类型
+
+    private Question question;//关联试题
+
+    public static long getSerialVersionUID() {
+        return serialVersionUID;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public int getNumber() {
+        return number;
+    }
+
+    public void setNumber(int number) {
+        this.number = number;
+    }
+
+    public double getScore() {
+        return score;
+    }
+
+    public void setScore(double score) {
+        this.score = score;
+    }
+
+    public QuestionType getQuestionType() {
+        return questionType;
+    }
+
+    public void setQuestionType(QuestionType questionType) {
+        this.questionType = questionType;
+    }
+
+    public Question getQuestion() {
+        return question;
+    }
+
+    public void setQuestion(Question question) {
+        this.question = question;
+    }
+}

+ 76 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/dto/PaperDto.java

@@ -0,0 +1,76 @@
+package com.qmth.cqb.paper.dto;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.*;
+
+/**
+ * Created by songyue on 17/3/15.
+ */
+public class PaperDto implements Serializable{
+    private static final long serialVersionUID = -4673013279766466337L;
+
+    private String id;
+
+    private String name;//试卷名称
+
+    private String title;//试卷标题
+
+    private double totalScore;//试卷总分
+
+    private List<PaperDetailDto> paperDetails;
+
+    private Map<String,String> params;//导入试卷属性
+
+    public static long getSerialVersionUID() {
+        return serialVersionUID;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public double getTotalScore() {
+        return totalScore;
+    }
+
+    public void setTotalScore(double totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    public List<PaperDetailDto> getPaperDetails() {
+        return paperDetails;
+    }
+
+    public void setPaperDetails(List<PaperDetailDto> paperDetails) {
+        this.paperDetails = paperDetails;
+    }
+
+    public Map<String, String> getParams() {
+        return params;
+    }
+
+    public void setParams(Map<String, String> params) {
+        this.params = params;
+    }
+}

+ 1 - 1
cqb-paper/src/main/java/com/qmth/cqb/paper/model/ExtractConfig.java

@@ -3,7 +3,7 @@ package com.qmth.cqb.paper.model;
 import java.io.Serializable;
 import java.util.Map;
 
-import com.qmth.cqb.utils.enumeration.ExtractPolicy;
+import com.qmth.cqb.utils.enums.ExtractPolicy;
 import org.springframework.data.annotation.Id;
 
 public class ExtractConfig implements Serializable{

+ 80 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/model/ImportPaperCheck.java

@@ -0,0 +1,80 @@
+package com.qmth.cqb.paper.model;
+
+/**
+ * Created by songyue on 17/3/12.
+ */
+public class ImportPaperCheck {
+    public String errorInfo;
+    public String quesGroup;
+    public String quesType;
+    public String quesName;
+    public String quesCount;
+    public String quesScore;
+    public int index;
+
+    public String getErrorInfo() {
+        return errorInfo;
+    }
+
+    public void setErrorInfo(String errorInfo) {
+        this.errorInfo = errorInfo;
+    }
+
+    public String getQuesGroup() {
+        return quesGroup;
+    }
+
+    public void setQuesGroup(String quesGroup) {
+        this.quesGroup = quesGroup;
+    }
+
+    public String getQuesType() {
+        return quesType;
+    }
+
+    public void setQuesType(String quesType) {
+        this.quesType = quesType;
+    }
+
+    public String getQuesName() {
+        return quesName;
+    }
+
+    public void setQuesName(String quesName) {
+        this.quesName = quesName;
+    }
+
+    public String getQuesCount() {
+        return quesCount;
+    }
+
+    public void setQuesCount(String quesCount) {
+        this.quesCount = quesCount;
+    }
+
+    public String getQuesScore() {
+        return quesScore;
+    }
+
+    public void setQuesScore(String quesScore) {
+        this.quesScore = quesScore;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    public ImportPaperCheck() {
+        this.errorInfo = "";
+        this.quesGroup = "";
+        this.quesType = "";
+        this.quesName = "";
+        this.quesCount = "";
+        this.quesScore = "";
+        this.index = 0;
+    }
+}

+ 90 - 110
cqb-paper/src/main/java/com/qmth/cqb/paper/model/Paper.java

@@ -3,6 +3,7 @@ package com.qmth.cqb.paper.model;
 import java.io.Serializable;
 import java.util.Map;
 
+import com.qmth.cqb.utils.CommonUtils;
 import org.springframework.data.annotation.Id;
 import org.springframework.data.mongodb.core.index.Indexed;
 
@@ -24,136 +25,115 @@ public class Paper implements Serializable {
     
     private Double totalScore;//试卷总分
     
+    private String creator;//创建人id
+
     private Integer paperDetailCount;//大题数量
-    
-    //private String corusecode;//课程代码
-    
-    //private String groupCode;//试卷类型
-    
-    private String creatorName;//创建人id
-     
+
     private String createTime;//创建时间
 
     private String lastModifyName;//最后修改人名称
-    
+
     private String word;//原始试卷word
 
     private String html;//原始试卷html
 
     private Map<String,String> params;//导入试卷属性
 
-	public String getId() {
-		return id;
-	}
+    public static long getSerialVersionUID() {
+        return serialVersionUID;
+    }
+
+    public String getId() {
+        return id;
+    }
 
-	public void setId(String id) {
-		this.id = id;
-	}
+    public void setId(String id) {
+        this.id = id;
+    }
 
-	public String getName() {
-		return name;
-	}
+    public String getName() {
+        return name;
+    }
 
-	public void setName(String name) {
-		this.name = name;
-	}
+    public void setName(String name) {
+        this.name = name;
+    }
 
-	public String getTitle() {
-		return title;
-	}
+    public String getTitle() {
+        return title;
+    }
 
-	public void setTitle(String title) {
-		this.title = title;
-	}
+    public void setTitle(String title) {
+        this.title = title;
+    }
 
-	public Double getTotalScore() {
-		return totalScore;
-	}
+    public Double getTotalScore() {
+        return totalScore;
+    }
 
-	public void setTotalScore(Double totalScore) {
-		this.totalScore = totalScore;
-	}
-	
+    public void setTotalScore(Double totalScore) {
+        this.totalScore = totalScore;
+    }
 
-	public Integer getPaperDetailCount() {
-		return paperDetailCount;
-	}
+    public Integer getPaperDetailCount() {
+        return paperDetailCount;
+    }
 
-	public void setPaperDetailCount(Integer paperDetailCount) {
-		this.paperDetailCount = paperDetailCount;
-	}
-	
-	
-	public String getCreatorName() {
-		return creatorName;
-	}
-
-	public void setCreatorName(String creatorName) {
-		this.creatorName = creatorName;
-	}
-
-	public String getCreateTime() {
-		return createTime;
-	}
-
-//	public String getCorusecode() {
-//		return corusecode;
-//	}
-//
-//	public void setCorusecode(String corusecode) {
-//		this.corusecode = corusecode;
-//	}
-	
-//	public String getGroupCode() {
-//		return groupCode;
-//	}
-//
-//	public void setGroupCode(String groupCode) {
-//		this.groupCode = groupCode;
-//	}
-
-	public void setCreateTime(String createTime) {
-		this.createTime = createTime;
-	}
-
-	public String getWord() {
-		return word;
-	}
-
-	public void setWord(String word) {
-		this.word = word;
-	}
-
-	public String getHtml() {
-		return html;
-	}
-
-	public void setHtml(String html) {
-		this.html = html;
-	}
-
-	public Map<String, String> getParams() {
-		return params;
-	}
-
-	public void setParams(Map<String, String> params) {
-		this.params = params;
-	}
-
-	public static long getSerialversionuid() {
-		return serialVersionUID;
-	}
-    
-	public String getLastModifyName() {
-		return lastModifyName;
-	}
+    public void setPaperDetailCount(Integer paperDetailCount) {
+        this.paperDetailCount = paperDetailCount;
+    }
 
-	public void setLastModifyName(String lastModifyName) {
-		this.lastModifyName = lastModifyName;
-	}
-	
-	public Paper() {
+    public String getCreateTime() {
+        return createTime;
     }
 
-    
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getLastModifyName() {
+        return lastModifyName;
+    }
+
+    public void setLastModifyName(String lastModifyName) {
+        this.lastModifyName = lastModifyName;
+    }
+
+    public String getWord() {
+        return word;
+    }
+
+    public void setWord(String word) {
+        this.word = word;
+    }
+
+    public String getHtml() {
+        return html;
+    }
+
+    public void setHtml(String html) {
+        this.html = html;
+    }
+
+    public Map<String, String> getParams() {
+        return params;
+    }
+
+    public void setParams(Map<String, String> params) {
+        this.params = params;
+    }
+
+    public String getCreator() {
+        return creator;
+    }
+
+    public void setCreator(String creator) {
+        this.creator = creator;
+    }
+
+    public Paper() {
+		this.createTime = CommonUtils.getCurDateTime();
+    }
+
+
 }

+ 28 - 8
cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperDetail.java

@@ -2,6 +2,7 @@ package com.qmth.cqb.paper.model;
 
 import java.io.Serializable;
 
+import java.util.List;
 import org.springframework.data.annotation.Id;
 import org.springframework.data.mongodb.core.mapping.DBRef;
 
@@ -13,21 +14,28 @@ public class PaperDetail implements Serializable {
 	
 	@Id
 	private String id;
-	
+
 	@DBRef
 	private Paper paper;//关联的试卷
 	
 	private Integer number;//大题序号
 	
 	private String name;//大题名称
-	
-	@DBRef
+
 	private QuestionType questionType;//大题类型
 	
 	private Double score;//大题分数
 	
 	private Integer unitCount;//大题下的小题数量
 
+	private String creator;//创建人id
+
+	private String createTime;//创建时间
+
+	public static long getSerialVersionUID() {
+		return serialVersionUID;
+	}
+
 	public String getId() {
 		return id;
 	}
@@ -60,11 +68,11 @@ public class PaperDetail implements Serializable {
 		this.name = name;
 	}
 
-	public QuestionType getQuesStructType() {
+	public QuestionType getQuestionType() {
 		return questionType;
 	}
 
-	public void setQuesStructType(QuestionType questionType) {
+	public void setQuestionType(QuestionType questionType) {
 		this.questionType = questionType;
 	}
 
@@ -84,10 +92,22 @@ public class PaperDetail implements Serializable {
 		this.unitCount = unitCount;
 	}
 
-	public static long getSerialversionuid() {
-		return serialVersionUID;
+	public String getCreator() {
+		return creator;
 	}
-	
+
+	public void setCreator(String creator) {
+		this.creator = creator;
+	}
+
+	public String getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(String createTime) {
+		this.createTime = createTime;
+	}
+
 	public PaperDetail(){
 		
 	}

+ 0 - 100
cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperDetailStructure.java

@@ -1,100 +0,0 @@
-package com.qmth.cqb.paper.model;
-
-import java.io.Serializable;
-
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-import com.qmth.cqb.utils.enumeration.QuesStructType;
-
-public class PaperDetailStructure implements Serializable{
-	
-	private static final long serialVersionUID = -1102384643351847702L;
-
-	@Id
-	private String id;
-	
-	@DBRef
-	private PaperStructure paperStructure;//关联的试卷
-	
-	private int number;//大题序号
-	
-	private String name;//大题名称
-	
-	private QuesStructType structType;//大题类型
-	
-	private double totalScore;//大题分数
-	
-	private int questionCount;//大题下的小题数量
-	
-	private double[] questionScores;//大题下面小题分数
-
-	public String getId() {
-		return id;
-	}
-
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	public int getNumber() {
-		return number;
-	}
-
-	public void setNumber(int number) {
-		this.number = number;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	public PaperStructure getPaperStructure() {
-		return paperStructure;
-	}
-
-	public void setPaperStructure(PaperStructure paperStructure) {
-		this.paperStructure = paperStructure;
-	}
-
-	public QuesStructType getStructType() {
-		return structType;
-	}
-
-	public void setStructType(QuesStructType structType) {
-		this.structType = structType;
-	}
-
-	public double getTotalScore() {
-		return totalScore;
-	}
-
-	public void setTotalScore(double totalScore) {
-		this.totalScore = totalScore;
-	}
-
-	public int getQuestionCount() {
-		return questionCount;
-	}
-
-	public void setQuestionCount(int questionCount) {
-		this.questionCount = questionCount;
-	}
-
-	public double[] getQuestionScores() {
-		return questionScores;
-	}
-
-	public void setQuestionScores(double[] questionScores) {
-		this.questionScores = questionScores;
-	}
-
-	public static long getSerialversionuid() {
-		return serialVersionUID;
-	}
-	
-	
-}

+ 24 - 18
cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperDetailUnit.java

@@ -24,12 +24,19 @@ public class PaperDetailUnit implements Serializable{
 	@DBRef
 	private PaperDetail paperDetail;//关联的大题
 	
-	@DBRef
 	private QuestionType questionType;//小题类型
 	
 	@DBRef
 	private Question question;//关联试题
 
+	private String creator;//创建人id
+
+	private String createTime;//创建时间
+
+	public static long getSerialVersionUID() {
+		return serialVersionUID;
+	}
+
 	public String getId() {
 		return id;
 	}
@@ -62,10 +69,6 @@ public class PaperDetailUnit implements Serializable{
 		this.score = score;
 	}
 
-	public static long getSerialVersionUID() {
-		return serialVersionUID;
-	}
-
 	public PaperDetail getPaperDetail() {
 		return paperDetail;
 	}
@@ -82,14 +85,6 @@ public class PaperDetailUnit implements Serializable{
 		this.questionType = questionType;
 	}
 
-	public QuestionType getQuesStructType() {
-		return questionType;
-	}
-
-	public void setQuesStructType(QuestionType questionType) {
-		this.questionType = questionType;
-	}
-
 	public Question getQuestion() {
 		return question;
 	}
@@ -98,11 +93,22 @@ public class PaperDetailUnit implements Serializable{
 		this.question = question;
 	}
 
-	public static long getSerialversionuid() {
-		return serialVersionUID;
+	public String getCreator() {
+		return creator;
 	}
-	
-	
-	
 
+	public void setCreator(String creator) {
+		this.creator = creator;
+	}
+
+	public String getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(String createTime) {
+		this.createTime = createTime;
+	}
+
+	public PaperDetailUnit() {
+	}
 }

+ 109 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperStruct.java

@@ -0,0 +1,109 @@
+package com.qmth.cqb.paper.model;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.List;
+
+import com.qmth.cqb.utils.CommonUtils;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+
+/**
+ * 试卷结构
+ * Created by songyue on 16/12/28.
+ */
+
+public class PaperStruct implements Serializable{
+
+	private static final long serialVersionUID = 6380530617488717881L;
+
+	@Id
+    private String id;
+
+    @Indexed(unique = true)
+    private String name;//试卷结构名称
+        
+    private Double totalScore;//总分
+    
+    private Integer detailCount;//大题数量
+    
+    private Map params;
+
+	private List<PaperStructDetail> paperStructDetails;//大题
+
+	private String creator;//创建人id
+
+	private String createTime;//创建时间
+
+	public static long getSerialVersionUID() {
+		return serialVersionUID;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Double getTotalScore() {
+		return totalScore;
+	}
+
+	public void setTotalScore(Double totalScore) {
+		this.totalScore = totalScore;
+	}
+
+	public Integer getDetailCount() {
+		return detailCount;
+	}
+
+	public void setDetailCount(Integer detailCount) {
+		this.detailCount = detailCount;
+	}
+
+	public Map getParams() {
+		return params;
+	}
+
+	public void setParams(Map params) {
+		this.params = params;
+	}
+
+	public List<PaperStructDetail> getPaperStructDetails() {
+		return paperStructDetails;
+	}
+
+	public void setPaperStructDetails(List<PaperStructDetail> paperStructDetails) {
+		this.paperStructDetails = paperStructDetails;
+	}
+
+	public String getCreator() {
+		return creator;
+	}
+
+	public void setCreator(String creator) {
+		this.creator = creator;
+	}
+
+	public String getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(String createTime) {
+		this.createTime = createTime;
+	}
+
+	public PaperStruct() {
+		this.createTime = CommonUtils.getCurDateTime();
+	}
+}

+ 104 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperStructDetail.java

@@ -0,0 +1,104 @@
+package com.qmth.cqb.paper.model;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.List;
+
+import com.qmth.cqb.base.model.QuesType;
+
+/**
+ * 试卷结构明细
+ * Created by songyue on 16/12/28.
+ */
+
+public class PaperStructDetail implements Serializable{
+	
+	private static final long serialVersionUID = -1102384643351847702L;
+
+	private String id;
+	
+	private Integer number;//大题序号
+	
+	private String name;//大题名称
+	
+	private List<QuesType> quesTypes;//大题类型
+	
+	private Double totalScore;//大题分数
+	
+	private Integer questionCount;//大题下的小题数量
+	
+	private Double[] questionScores;//大题下面小题分数
+
+	private Map params;//大题参数
+
+	public static long getSerialVersionUID() {
+		return serialVersionUID;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public Integer getNumber() {
+		return number;
+	}
+
+	public void setNumber(Integer number) {
+		this.number = number;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public List<QuesType> getQuesTypes() {
+		return quesTypes;
+	}
+
+	public void setQuesTypes(List<QuesType> quesTypes) {
+		this.quesTypes = quesTypes;
+	}
+
+	public Double getTotalScore() {
+		return totalScore;
+	}
+
+	public void setTotalScore(Double totalScore) {
+		this.totalScore = totalScore;
+	}
+
+	public Integer getQuestionCount() {
+		return questionCount;
+	}
+
+	public void setQuestionCount(Integer questionCount) {
+		this.questionCount = questionCount;
+	}
+
+	public Double[] getQuestionScores() {
+		return questionScores;
+	}
+
+	public void setQuestionScores(Double[] questionScores) {
+		this.questionScores = questionScores;
+	}
+
+	public Map getParams() {
+		return params;
+	}
+
+	public void setParams(Map params) {
+		this.params = params;
+	}
+
+	public PaperStructDetail() {
+	}
+}

+ 0 - 67
cqb-paper/src/main/java/com/qmth/cqb/paper/model/PaperStructure.java

@@ -1,67 +0,0 @@
-package com.qmth.cqb.paper.model;
-
-import java.io.Serializable;
-import java.util.Map;
-
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.index.Indexed;
-
-public class PaperStructure implements Serializable{
-
-	private static final long serialVersionUID = 6380530617488717881L;
-
-	@Id
-    private String id;
-
-    @Indexed(unique = true)
-    private String name;//试卷结构名称
-        
-    private double totalScore;//总分
-    
-    private int detailCount;//大题数量
-    
-    private Map paraMap;
-
-	public String getId() {
-		return id;
-	}
-
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	public double getTotalScore() {
-		return totalScore;
-	}
-
-	public void setTotalScore(double totalScore) {
-		this.totalScore = totalScore;
-	}
-
-	public int getDetailCount() {
-		return detailCount;
-	}
-
-	public void setDetailCount(int detailCount) {
-		this.detailCount = detailCount;
-	}
-
-	public Map getParaMap() {
-		return paraMap;
-	}
-
-	public void setParaMap(Map paraMap) {
-		this.paraMap = paraMap;
-	}
-    
-    
-    
-}

+ 177 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/service/ExportPaperService.java

@@ -0,0 +1,177 @@
+package com.qmth.cqb.paper.service;
+
+import com.google.gson.Gson;
+import com.qmth.cqb.paper.dao.PaperDetailRepo;
+import com.qmth.cqb.paper.dao.PaperDetailUnitRepo;
+import com.qmth.cqb.paper.dao.PaperRepo;
+import com.qmth.cqb.paper.dto.PaperDetailDto;
+import com.qmth.cqb.paper.dto.PaperDetailUnitDto;
+import com.qmth.cqb.paper.dto.PaperDto;
+import com.qmth.cqb.paper.model.Paper;
+import com.qmth.cqb.paper.model.PaperDetail;
+import com.qmth.cqb.paper.model.PaperDetailUnit;
+import com.qmth.cqb.question.dao.QuesRepo;
+import com.qmth.cqb.question.model.Question;
+import com.qmth.cqb.utils.BeanCopierUtil;
+import com.qmth.cqb.utils.CommonUtils;
+import com.qmth.cqb.utils.word.DocxProcessUtil;
+import org.docx4j.XmlUtils;
+import org.docx4j.jaxb.Context;
+import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
+import org.docx4j.wml.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Created by songyue on 17/3/15.
+ */
+@Service
+public class ExportPaperService {
+
+    @Autowired
+    PaperRepo paperRepo;
+
+    @Autowired
+    PaperDetailRepo paperDetailRepo;
+
+    @Autowired
+    PaperDetailUnitRepo paperDetailUnitRepo;
+
+    @Autowired
+    QuesRepo quesRepo;
+
+    @Autowired
+    Gson gson;
+
+    @Autowired
+    PaperDetailUnitService paperDetailUnitService;
+
+    /**
+     * 初始化导出试卷DTO
+     * @param id
+     * @return
+     */
+    public Map initExportPaper(String id)throws Exception{
+        //创建返回Map
+        Map returnMap = new HashMap();
+        //获取paper
+        Paper paper = paperRepo.findOne(id);
+        if(paper == null){
+            returnMap.put("errorInfo","该试卷不存在");
+            return returnMap;
+        }
+        //创建paperDto
+        PaperDto paperDto = BeanCopierUtil.copyProperties(paper,PaperDto.class);
+        //获取大题
+        List<PaperDetail> paperDetails = paperDetailRepo.findByPaper(paper);
+        List<PaperDetailDto> paperDetailDtos =
+                BeanCopierUtil.copyPropertiesOfList(paperDetails,PaperDetailDto.class);
+        paperDto.setPaperDetails(paperDetailDtos);
+
+        //封装小题
+        for(int i = 0;i < paperDetailDtos.size();i++){
+            List<PaperDetailUnit> paperDetailUnits =
+                    paperDetailUnitRepo.findByPaperDetail(paperDetails.get(i));
+            List<PaperDetailUnitDto> paperDetailUnitDtos =
+                    BeanCopierUtil.copyPropertiesOfList(paperDetailUnits,PaperDetailUnitDto.class);
+            paperDetailDtos.get(i).setPaperDetailUnits(paperDetailUnitDtos);
+        }
+        //初始化试卷序号
+        initPaperNum(paperDto);
+
+        returnMap.put("paper",paperDto);
+        returnMap.put("fileName",paperDto.getName());
+
+        return returnMap;
+    }
+
+    /**
+     * 导出试卷
+     * @param id
+     */
+    public String exportPaper(String id) throws Exception {
+        Map dataMap = initExportPaper(id);
+        if(dataMap.get("errorInfo")!=null){
+            return (String)dataMap.get("errorInfo");
+        }
+        String fileName = (String)dataMap.get("fileName");
+        DocxProcessUtil.exportPaper(dataMap,fileName);
+        DocxProcessUtil.processImage(fileName,getPkgList(id));
+        return "success";
+    }
+
+    /**
+     * 初始化序号
+     * @param paperDto
+     */
+    public void initPaperNum(PaperDto paperDto)throws Exception{
+        if(paperDto.getPaperDetails() == null || paperDto.getPaperDetails().size() == 0){
+            return;
+        }
+        int mainNum = 0;
+        int subNum = 0;
+        for(PaperDetailDto paperDetail:paperDto.getPaperDetails()){
+            //大题序号
+            paperDetail.setCnNum(CommonUtils.toCHNum(paperDetail.getNumber()));
+            paperDetail.setNumber(++mainNum);
+            if(paperDetail.getPaperDetailUnits() == null ||
+                    paperDetail.getPaperDetailUnits().size() == 0){
+                return;
+            }
+            //小题序号
+            for(PaperDetailUnitDto paperDetailUnit:paperDetail.getPaperDetailUnits()){
+                List<Question> subQuesList = paperDetailUnit.getQuestion().getSubQuestions();
+                //套题序号
+                if(subQuesList != null && subQuesList.size() > 0){
+                    for(Question subQues:subQuesList){
+                        subQues.setQuesBodyWord(setSubQuesNum(subQues.getQuesBodyWord(),++subNum));
+                    }
+                }else{
+                    Question question = paperDetailUnit.getQuestion();
+                    question.setQuesBodyWord(setSubQuesNum(question.getQuesBodyWord(),++subNum));
+                }
+            }
+        }
+    }
+
+    /**
+     * 获取当前试卷下所有试题WordPkg
+     * @param id
+     * @return
+     */
+    public List<WordprocessingMLPackage> getPkgList(String id){
+        Paper paper = paperRepo.findOne(id);
+        List<WordprocessingMLPackage> wordMLPackages = paperDetailUnitRepo.findByPaper(paper)
+                .stream().map(PaperDetailUnit::getQuestion).collect(Collectors.toList())
+                .stream().map(Question::getQuesPkgObj).collect(Collectors.toList());
+        return wordMLPackages;
+    }
+
+    /**
+     * 设置题号
+     * @param quesBodyWordMl
+     * @param num
+     * @return
+     * @throws Exception
+     */
+    public String setSubQuesNum(String quesBodyWordMl,int num) throws Exception {
+        String tmpStr = DocxProcessUtil.BODY_HEADER +quesBodyWordMl+DocxProcessUtil.BODY_TAIL;
+        Body body = (Body)XmlUtils.unmarshalString(tmpStr,
+                Context.jc,Body.class);
+        P p = (P)body.getContent().get(0);
+        List<Object> pContent = p.getContent();
+        R run = new R();
+        Text text = new Text();
+        text.setValue(num+". ");
+        run.getContent().add(text);
+        pContent.add(0,run);
+        return DocxProcessUtil.formatPWordMl(XmlUtils.marshaltoString(p));
+    }
+
+
+}

+ 751 - 50
cqb-paper/src/main/java/com/qmth/cqb/paper/service/ImportPaperService.java

@@ -2,45 +2,60 @@ package com.qmth.cqb.paper.service;
 
 import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.startsWith;
 
+import com.google.gson.Gson;
+import com.qmth.cqb.paper.dao.PaperDetailRepo;
+import com.qmth.cqb.paper.dao.PaperDetailUnitRepo;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import com.qmth.cqb.paper.dao.PaperRepo;
+import com.qmth.cqb.paper.model.*;
+import com.qmth.cqb.question.dao.QuesRepo;
+import com.qmth.cqb.question.model.QuesOption;
+import com.qmth.cqb.question.model.Question;
+import com.qmth.cqb.question.model.QuestionType;
+import com.qmth.cqb.utils.CommonUtils;
+import com.qmth.cqb.utils.enums.QuesStructType;
+import com.qmth.cqb.utils.enums.QuesUnit;
+import com.qmth.cqb.utils.modal.PagingAndSortingResponse;
+import com.qmth.cqb.utils.word.DocxProcessUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
+import org.docx4j.wml.P;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Example;
 import org.springframework.data.domain.ExampleMatcher;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
-import org.springframework.data.mongodb.core.MongoTemplate;
 import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
 
-import com.qmth.cqb.paper.model.Paper;
-import com.qmth.cqb.paper.model.ImportPaperSearchCondition;
-import com.qmth.cqb.utils.modal.PagingAndSortingResponse;
+import java.io.*;
 
 @Service
 public class ImportPaperService {
 
+    @Autowired
+    PaperRepo paperRepo;
 
-    /**
-     * 一般返回类型统一为NormalResponse对象
-     * NormalResponse(String httpStatus, String Message)
-     * 分页集合返回类型为PagingAndSortingResponse
-     * PagingAndSortingResponse(int curPage, int pageSize, int totalPages, long totalElements, List dataList)
-     * 一般集合返回类型为List
-     */
+    @Autowired
+    PaperDetailRepo paperDetailRepo;
 
     @Autowired
-    PaperRepo paperRepo;
+    PaperDetailUnitRepo paperDetailUnitRepo;
+
+    @Autowired
+    QuesRepo quesRepo;
+
+    @Autowired
+    Gson gson;
 
     @Autowired
     PaperDetailService paperDetailService;
 
-    
+
     /**
      * 查询所有已导入试卷
      * @param searchCondition
@@ -48,22 +63,19 @@ public class ImportPaperService {
      * @param pageSize
      * @return
      */
-    public PagingAndSortingResponse<Paper> findAll(ImportPaperSearchCondition searchCondition,int curPage,int pageSize){
+    public Page<Paper> findAll(ImportPaperSearchCondition searchCondition,
+                               int curPage,
+                               int pageSize){
     	Paper importPaper = new Paper();
     	BeanUtils.copyProperties(searchCondition,importPaper);
-    	if(searchCondition.getCourseId() != null){
-        	Map<String,String> param = new HashMap<String,String>();
-        	param.put("courseId", searchCondition.getCourseId());
-        	importPaper.setParams(param);
-    	}
-        Page<Paper> importPaperList = paperRepo.findAll(Example.of(importPaper),new PageRequest(curPage-1,pageSize));
-        return new PagingAndSortingResponse<Paper>(importPaperList.getNumber(),importPaperList.getSize(),
-                importPaperList.getTotalPages(),importPaperList.getTotalElements(),importPaperList.getContent());
+    	ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("paperName", startsWith());
+        return paperRepo.findAll(Example.of(importPaper,matcher),
+                new PageRequest(curPage - 1,pageSize));
     }
 
     /**
      * 查询所有已导入试卷
-     * @param searchCondition
+     * @param courseId
      * @param curPage
      * @param pageSize
      * @return
@@ -79,45 +91,734 @@ public class ImportPaperService {
         return importPaperList;
     }
 
-    
+
     /**
-     * 按ID查询导入试卷
-     * @param paperId
+     * 导入试卷
+     * @param inputStream
      * @return
      */
-    public Paper findById(String paperId){
-        return paperRepo.findOne(paperId);
+    public String ImportPaper(InputStream inputStream){
+        String errorInfo = processImportPaper(inputStream);
+        if(StringUtils.isEmpty(errorInfo)){
+            return "success";
+        }else{
+            return errorInfo;
+        }
+    }
+
+    /**
+     * 保存导入试卷信息
+     * @param paper
+     * @param paperDetails
+     * @param paperDetailUnits
+     * @param importPaperCheck
+     */
+    public void savePaper(Paper paper,
+                          List paperDetails,
+                          List paperDetailUnits,
+                          List questions,
+                          ImportPaperCheck importPaperCheck){
+
+        if(!StringUtils.isEmpty(importPaperCheck.errorInfo)) return;
+
+        if(paper != null){
+            paperRepo.save(paper);
+        }
+
+        if(paperDetails.size() > 0){
+            paperDetailRepo.save(paperDetails);
+        }
+
+        if(questions.size() > 0){
+            quesRepo.save(questions);
+        }
+
+        if(paperDetailUnits.size() > 0){
+            paperDetailUnitRepo.save(paperDetailUnits);
+        }
+
+    }
+
+    /**
+     * 处理导入试卷
+     * @param inputStream
+     */
+    public String processImportPaper(InputStream inputStream){
+
+        WordprocessingMLPackage wordMLPackage;
+        WordprocessingMLPackage tmpWordMlPackage;
+        WordprocessingMLPackage writePkg;
+        ImportPaperCheck importPaperCheck = new ImportPaperCheck();
+
+        try{
+            wordMLPackage = WordprocessingMLPackage.load(inputStream);
+            //初始化图片路径
+            DocxProcessUtil.initPkgImage(wordMLPackage);
+            //深拷贝临时pkg与最终写入pkg
+            tmpWordMlPackage = DocxProcessUtil.getTmpPackage(wordMLPackage);
+            writePkg = DocxProcessUtil.getTmpPackage(wordMLPackage);
+
+            //获取word文档中所有段落
+            List<Object> pList = DocxProcessUtil.getAllElementFromObject(
+                    wordMLPackage.getMainDocumentPart(), P.class);
+
+            //创建试卷类
+            Paper paper = new Paper();
+
+            //创建空大题类
+            PaperDetail paperDetail = null;
+
+            //创建大题集合
+            List<PaperDetail> paperDetails = new ArrayList<PaperDetail>();
+
+            //创建小题集合
+            List<PaperDetailUnit> paperDetailUnits = new ArrayList<PaperDetailUnit>();
+
+            //创建试题集合
+            List<Question> questions = new ArrayList<Question>();
+
+            //大题号
+            int mainQuesNum = 0;
+
+            //小题号
+            int subQuesNum = 0;
+
+            for (int i = 0;i < pList.size();i++) {
+                P p=(P) pList.get(i);
+                String pText = DocxProcessUtil.getPText(p);
+
+                //获取大题头信息
+                if(pText.startsWith("[试题分类]")){
+
+                    //处理大题头信息
+                    processMainQuesHeader(pList,importPaperCheck.index,importPaperCheck);
+
+                    //校验大题头信息
+                    if(!checkQuesHeader(importPaperCheck)){
+                        return importPaperCheck.errorInfo;
+                    }
+
+                    //创建大题类
+                    paperDetail = new PaperDetail();
+
+                    //设置大题类
+                    initQuesHeader(paper,
+                                   paperDetail,
+                                   paperDetails,
+                                   ++mainQuesNum,
+                                   importPaperCheck);
+
+                }else if(pText.matches("^\\d{1,}\\.[\\s\\S]*")
+                        || (isNested(importPaperCheck) && !pText.startsWith("["))){
+                    //处理试题
+
+                    //创建小题类和试题类
+                    PaperDetailUnit paperDetailUnit = new PaperDetailUnit();
+                    Question question = new Question();
+
+                    //初始化小题类和试题类
+                    initPaperDetail(paper,
+                                    paperDetail,
+                                    paperDetailUnit,
+                                    question,
+                                    ++subQuesNum,
+                                    importPaperCheck);
+
+                    //处理客观题
+                    if(importPaperCheck.quesType.equals("单选")
+                            || importPaperCheck.quesType.equals("多选")){
+
+                        //处理题干
+                        processQuesBody(pList,
+                                        importPaperCheck.index,
+                                        question,
+                                        importPaperCheck,
+                                        tmpWordMlPackage
+                        );
+
+                        //处理选项
+                        processQuesOption(pList,
+                                          importPaperCheck.index,
+                                          subQuesNum,
+                                          question,
+                                          importPaperCheck,
+                                          tmpWordMlPackage);
+                        //处理尾信息
+                        processQuesTail(pList,
+                                        importPaperCheck.index,
+                                        subQuesNum,
+                                        question,
+                                        paperDetailUnit,
+                                        importPaperCheck,
+                                        tmpWordMlPackage,
+                                        false);
+
+                    }else if(importPaperCheck.quesType.equals("套题")){
+                        //处理套题
+                        processNestedQues(pList,
+                                          importPaperCheck.index,
+                                          question,
+                                          paperDetailUnit,
+                                          importPaperCheck,
+                                          tmpWordMlPackage);
+                    }else{
+                        //处理其他题型
+                        processQuesBody(pList,
+                                        importPaperCheck.index,
+                                        question,
+                                        importPaperCheck,
+                                        tmpWordMlPackage
+                        );
+
+                        processQuesTail(pList,
+                                        importPaperCheck.index,
+                                        subQuesNum,
+                                        question,
+                                        paperDetailUnit,
+                                        importPaperCheck,
+                                        tmpWordMlPackage,
+                                        false);
+                    }
+                    //设置WordMlPackage二进制数据
+                    setPkgByte(question,writePkg);
+
+                    //设置question与Unit集合数据
+                    questions.add(question);
+                    paperDetailUnits.add(paperDetailUnit);
+
+                    //设置当前索引,防止多余循环
+                    i = importPaperCheck.index - 1;
+                }
+                if(!StringUtils.isEmpty(importPaperCheck.errorInfo)){
+                    return importPaperCheck.errorInfo;
+                }
+            }
+
+            //保存导入试卷信息
+            savePaper(paper,
+                      paperDetails,
+                      paperDetailUnits,
+                      questions,
+                      importPaperCheck);
+
+        }catch (Exception e){
+            e.printStackTrace();
+            importPaperCheck.setErrorInfo(e.getMessage());
+        }
+        wordMLPackage = null;
+        tmpWordMlPackage = null;
+        return importPaperCheck.errorInfo;
+    }
+
+    /**
+     * 初始化大题头信息
+     * @param paper
+     * @param paperDetail
+     * @param paperDetails
+     * @param mainQuesNum
+     * @param importPaperCheck
+     */
+    public void initQuesHeader(Paper paper,
+                               PaperDetail paperDetail,
+                               List<PaperDetail> paperDetails,
+                               int mainQuesNum,
+                               ImportPaperCheck importPaperCheck){
+
+        paperDetail.setPaper(paper);
+
+        //设置试卷
+        paper.setTitle(importPaperCheck.quesGroup);
+        paper.setName(importPaperCheck.quesGroup);
+        Map paramMap = new HashMap();
+        paramMap.put("courseNo",getCourseNo(importPaperCheck));
+        paramMap.put("courseName",getCourseName(importPaperCheck));
+        paper.setParams(paramMap);
+
+        //设置大题信息
+        paperDetail.setName(importPaperCheck.quesName);
+        paperDetail.setUnitCount(Integer.parseInt(importPaperCheck.quesCount));
+        paperDetail.setNumber(mainQuesNum);
+
+        paperDetails.add(paperDetail);
+
     }
 
     /**
-     * 保存试卷
-     * @param importPaper
+     * 初始化试卷明细和试题
+     * @param paperDetail
+     * @param paperDetailUnit
+     * @param question
+     * @param subQuesNum
+     * @param importPaperCheck
+     */
+    public void initPaperDetail(Paper paper,
+                                PaperDetail paperDetail,
+                                PaperDetailUnit paperDetailUnit,
+                                Question question,
+                                int subQuesNum,
+                                ImportPaperCheck importPaperCheck){
+
+        question.setQuestionType(getQuesType(importPaperCheck.quesType));
+        paperDetailUnit.setNumber(++subQuesNum);
+        paperDetailUnit.setQuestion(question);
+        paperDetailUnit.setPaperDetail(paperDetail);
+        paperDetailUnit.setQuestionType(getQuesType(importPaperCheck.quesType));
+        paperDetailUnit.setScore(Double.parseDouble(importPaperCheck.quesScore));
+        paperDetailUnit.setPaper(paper);
+    }
+
+    /**
+     * 校验试题头标识
+     * @param importPaperCheck
      * @return
      */
-    public Paper saveImportPaper(Paper importPaper){
-    	Paper tempPaper = paperRepo.save(importPaper);
-        return tempPaper;
+    public boolean checkQuesHeader(ImportPaperCheck importPaperCheck){
+
+        String tmpErrorInfo = "";
+        if(StringUtils.isEmpty(importPaperCheck.quesGroup)){
+            tmpErrorInfo += "试题分类为空或格式不正确";
+
+        }else if(StringUtils.isEmpty(importPaperCheck.quesType)){
+            tmpErrorInfo += "题型为空或格式不正确";
+
+        }else if(StringUtils.isEmpty(importPaperCheck.quesName)){
+            tmpErrorInfo += "大题名称为空或格式不正确";
+
+        }else if(StringUtils.isEmpty(importPaperCheck.quesCount)){
+            tmpErrorInfo += "题目数量为空或格式不正确";
+
+        }else if(StringUtils.isEmpty(importPaperCheck.quesScore)){
+            tmpErrorInfo += "分数为空或格式不正确";
+
+        }
+        if(!StringUtils.isEmpty(importPaperCheck.quesType)
+                && !CommonUtils.checkQuesType(importPaperCheck.quesType)){
+            tmpErrorInfo += "题型必须是单选、多选、判断、填空、问答、套题中的一种";
+        }
+        if(StringUtils.isEmpty(tmpErrorInfo)){
+            return true;
+        }else{
+            importPaperCheck.setErrorInfo(tmpErrorInfo);
+            return false;
+        }
+    }
+
+    /**
+     * 处理大题头信息
+     * @param pList
+     * @param index
+     * @param importPaperCheck
+     */
+    public void processMainQuesHeader(List pList,
+                                      int index,
+                                      ImportPaperCheck importPaperCheck){
+
+        int i = 0;
+
+        for(i = index;i < pList.size();i++){
+            P pHeader = (P)pList.get(i);
+            String tmpText = DocxProcessUtil.getPText(pHeader);
+            if(tmpText.startsWith("[试题分类]")){
+
+                importPaperCheck.setQuesGroup(tmpText.replaceAll("\\[试题分类\\]","")
+                        .replaceAll("[:|:]","").trim());
+
+            }else if(tmpText.startsWith("[题型]")){
+
+                importPaperCheck.setQuesType(tmpText.replaceAll("\\[题型\\]","")
+                        .replaceAll("[:|:]","").trim());
+
+            }else if(tmpText.startsWith("[大题名称]")){
+
+                importPaperCheck.setQuesName(tmpText.replaceAll("\\[大题名称\\]","")
+                        .replaceAll("[:|:]","").trim());
+
+            }else if(tmpText.startsWith("[题目数量]")){
+
+                importPaperCheck.setQuesCount(tmpText.replaceAll("\\[题目数量\\]","")
+                        .replaceAll("[:|:]","").trim());
+
+            }else if(tmpText.startsWith("[分数]")){
+
+                importPaperCheck.setQuesScore(tmpText.replaceAll("\\[分数\\]","")
+                        .replaceAll("[:|:]","").trim());
+
+            }else if(StringUtils.isEmpty(tmpText)){
+                continue;
+            }else{
+                break;
+            }
+        }
+        importPaperCheck.setIndex(i);
+    }
+
+    /**
+     * 处理题干信息
+     * @param pList
+     * @param index
+     * @param question
+     * @param importPaperCheck
+     * @param wordMLPackage
+     * @throws Exception
+     */
+    public void processQuesBody(List pList,
+                                int index,
+                                Question question,
+                                ImportPaperCheck importPaperCheck,
+                                WordprocessingMLPackage wordMLPackage)throws Exception{
+        //定义题干wordml和html
+        String quesBodyWordMl = "";
+        String quesBodyHtml = "";
+        int i = 0;
+
+        for(i = index;i < pList.size();i++){
+            P pBody = (P)pList.get(i);
+            String tmpText = DocxProcessUtil.getPText(pBody);
+
+            //判断是否为题干
+            if(StringUtils.isEmpty(tmpText)){
+                continue;
+            }else if(tmpText.matches("^\\d{1,}\\.[\\s\\S]*")
+                    || (!tmpText.matches("^[a-zA-Z]\\.[\\s\\S]*")
+                    && !tmpText.startsWith("["))){
+                //过滤题干标题
+                pBody = DocxProcessUtil.formatP(pBody, QuesUnit.QUES_BODY);
+
+                String tmpWordMl = DocxProcessUtil.getPWordMl(pBody);
+                String tmpHtml = DocxProcessUtil.docx2Html(tmpWordMl,wordMLPackage);
+                quesBodyWordMl += DocxProcessUtil.formatPWordMl(tmpWordMl);
+                quesBodyHtml += tmpHtml;
+            }else{
+                break;
+            }
+        }
+        importPaperCheck.setIndex(i);
+        question.setQuesBody(quesBodyHtml);
+        question.setQuesBodyWord(quesBodyWordMl);
     }
 
     /**
-     * 批量删除导入试卷
-     * @param paperId
+     * 处理题目选项
+     * @param paperIds
      * @return
+     * @throws Exception
      */
-    public void deleteImportPaper(String[] paperIds){
-    	//需要同时删除paperDetail,paperdetailUnit
-    	Iterable<Paper> papers = new ArrayList<Paper>();
+    public void deleteImportPaper(String[] paperIds) {
+        //需要同时删除paperDetail,paperdetailUnit
+        Iterable<Paper> papers = new ArrayList<Paper>();
         List<String> ids = new ArrayList<String>();
-    	for(int i=0;i<paperIds.length;i++){
-    		ids.add(paperIds[i]);
-    	}
-    	papers = paperRepo.findAll(ids);
-    	for(Paper paper:papers){
-    		paperDetailService.deletePaperDetailsByPaper(paper);
-    	}   
-    	paperRepo.delete(papers);
-    	
-    }
-    
+        for (int i = 0; i < paperIds.length; i++) {
+            ids.add(paperIds[i]);
+        }
+        papers = paperRepo.findAll(ids);
+        for (Paper paper : papers) {
+            paperDetailService.deletePaperDetailsByPaper(paper);
+        }
+        paperRepo.delete(papers);
+    }
+
+    public String processQuesOption(List pList,
+                                    int index,
+                                    int subQuesNum,
+                                    Question question,
+                                    ImportPaperCheck importPaperCheck,
+                                    WordprocessingMLPackage wordMLPackage)throws Exception{
+
+        //定义试题选项wordml和html
+        String quesOptionWordMl = "";
+        String quesOptionHtml = "";
+        //定义选项集合
+        List<QuesOption> quesOptions = new ArrayList<QuesOption>();
+        //定义选项数量
+        int optionCount = 0;
+
+        int i = 0;
+
+        for(i = index;i < pList.size();i++){
+            P pOption = (P)pList.get(i);
+            String tmpText = DocxProcessUtil.getPText(pOption);
+
+            if(StringUtils.isEmpty(tmpText)){
+                continue;
+            }else if(tmpText.matches("^[a-zA-Z]\\.[\\s\\S]*")){//判断是否为选项
+
+                quesOptionWordMl = DocxProcessUtil.getPWordMl(pOption);
+                quesOptionHtml = DocxProcessUtil.docx2Html(quesOptionWordMl,wordMLPackage);
+                //创建试题选项
+                QuesOption quesOption = new QuesOption();
+                quesOption.setOptionBody(quesOptionHtml);
+                quesOption.setOptionBodyWord(DocxProcessUtil.formatPWordMl(quesOptionWordMl));
+                quesOption.setNumber(tmpText.substring(0,1));
+                quesOptions.add(quesOption);
+                optionCount++;
+            }else{
+                break;
+            }
+        }
+        importPaperCheck.setIndex(i);
+        if(optionCount < 2){
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck.quesName,
+                    subQuesNum) +"中选项格式不正确或有缺失,如没有缺失可尝试换行处理");
+        }else{
+            question.setQuesOptions(quesOptions);
+        }
+        return importPaperCheck.errorInfo;
+    }
+
+    /**
+     * 处理小题尾信息
+     * @param pList
+     * @param index
+     * @param subQuesNum
+     * @param question
+     * @param paperDetailUnit
+     * @param importPaperCheck
+     */
+    public void processQuesTail(List pList,
+                                int index,
+                                int subQuesNum,
+                                Question question,
+                                PaperDetailUnit paperDetailUnit,
+                                ImportPaperCheck importPaperCheck,
+                                WordprocessingMLPackage wordMLPackage,
+                                boolean isNested)throws Exception{
+
+        String quesAnwserWordMl = "";
+        String quesAnwserHtml = "";
+        String quesScore = "";
+        Map<String,String> quesParams = new HashMap<String,String>();
+        int i = 0;
+
+        for(i = index;i < pList.size();i++){
+            P pAnswer = (P)pList.get(i);
+            String tmpText = DocxProcessUtil.getPText(pAnswer);
+            if(StringUtils.isEmpty(tmpText)){
+                continue;
+            }else if(tmpText.startsWith("[答案]")){
+                pAnswer = DocxProcessUtil.formatP(pAnswer,QuesUnit.QUES_ANSWER);
+                quesAnwserWordMl = DocxProcessUtil.getPWordMl(pAnswer);
+                quesAnwserHtml = DocxProcessUtil.docx2Html(quesAnwserWordMl,wordMLPackage);
+
+            }else if(tmpText.startsWith("[小题分数]")){
+                quesScore = tmpText.replaceAll("\\[小题分数\\]","").replaceAll("[:|:]","").trim();
+            }else{
+                break;
+            }
+        }
+        importPaperCheck.setIndex(i);
+        //校验答案
+        if(!StringUtils.isEmpty(quesAnwserHtml)){
+            question.setQuesAnswer(quesAnwserHtml);
+            question.setQuesAnswerWord(
+                    DocxProcessUtil.formatPWordMl(quesAnwserWordMl));
+        }else{
+            importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck.quesName,
+                    subQuesNum) +"答案为空或格式不正确");
+        }
+
+        //设置小题分数
+        quesParams.put("小题分数",quesScore);
+        question.setQuesParams(quesParams);
+
+        //一般大题明细需要设置分数
+        if(!isNested && !StringUtils.isEmpty(quesScore)){
+            paperDetailUnit.setScore(Double.parseDouble(quesScore));
+        }
+    }
+
+    /**
+     * 处理套题
+     * @param pList
+     * @param index
+     * @param question
+     * @param paperDetailUnit
+     * @param importPaperCheck
+     * @throws Exception
+     */
+    public void processNestedQues(List pList,
+                                  int index,
+                                  Question question,
+                                  PaperDetailUnit paperDetailUnit,
+                                  ImportPaperCheck importPaperCheck,
+                                  WordprocessingMLPackage wordMLPackage)throws Exception{
+        //题型
+        String nestedQuesType = "";
+
+        //设置套题题干
+        processQuesBody(pList,index,question,importPaperCheck,wordMLPackage);
+
+        //创建小题集合
+        List<Question> subQuesList = new ArrayList<Question>();
+
+        int beginNum = importPaperCheck.index;
+
+        int subQuesNum = 0;
+        for(int i = beginNum;i < pList.size();i++){
+            P pSubQues = (P)pList.get(i);
+            String tmpText = DocxProcessUtil.getPText(pSubQues);
+
+            if(StringUtils.isEmpty(tmpText)){
+                continue;
+            }if(tmpText.startsWith("[小题型]")){
+
+                nestedQuesType = tmpText.replaceAll("\\[小题型\\]","").replaceAll("[:|:]","").trim();
+                importPaperCheck.index++;
+
+            }else if(tmpText.matches("^\\d\\.[\\s\\S]*")){
+
+                ++subQuesNum;
+
+                if(StringUtils.isEmpty(nestedQuesType)){
+                    importPaperCheck.setErrorInfo(getQuesNumInfo(importPaperCheck.quesName
+                            ,subQuesNum)+ "小题型为空或格式不正确");
+                    return;
+                }
+
+                Question subQues = new Question();
+
+                //处理客观题
+                if(nestedQuesType.equals("单选") || nestedQuesType.equals("多选")){
+
+                    //处理题干
+                    processQuesBody(pList,
+                                    importPaperCheck.index,
+                                    subQues,
+                                    importPaperCheck,
+                                    wordMLPackage
+                    );
+
+                    //处理选项
+                    processQuesOption(pList,
+                                      importPaperCheck.index,
+                                      subQuesNum,
+                                      subQues,
+                                      importPaperCheck,
+                                      wordMLPackage);
+
+                    //处理尾信息
+                    processQuesTail(pList,
+                                    importPaperCheck.index,
+                                    subQuesNum,
+                                    subQues,
+                                    paperDetailUnit,
+                                    importPaperCheck,
+                                    wordMLPackage,
+                                    true);
+
+                }else{
+                    //处理其他题型
+                    processQuesBody(pList,
+                                    importPaperCheck.index,
+                                    subQues,
+                                    importPaperCheck,
+                                    wordMLPackage
+                    );
+
+                    processQuesTail(pList,
+                                    importPaperCheck.index,
+                                    subQuesNum,
+                                    subQues,
+                                    paperDetailUnit,
+                                    importPaperCheck,
+                                    wordMLPackage,
+                                    true);
+                }
+                subQuesList.add(subQues);
+                i = importPaperCheck.index - 1;
+            }else{
+                break;
+            }
+            if(!StringUtils.isEmpty(importPaperCheck.errorInfo)){
+                return;
+            }
+        }
+        question.setSubQuestions(subQuesList);
+    }
+
+
+    /**
+     * 获取试题类型
+     * @param quesType
+     * @return
+     */
+    public static QuestionType getQuesType(String quesType){
+        return getQuesType(quesType,"");
+    }
+
+    /**
+     * 获取试题类型
+     * @param quesType
+     * @param quesName
+     * @return
+     */
+    public static QuestionType getQuesType(String quesType,String quesName){
+        QuesStructType quesStructType = CommonUtils.getEnum(QuesStructType.class,quesType);
+        return new QuestionType(quesStructType,quesName);
+    }
+
+
+
+    /**
+     * 获取当前试题大题小题号
+     * @param quesType
+     * @param subQuesNum
+     * @return
+     */
+    public static String getQuesNumInfo(String quesType,int subQuesNum){
+        return quesType+"第"+subQuesNum+"小题";
+    }
+
+    /**
+     * 判断是否为套题
+     * @param importPaperCheck
+     * @return
+     */
+    public static boolean isNested(ImportPaperCheck importPaperCheck){
+        if(importPaperCheck.getQuesType().equals("套题")){
+            return true;
+        }else{
+            return false;
+        }
+    }
+
+    /**
+     * 获取课程代码
+     * @param importPaperCheck
+     * @return
+     */
+    public static String getCourseNo(ImportPaperCheck importPaperCheck){
+        String [] courseInfo = importPaperCheck.quesGroup.split("_");
+        if(courseInfo.length == 2){
+            return courseInfo[1];
+        }else{
+            return "";
+        }
+    }
+
+    /**
+     * 获取课程名称
+     * @param importPaperCheck
+     * @return
+     */
+    public static String getCourseName(ImportPaperCheck importPaperCheck){
+        String [] courseInfo = importPaperCheck.quesGroup.split("_");
+        if(courseInfo.length == 2){
+            return courseInfo[0];
+        }else{
+            return "";
+        }
+    }
+
+    /**
+     * 设置wordMLPackage对象二进制数据
+     * @param question
+     * @param wordMLPackage
+     * @throws Exception
+     */
+    public static void setPkgByte(Question question,
+                                  WordprocessingMLPackage wordMLPackage)throws Exception{
+        question.setQuesPkg(DocxProcessUtil.getPkgByte(wordMLPackage));
+    }
+
 
 }

+ 1 - 1
cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperDetailService.java

@@ -63,7 +63,7 @@ public class PaperDetailService {
     
     /**
      * 查询同一个试卷对象对应大题
-     * @param paperDetail
+     * @param paper
      * @return
      */
     public List<PaperDetail> getPaperDetailsByPaper(Paper paper){

+ 0 - 63
cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperDetailStructureService.java

@@ -1,63 +0,0 @@
-package com.qmth.cqb.paper.service;
-
-import java.util.List;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Example;
-import org.springframework.stereotype.Service;
-import com.qmth.cqb.paper.dao.PaperDetailStructureRepo;
-import com.qmth.cqb.paper.model.PaperDetailStructure;
-import com.qmth.cqb.paper.model.PaperStructure;
-/**
- * Created by songyue on 16/12/28.
- */
-@Service
-public class PaperDetailStructureService {
-	
-	@Autowired
-	PaperDetailStructureRepo detailStructureRepo;
-	
-	
-
-    /**
-     * 按ID查询试卷结构明细
-     * @param detailId
-     * @return
-     */
-    public PaperDetailStructure findById(String detailId){
-        return detailStructureRepo.findOne(detailId);
-    }
-    
-    
-
-    /**
-     * 保存试卷结构明细
-     * @param PaperDetailStructure
-     * @return
-     */
-    public PaperDetailStructure savePaperStructureDetail(PaperDetailStructure pds){
-    	PaperDetailStructure temp = detailStructureRepo.save(pds);
-        return temp;
-    }
-
-    /**
-     * 删除试卷结构明细
-     * @param detailId
-     * @return
-     */
-    public void deletePaperDetailStructure(String detailId){
-    	detailStructureRepo.delete(detailId);
-    }
-
-    /**
-     * 查询同一个试卷对象对应试卷结构明细
-     * @param paperDetail
-     * @return
-     */
-    public List<PaperDetailStructure> getDetailsByPaperStructure(PaperStructure paperStructure){
-    	PaperDetailStructure pd = new PaperDetailStructure();
-    	pd.setPaperStructure(paperStructure);  	
-    	List<PaperDetailStructure> paperDetails = detailStructureRepo.findAll(Example.of(pd));
-    	return paperDetails;
-    }
-}

+ 5 - 3
cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperDetailUnitService.java

@@ -4,6 +4,7 @@ package com.qmth.cqb.paper.service;
 import java.util.ArrayList;
 import java.util.List;
 
+import com.qmth.cqb.question.dao.QuesRepo;
 import com.qmth.cqb.question.model.Question;
 import com.qmth.cqb.question.service.QuesService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -22,15 +23,16 @@ public class PaperDetailUnitService {
 	@Autowired
 	QuesService quesService;
 
+	@Autowired
+	QuesRepo quesRepo;
+
 	/**
 	 * 根据Id获得对应的试题对象
 	 * @param id
 	 * @return
 	 */
 	public Question getQuestionByPaperDetailUnitId(String id){
-		PaperDetailUnit pdu = paperDetailUnitRepo.findOne(id);
-		Question ques = quesService.findById(pdu.getId());
-		return ques;
+		return paperDetailUnitRepo.findOne(id).getQuestion();
 	}
 
     /**

+ 63 - 0
cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperStructDetailService.java

@@ -0,0 +1,63 @@
+package com.qmth.cqb.paper.service;
+
+import java.util.List;
+
+import com.qmth.cqb.paper.dao.PaperStructRepo;
+import com.qmth.cqb.paper.model.PaperStructDetail;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.qmth.cqb.paper.dao.PaperStructDetailRepo;
+import com.qmth.cqb.paper.model.PaperStruct;
+/**
+ * Created by songyue on 16/12/28.
+ */
+@Service
+public class PaperStructDetailService {
+	
+	@Autowired
+    PaperStructDetailRepo detailStructureRepo;
+
+    @Autowired
+    PaperStructRepo paperStructRepo;
+	
+	
+
+    /**
+     * 按ID查询试卷结构明细
+     * @param detailId
+     * @return
+     */
+    public PaperStructDetail findById(String detailId){
+        return detailStructureRepo.findOne(detailId);
+    }
+    
+    
+
+    /**
+     * 保存试卷结构明细
+     * @param pds
+     * @return
+     */
+    public PaperStructDetail savePaperStructureDetail(PaperStructDetail pds){
+    	PaperStructDetail temp = detailStructureRepo.save(pds);
+        return temp;
+    }
+
+    /**
+     * 删除试卷结构明细
+     * @param detailId
+     * @return
+     */
+    public void deletePaperDetailStructure(String detailId){
+    	detailStructureRepo.delete(detailId);
+    }
+
+    /**
+     * 查询同一个试卷对象对应试卷结构明细
+     * @param paperStruct
+     * @return
+     */
+    public List<PaperStructDetail> getDetailsByPaperStructure(PaperStruct paperStruct){
+    	return paperStructRepo.findOne(paperStruct.getId()).getPaperStructDetails();
+    }
+}

+ 9 - 9
cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperStructureService.java → cqb-paper/src/main/java/com/qmth/cqb/paper/service/PaperStructService.java

@@ -4,17 +4,17 @@ package com.qmth.cqb.paper.service;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import com.qmth.cqb.paper.dao.PaperStructureRepo;
-import com.qmth.cqb.paper.model.PaperStructure;
+import com.qmth.cqb.paper.dao.PaperStructRepo;
+import com.qmth.cqb.paper.model.PaperStruct;
 
 /**
  * Created by songyue on 16/12/28.
  */
 @Service
-public class PaperStructureService {
+public class PaperStructService {
 	
 	@Autowired
-	PaperStructureRepo paperStructureRepo;
+    PaperStructRepo paperStructRepo;
 	
 
     /**
@@ -22,8 +22,8 @@ public class PaperStructureService {
      * @param paperId
      * @return
      */
-    public PaperStructure findById(String paperId){
-        return paperStructureRepo.findOne(paperId);
+    public PaperStruct findById(String paperId){
+        return paperStructRepo.findOne(paperId);
     }
 
     /**
@@ -31,8 +31,8 @@ public class PaperStructureService {
      * @param importPaper
      * @return
      */
-    public PaperStructure savePaperStructure(PaperStructure ps){
-    	PaperStructure tempPaper = paperStructureRepo.save(ps);
+    public PaperStruct savePaperStructure(PaperStruct ps){
+    	PaperStruct tempPaper = paperStructRepo.save(ps);
         return tempPaper;
     }
 
@@ -42,7 +42,7 @@ public class PaperStructureService {
      * @return
      */
     public void deletePaperStructure(String paperId){
-    	paperStructureRepo.delete(paperId);
+    	paperStructRepo.delete(paperId);
     }
 	
 

+ 24 - 34
cqb-paper/src/main/java/com/qmth/cqb/paper/web/ImportPaperController.java

@@ -1,5 +1,6 @@
 package com.qmth.cqb.paper.web;
 
+import com.qmth.cqb.paper.dao.PaperRepo;
 import com.qmth.cqb.paper.model.ImportPaperSearchCondition;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
@@ -26,37 +27,32 @@ public class ImportPaperController {
 	
 	@Autowired
 	ImportPaperService importPaperService;
+
+    @Autowired
+    PaperRepo paperRepo;
+
     /**
      * 获取导入试卷
-     * @param importPaper_id
+     * @param id
      * @return
      */
-    @GetMapping(value = "/importPaper/{importPaper_id}")
-    public Paper getPaperById(@PathVariable String importPaper_id){
-        return importPaperService.findById(importPaper_id);
+    @GetMapping(value = "/importPaper/{id}")
+    public ResponseEntity getPaperById(@PathVariable String id){
+        return new ResponseEntity(paperRepo.findOne(id),HttpStatus.OK);
     }
-    
-    /**
-     * 获取导入试卷的所有试题
-     * @param importPaper_id
-     * @return
-     */
-//    @GetMapping(value = "/importPaper/question/{importPaper_id}")
-//    public List<Question> getQuesPaperById(@PathVariable String importPaper_id){
-//    	return importPaperService.findById(importPaper_id).getQuestionList();
-//    }
-
 
     /**
      * 获取全部导入试卷
      * @return
      */
-    @GetMapping(value = "/importPaper/all/{curPage}/{pageSize}")
-    public PagingAndSortingResponse<Paper> getAllPaper(@ModelAttribute ImportPaperSearchCondition searchCondition, @PathVariable int curPage, @PathVariable int pageSize){
-      PagingAndSortingResponse<Paper> psr = importPaperService.findAll(searchCondition, curPage, pageSize);
-      return psr;
+    @GetMapping(value = "/importPaper/{curPage}/{paseSize}")
+    public ResponseEntity getAllPaper(@ModelAttribute ImportPaperSearchCondition searchCondition,                                            @PathVariable int curPage,
+                                      @PathVariable int pageSize){
+
+      return new ResponseEntity(importPaperService.findAll(searchCondition,curPage,pageSize),
+              HttpStatus.OK);
     }
-    
+
     /**
      * 获取全部导入试卷
      * @return
@@ -64,7 +60,7 @@ public class ImportPaperController {
     @GetMapping(value = "/importPaper/{courseId}/{curPage}/{pageSize}")
     public ResponseEntity getImportPapersByCourseId(
     		                              @PathVariable String courseId,
-    		                              @PathVariable int curPage, 
+    		                              @PathVariable int curPage,
     		                              @PathVariable int pageSize
     		                              ){
       ResponseEntity rse = new ResponseEntity(importPaperService.getImportPapersByCourseId(courseId,curPage, pageSize),HttpStatus.OK);
@@ -79,10 +75,7 @@ public class ImportPaperController {
      */
     @PutMapping(value = "/importPaper")
     public ResponseEntity updatePaper(@ModelAttribute Paper paper){
-    	Paper paper2 = importPaperService.saveImportPaper(paper);
-    	ResponseEntity rse = new ResponseEntity(paper2,HttpStatus.OK);
-    	return rse;
-    	
+    	return new ResponseEntity(paperRepo.save(paper),HttpStatus.OK);
     }
 
     /**
@@ -92,20 +85,17 @@ public class ImportPaperController {
      */
     @PostMapping(value = "/importPaper")
     public ResponseEntity addPaper(@ModelAttribute Paper paper){
-    	Paper paper2 = importPaperService.saveImportPaper(paper);
-    	ResponseEntity rse = new ResponseEntity(paper2,HttpStatus.OK);
-    	return rse;
+    	return new ResponseEntity(paperRepo.save(paper),HttpStatus.OK);
     }
 
     /**
      * 删除导入试卷
-     * @param importPaper_id
+     * @param id
      * @return
      */
-    @DeleteMapping(value = "/importPaper/{importPaper_id}")
-    public ResponseEntity removePaper(@PathVariable String[] importPaper_id){
-    	importPaperService.deleteImportPaper(importPaper_id);
-    	ResponseEntity res = new ResponseEntity(importPaper_id,HttpStatus.OK);
-		return res;
+    @DeleteMapping(value = "/importPaper/{id}")
+    public ResponseEntity removePaper(@PathVariable String id){
+    	paperRepo.delete(id);
+		return new ResponseEntity(HttpStatus.OK);
     }
 }

+ 92 - 92
cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperStructureController.java → cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperStructController.java

@@ -1,92 +1,92 @@
-package com.qmth.cqb.paper.web;
-
-import java.util.List;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.qmth.cqb.paper.model.PaperDetailStructure;
-import com.qmth.cqb.paper.model.PaperStructure;
-import com.qmth.cqb.paper.service.PaperDetailStructureService;
-import com.qmth.cqb.paper.service.PaperStructureService;
-
-/**
- * Created by songyue on 16/12/28.
- */
-@RestController
-@RequestMapping("${api_cqb}/")
-public class PaperStructureController {
-	
-	@Autowired
-    PaperStructureService paperStructureService;
-	
-	@Autowired
-    PaperDetailStructureService detailService;
-	
-    /**
-     * 根据id获取试卷结构
-     * @param 
-     * @return
-     */
-    @GetMapping(value = "/paperStructure/{paper_id}")
-    public PaperStructure getPaperStructureById(@PathVariable String paper_id){
-        return paperStructureService.findById(paper_id);
-    }
-    
-    /**
-     * 获取试卷结构下面的详情信息
-     * @param paper_id
-     * @return
-     */
-    @GetMapping(value = "/paperStructure/detail/{paper_id}")
-    public List<PaperDetailStructure> getQuesPaperById(@PathVariable String paper_id){
-    	return detailService.getDetailsByPaperStructure(paperStructureService.findById(paper_id));
-    }
-
-
-    /**
-     * 更新导入试卷信息
-     * @param 
-     * @return
-     */
-    @PutMapping(value = "/paperStructure")
-    public ResponseEntity updatePaperStructure(@ModelAttribute PaperStructure ps){
-    	PaperStructure temp = paperStructureService.savePaperStructure(ps);
-    	ResponseEntity rse = new ResponseEntity(temp,HttpStatus.OK);
-    	return rse;
-    	
-    }
-
-    /**
-     * 新增导入试卷
-     * @param paper
-     * @return
-     */
-    @PostMapping(value = "/paperStructure")
-    public ResponseEntity addPaperStructure(@ModelAttribute PaperStructure ps){
-    	PaperStructure temp = paperStructureService.savePaperStructure(ps);
-    	ResponseEntity rse = new ResponseEntity(temp,HttpStatus.OK);
-    	return rse;
-    }
-
-    /**
-     * 删除导入试卷
-     * @param paper_id
-     * @return
-     */
-    @DeleteMapping(value = "/paperStructure/{paper_id}")
-    public ResponseEntity removePaperStructure(@PathVariable String paper_id){
-    	paperStructureService.deletePaperStructure(paper_id);
-    	ResponseEntity res = new ResponseEntity(paper_id,HttpStatus.OK);
-		return res;
-    }
-}
+package com.qmth.cqb.paper.web;
+
+import java.util.List;
+
+import com.qmth.cqb.paper.model.PaperStructDetail;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.qmth.cqb.paper.model.PaperStruct;
+import com.qmth.cqb.paper.service.PaperStructDetailService;
+import com.qmth.cqb.paper.service.PaperStructService;
+
+/**
+ * Created by songyue on 16/12/28.
+ */
+@RestController
+@RequestMapping("${api_cqb}/")
+public class PaperStructController {
+	
+	@Autowired
+    PaperStructService paperStructService;
+	
+	@Autowired
+    PaperStructDetailService detailService;
+	
+    /**
+     * 根据id获取试卷结构
+     * @param 
+     * @return
+     */
+    @GetMapping(value = "/paperStructure/{paper_id}")
+    public PaperStruct getPaperStructureById(@PathVariable String paper_id){
+        return paperStructService.findById(paper_id);
+    }
+    
+    /**
+     * 获取试卷结构下面的详情信息
+     * @param paper_id
+     * @return
+     */
+    @GetMapping(value = "/paperStructure/detail/{paper_id}")
+    public List<PaperStructDetail> getQuesPaperById(@PathVariable String paper_id){
+    	return detailService.getDetailsByPaperStructure(paperStructService.findById(paper_id));
+    }
+
+
+    /**
+     * 更新导入试卷信息
+     * @param 
+     * @return
+     */
+    @PutMapping(value = "/paperStructure")
+    public ResponseEntity updatePaperStructure(@ModelAttribute PaperStruct ps){
+    	PaperStruct temp = paperStructService.savePaperStructure(ps);
+    	ResponseEntity rse = new ResponseEntity(temp,HttpStatus.OK);
+    	return rse;
+    	
+    }
+
+    /**
+     * 新增导入试卷
+     * @param paper
+     * @return
+     */
+    @PostMapping(value = "/paperStructure")
+    public ResponseEntity addPaperStructure(@ModelAttribute PaperStruct ps){
+    	PaperStruct temp = paperStructService.savePaperStructure(ps);
+    	ResponseEntity rse = new ResponseEntity(temp,HttpStatus.OK);
+    	return rse;
+    }
+
+    /**
+     * 删除导入试卷
+     * @param paper_id
+     * @return
+     */
+    @DeleteMapping(value = "/paperStructure/{paper_id}")
+    public ResponseEntity removePaperStructure(@PathVariable String paper_id){
+    	paperStructService.deletePaperStructure(paper_id);
+    	ResponseEntity res = new ResponseEntity(paper_id,HttpStatus.OK);
+		return res;
+    }
+}

+ 10 - 10
cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperDetailStructureController.java → cqb-paper/src/main/java/com/qmth/cqb/paper/web/PaperStructDetailController.java

@@ -1,7 +1,7 @@
 package com.qmth.cqb.paper.web;
 
-import com.qmth.cqb.paper.model.PaperDetailStructure;
-import com.qmth.cqb.paper.service.PaperDetailStructureService;
+import com.qmth.cqb.paper.model.PaperStructDetail;
+import com.qmth.cqb.paper.service.PaperStructDetailService;
 
 import io.swagger.annotations.ApiOperation;
 
@@ -22,9 +22,9 @@ import org.springframework.web.bind.annotation.RestController;
  */
 @RestController
 @RequestMapping("${api_cqb}/")
-public class PaperDetailStructureController {
+public class PaperStructDetailController {
 	@Autowired
-	PaperDetailStructureService detailService;
+    PaperStructDetailService detailService;
 	
 	
 	
@@ -35,8 +35,8 @@ public class PaperDetailStructureController {
     * @return
     */
    @ApiOperation(value="获取单个大题",notes="获取单个大题")
-   @GetMapping(value = "/PaperDetailStructure/{detail_id}")
-   public PaperDetailStructure getPaperDetailStructureById(@PathVariable String detail_id){
+   @GetMapping(value = "/PaperStructDetail/{detail_id}")
+   public PaperStructDetail getPaperDetailStructureById(@PathVariable String detail_id){
        return detailService.findById(detail_id);
    }
 
@@ -47,8 +47,8 @@ public class PaperDetailStructureController {
     * @return
     */
    @PutMapping(value = "/paperDetailStructure")
-   public ResponseEntity updatePaperDetailStructure(@ModelAttribute PaperDetailStructure pd){
-       PaperDetailStructure paperDetail = detailService.savePaperStructureDetail(pd);
+   public ResponseEntity updatePaperDetailStructure(@ModelAttribute PaperStructDetail pd){
+       PaperStructDetail paperDetail = detailService.savePaperStructureDetail(pd);
        ResponseEntity rse = new ResponseEntity(paperDetail,HttpStatus.OK);
        return rse;
    	
@@ -60,8 +60,8 @@ public class PaperDetailStructureController {
     * @return
     */
    @PostMapping(value = "/paperDetailStructure")
-   public ResponseEntity addPaperDetailStructure(@ModelAttribute PaperDetailStructure pd){
-     PaperDetailStructure paperDetail = detailService.savePaperStructureDetail(pd);
+   public ResponseEntity addPaperDetailStructure(@ModelAttribute PaperStructDetail pd){
+     PaperStructDetail paperDetail = detailService.savePaperStructureDetail(pd);
      ResponseEntity rse2 = new ResponseEntity(paperDetail,HttpStatus.OK);
      return rse2;
    }

+ 0 - 9
cqb-question-resource/src/main/java/com/qmth/cqb/question/dao/QuesOptionRepo.java

@@ -1,9 +0,0 @@
-package com.qmth.cqb.question.dao;
-
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.data.repository.query.QueryByExampleExecutor;
-
-import com.qmth.cqb.question.model.QuesOption;
-
-public interface QuesOptionRepo extends MongoRepository<QuesOption,String>,QueryByExampleExecutor<QuesOption>{
-}

+ 0 - 11
cqb-question-resource/src/main/java/com/qmth/cqb/question/dao/QuestionTypeRepo.java

@@ -1,11 +0,0 @@
-package com.qmth.cqb.question.dao;
-
-import com.qmth.cqb.question.model.QuestionType;
-import org.springframework.data.mongodb.repository.MongoRepository;
-import org.springframework.data.repository.query.QueryByExampleExecutor;
-
-/**
- * Created by songyue on 16/12/28.
- */
-public interface QuestionTypeRepo extends MongoRepository<QuestionType,String>,QueryByExampleExecutor<QuestionType>{
-}

+ 8 - 8
cqb-question-resource/src/main/java/com/qmth/cqb/question/model/QuesOption.java

@@ -8,22 +8,22 @@ import java.io.Serializable;
 public class QuesOption implements Serializable{
     private static final long serialVersionUID = 6187112681135912330L;
 
-    private String optionNo;//选项编号
+    private String number;//选项编号
 
     private String optionBody;//选项内容
 
-    private byte[] optionBodyWord;//选项word
+    private String optionBodyWord;//选项word
 
     public static long getSerialVersionUID() {
         return serialVersionUID;
     }
 
-    public String getOptionNo() {
-        return optionNo;
+    public String getNumber() {
+        return number;
     }
 
-    public void setOptionNo(String optionNo) {
-        this.optionNo = optionNo;
+    public void setNumber(String number) {
+        this.number = number;
     }
 
     public String getOptionBody() {
@@ -34,11 +34,11 @@ public class QuesOption implements Serializable{
         this.optionBody = optionBody;
     }
 
-    public byte[] getOptionBodyWord() {
+    public String getOptionBodyWord() {
         return optionBodyWord;
     }
 
-    public void setOptionBodyWord(byte[] optionBodyWord) {
+    public void setOptionBodyWord(String optionBodyWord) {
         this.optionBodyWord = optionBodyWord;
     }
 

+ 57 - 41
cqb-question-resource/src/main/java/com/qmth/cqb/question/model/Question.java

@@ -1,8 +1,9 @@
 package com.qmth.cqb.question.model;
 
+import com.qmth.cqb.utils.CommonUtils;
+import com.qmth.cqb.utils.word.DocxProcessUtil;
+import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
 import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.index.Indexed;
-import org.springframework.data.mongodb.core.mapping.DBRef;
 
 import java.io.Serializable;
 import java.util.List;
@@ -16,32 +17,31 @@ public class Question implements Serializable{
     @Id
     private String id;
 
-    @Indexed(unique = true)
-
     private String quesBody;//题干,默认为html
 
-    private byte[] quesBodyWord;//题干word
+    private String quesBodyWord;//题干word
+
+    private byte[] quesPkg;//试题wordpkg对象序列化数据
 
     private String quesAnswer;//答案,默认为html
 
-    private byte[] quesAnswerWord;//答案word
+    private String quesAnswerWord;//答案word
 
     private String quesAnswerAnalysis;//答案解析,默认为html
 
-    private byte[] quesAnswerAnalysisWord;//答案word解析
+    private String quesAnswerAnalysisWord;//答案word解析
 
     private List<QuesOption> quesOptions;//试题选项
 
     private List<QuesResource> quesResource;//试题resource(试题资源库集合,适用于多媒体介质试题)
 
-    @DBRef
     private QuestionType questionType;//试题结构类型
 
     private String createTime;//创建时间
 
     private String updateTime;//更新时间
 
-    private List<Question> subQuestion;//子题目,用于套题
+    private List<Question> subQuestions;//子题目,用于套题
 
     private Map<String,String> quesParams;//试题属性
 
@@ -57,14 +57,6 @@ public class Question implements Serializable{
         this.id = id;
     }
 
-    public String getCreateTime() {
-        return createTime;
-    }
-
-    public void setCreateTime(String createTime) {
-        this.createTime = createTime;
-    }
-
     public String getQuesBody() {
         return quesBody;
     }
@@ -73,11 +65,11 @@ public class Question implements Serializable{
         this.quesBody = quesBody;
     }
 
-    public byte[] getQuesBodyWord() {
+    public String getQuesBodyWord() {
         return quesBodyWord;
     }
 
-    public void setQuesBodyWord(byte[] quesBodyWord) {
+    public void setQuesBodyWord(String quesBodyWord) {
         this.quesBodyWord = quesBodyWord;
     }
 
@@ -89,14 +81,30 @@ public class Question implements Serializable{
         this.quesAnswer = quesAnswer;
     }
 
-    public byte[] getQuesAnswerWord() {
+    public String getQuesAnswerWord() {
         return quesAnswerWord;
     }
 
-    public void setQuesAnswerWord(byte[] quesAnswerWord) {
+    public void setQuesAnswerWord(String quesAnswerWord) {
         this.quesAnswerWord = quesAnswerWord;
     }
 
+    public String getQuesAnswerAnalysis() {
+        return quesAnswerAnalysis;
+    }
+
+    public void setQuesAnswerAnalysis(String quesAnswerAnalysis) {
+        this.quesAnswerAnalysis = quesAnswerAnalysis;
+    }
+
+    public String getQuesAnswerAnalysisWord() {
+        return quesAnswerAnalysisWord;
+    }
+
+    public void setQuesAnswerAnalysisWord(String quesAnswerAnalysisWord) {
+        this.quesAnswerAnalysisWord = quesAnswerAnalysisWord;
+    }
+
     public List<QuesOption> getQuesOptions() {
         return quesOptions;
     }
@@ -113,20 +121,20 @@ public class Question implements Serializable{
         this.quesResource = quesResource;
     }
 
-    public List<Question> getSubQuestion() {
-        return subQuestion;
+    public QuestionType getQuestionType() {
+        return questionType;
     }
 
-    public void setSubQuestion(List<Question> subQuestion) {
-        this.subQuestion = subQuestion;
+    public void setQuestionType(QuestionType questionType) {
+        this.questionType = questionType;
     }
 
-    public Map<String, String> getQuesParams() {
-        return quesParams;
+    public String getCreateTime() {
+        return createTime;
     }
 
-    public void setQuesParams(Map<String, String> quesParams) {
-        this.quesParams = quesParams;
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
     }
 
     public String getUpdateTime() {
@@ -137,27 +145,35 @@ public class Question implements Serializable{
         this.updateTime = updateTime;
     }
 
-    public String getQuesAnswerAnalysis() {
-        return quesAnswerAnalysis;
+    public List<Question> getSubQuestions() {
+        return subQuestions;
     }
 
-    public void setQuesAnswerAnalysis(String quesAnswerAnalysis) {
-        this.quesAnswerAnalysis = quesAnswerAnalysis;
+    public void setSubQuestions(List<Question> subQuestions) {
+        this.subQuestions = subQuestions;
     }
 
-    public byte[] getQuesAnswerAnalysisWord() {
-        return quesAnswerAnalysisWord;
+    public Map<String, String> getQuesParams() {
+        return quesParams;
     }
 
-    public void setQuesAnswerAnalysisWord(byte[] quesAnswerAnalysisWord) {
-        this.quesAnswerAnalysisWord = quesAnswerAnalysisWord;
+    public void setQuesParams(Map<String, String> quesParams) {
+        this.quesParams = quesParams;
     }
 
-    public QuestionType getQuesStructType() {
-        return questionType;
+    public byte[] getQuesPkg() {
+        return quesPkg;
     }
 
-    public void setQuesStructType(QuestionType questionType) {
-        this.questionType = questionType;
+    public WordprocessingMLPackage getQuesPkgObj(){
+        return DocxProcessUtil.getPkg(this.quesPkg);
+    }
+
+    public void setQuesPkg(byte[] quesPkg) {
+        this.quesPkg = quesPkg;
+    }
+
+    public Question(){
+        this.createTime = CommonUtils.getCurDateTime();
     }
 }

+ 15 - 35
cqb-question-resource/src/main/java/com/qmth/cqb/question/model/QuestionType.java

@@ -1,76 +1,56 @@
 package com.qmth.cqb.question.model;
 
-import org.springframework.data.annotation.Id;
-
-import com.qmth.cqb.utils.enumeration.QuesStructType;
+import com.qmth.cqb.utils.enums.QuesStructType;
 
 import java.io.Serializable;
 import java.util.Map;
 
 /**
- * 试题结构类型(单选、多选、判断等)
+ * 试题类型(结构类型包装类)
  * Created by songyue on 16/12/28.
  */
 public class QuestionType implements Serializable{
     private static final long serialVersionUID = -4183850561167604080L;
 
-    @Id
-    private long id;
-
-    private QuesStructType quesType;//类型名称
+    private QuesStructType quesType;//结构类型
 
     private String name;//类型标题
 
     private Map params;//类型参数
 
-    public static long getSerialVersionUID() {
-        return serialVersionUID;
-    }
-
-
-    public long getId() {
-		return id;
-	}
-
-
-	public void setId(long id) {
-		this.id = id;
+	public static long getSerialVersionUID() {
+		return serialVersionUID;
 	}
 
-
 	public QuesStructType getQuesType() {
 		return quesType;
 	}
 
-
 	public void setQuesType(QuesStructType quesType) {
 		this.quesType = quesType;
 	}
 
-
 	public String getName() {
 		return name;
 	}
 
-
 	public void setName(String name) {
 		this.name = name;
 	}
 
-
-	public static long getSerialversionuid() {
-		return serialVersionUID;
+	public Map getParams() {
+		return params;
 	}
 
+	public void setParams(Map params) {
+		this.params = params;
+	}
 
-	public Map getParams() {
-        return params;
-    }
-
-    public void setParams(Map params) {
-        this.params = params;
+	public QuestionType() {
     }
 
-    public QuestionType() {
-    }
+	public QuestionType(QuesStructType quesType,String name) {
+		this.quesType = quesType;
+		this.name = name;
+	}
 }

+ 9 - 48
cqb-question-resource/src/main/java/com/qmth/cqb/question/service/QuesService.java

@@ -4,15 +4,12 @@ import com.qmth.cqb.question.dao.QuesRepo;
 import com.qmth.cqb.question.model.QuestionType;
 import com.qmth.cqb.question.model.Question;
 import com.qmth.cqb.question.model.QuestionSearchCondition;
-import com.qmth.cqb.utils.modal.NormalResponse;
-import com.qmth.cqb.utils.modal.PagingAndSortingResponse;
 
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Example;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
-import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Service;
 
 /**
@@ -21,14 +18,6 @@ import org.springframework.stereotype.Service;
 @Service
 public class QuesService {
 
-    /**
-     * 一般返回类型统一为NormalResponse对象
-     * NormalResponse(String httpStatus, String Message)
-     * 分页集合返回类型为PagingAndSortingResponse
-     * PagingAndSortingResponse(int curPage, int pageSize, int totalPages, long totalElements, List dataList)
-     * 一般集合返回类型为List
-     */
-
     @Autowired
     QuesRepo quesRepo;
 
@@ -39,42 +28,14 @@ public class QuesService {
      * @param pageSize
      * @return
      */
-    public PagingAndSortingResponse<Question> findAll(QuestionSearchCondition searchCondition, int curPage, int pageSize){
-    	Question que = new Question();
-    	QuestionType qst = new QuestionType();
-    	qst.setName(searchCondition.getQuesTypeName());
-    	que.setQuesStructType(qst);
-    	BeanUtils.copyProperties(searchCondition,que);
-        Page<Question> quesList = quesRepo.findAll(Example.of(que),new PageRequest(curPage-1,pageSize));
-        return new PagingAndSortingResponse<Question>(quesList.getNumber(),quesList.getSize(),
-                quesList.getTotalPages(),quesList.getTotalElements(),quesList.getContent());
-    }
-
-    /**
-     * 按ID查询试题
-     * @param typeId
-     * @return
-     */
-    public Question findById(String typeId){
-        return quesRepo.findOne(typeId);
-    }
-
-    /**
-     * 保存试题
-     * @param question
-     * @return
-     */
-    public Question saveQuestion(Question question){
-        Question tempQues = quesRepo.save(question);
-        return tempQues;
-    }
-
-    /**
-     * 删除试题
-     * @param typeId
-     * @return
-     */
-    public void deleteQuestion(String typeId){
-        quesRepo.delete(typeId);
+    public Page<Question> findAll(QuestionSearchCondition searchCondition,
+                                  int curPage,
+                                  int pageSize){
+    	Question ques = new Question();
+    	QuestionType quesType = new QuestionType();
+        quesType.setName(searchCondition.getQuesTypeName());
+    	ques.setQuestionType(quesType);
+    	BeanUtils.copyProperties(searchCondition,ques);
+        return quesRepo.findAll(Example.of(ques),new PageRequest(curPage - 1,pageSize));
     }
 }

+ 0 - 80
cqb-question-resource/src/main/java/com/qmth/cqb/question/service/QuesStructTypeService.java

@@ -1,80 +0,0 @@
-package com.qmth.cqb.question.service;
-
-import com.qmth.cqb.question.dao.QuestionTypeRepo;
-import com.qmth.cqb.question.model.QuestionType;
-import com.qmth.cqb.utils.modal.NormalResponse;
-import com.qmth.cqb.utils.modal.PagingAndSortingResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Example;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Service;
-
-/**
- * 试题结构类型服务类
- * Created by songyue on 16/12/28.
- */
-@Service
-public class QuesStructTypeService {
-
-    /**
-     * 一般返回类型统一为NormalResponse对象
-     * NormalResponse(String httpStatus, String Message)
-     * 分页集合返回类型为PagingAndSortingResponse
-     * PagingAndSortingResponse(int curPage, int pageSize, int totalPages, long totalElements, List dataList)
-     * 一般集合返回类型为List
-     */
-
-    @Autowired
-    QuestionTypeRepo quesStructTypeRepo;
-
-
-    /**
-     * 查询所有结构题型
-     * @param searchCondition
-     * @param curPage
-     * @param pageSize
-     * @return
-     */
-    public PagingAndSortingResponse<QuestionType> findAll(QuestionType searchCondition, int curPage, int pageSize){
-        Page<QuestionType> quesStructTypeList = quesStructTypeRepo.findAll(Example.of(searchCondition),new PageRequest(curPage-1,pageSize));
-        return new PagingAndSortingResponse<QuestionType>(quesStructTypeList.getNumber(),quesStructTypeList.getSize(),
-                quesStructTypeList.getTotalPages(),quesStructTypeList.getTotalElements(),quesStructTypeList.getContent());
-    }
-
-    /**
-     * 按ID查询结构题型
-     * @param typeId
-     * @return
-     */
-    public QuestionType findById(String typeId){
-        return quesStructTypeRepo.findOne(typeId);
-    }
-
-    /**
-     * 保存结构题型
-     * @param quesStructType
-     * @return
-     */
-    public NormalResponse saveQuesStructType(QuestionType quesStructType){
-        QuestionType tempPaper = quesStructTypeRepo.save(quesStructType);
-        if(tempPaper != null){
-            return new NormalResponse(HttpStatus.OK.toString(),"success");
-        }else{
-            return new NormalResponse(HttpStatus.INTERNAL_SERVER_ERROR.toString(),"保存失败");
-        }
-    }
-
-    /**
-     * 删除结构题型
-     * @param typeId
-     * @return
-     */
-    public NormalResponse deleteQuesStructType(String typeId){
-        quesStructTypeRepo.delete(typeId);
-        return new NormalResponse(HttpStatus.OK.toString(),"success");
-    }
-
-
-}

+ 28 - 48
cqb-question-resource/src/main/java/com/qmth/cqb/question/web/QuesController.java

@@ -2,6 +2,7 @@ package com.qmth.cqb.question.web;
 
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
+import com.qmth.cqb.question.dao.QuesRepo;
 import com.qmth.cqb.question.model.QuesOption;
 import com.qmth.cqb.question.model.QuestionType;
 import com.qmth.cqb.question.model.Question;
@@ -33,33 +34,37 @@ import org.springframework.web.bind.annotation.RestController;
 @RestController
 @RequestMapping("${api_cqb}/")
 public class QuesController {
+
     @Autowired
     QuesService quesService;
 
-      
     @Autowired
-    Gson gson;
+    QuesRepo quesRepo;
 
+    @Autowired
+    Gson gson;
 
     /**
      * 获取试题
-     * @param ques_id
+     * @param id
      * @return
      */
     @ApiOperation(value="获取单个试题",notes="获取单个试题")
-    @GetMapping(value = "/ques/{ques_id}")
-    public Question getQuesById(@PathVariable String ques_id){
-        return quesService.findById(ques_id);
+    @GetMapping(value = "/question/{id}")
+    public ResponseEntity getQuesById(@PathVariable String id){
+        return new ResponseEntity(quesRepo.findOne(id),HttpStatus.OK);
     }
 
     /**
-     * 获取全部试题
+     * 分页查询试题
      * @return
      */
-    @GetMapping(value = "/ques/all/{curPage}/{pageSize}")
-    public PagingAndSortingResponse<Question> getAllQuestion(@ModelAttribute QuestionSearchCondition searchCondition, @PathVariable int curPage, @PathVariable int pageSize){
-      PagingAndSortingResponse<Question> psr = quesService.findAll(searchCondition, curPage, pageSize);
-      return psr;
+    @ApiOperation(value="分页查询试题",notes="分页查询试题")
+    @GetMapping(value = "/question/{curPage}/{pageSize}")
+    public ResponseEntity getAllQuestion(@ModelAttribute QuestionSearchCondition searchCondition,                                              @PathVariable int curPage,
+                                         @PathVariable int pageSize){
+      return new ResponseEntity(quesService.findAll(searchCondition, curPage, pageSize),
+              HttpStatus.OK);
     }
 
     /**
@@ -67,12 +72,10 @@ public class QuesController {
      * @param 
      * @return
      */
+    @ApiOperation(value="更新试题",notes="更新试题")
     @PutMapping(value = "/question")
-    public ResponseEntity updateQuestion(@ModelAttribute Question ques){
-    	//return quesService.saveQuestion(ques);
-        Question qus = quesService.saveQuestion(ques);
-        ResponseEntity rse = new ResponseEntity(qus,HttpStatus.OK);
-        return rse;
+    public ResponseEntity updateQuestion(@ModelAttribute Question question){
+        return new ResponseEntity(quesRepo.save(question),HttpStatus.OK);
     	
     }
 
@@ -81,44 +84,21 @@ public class QuesController {
      * @param question
      * @return
      */
+    @ApiOperation(value="新增试题",notes="新增试题")
     @PostMapping(value = "/question")
-    public ResponseEntity addQuestion(@ModelAttribute Question ques){
-//    	QuesOption opt1 =  new QuesOption();
-//    	opt1.setOptionNo("1");
-//    	opt1.setOptionBody("10");
-//    	QuesOption opt2 =  new QuesOption();
-//    	opt2.setOptionNo("2");
-//    	opt2.setOptionBody("15");
-//    	List<QuesOption> opts = new ArrayList<QuesOption>();
-//    	opts.add(opt1);
-//    	opts.add(opt2);
-//    	QuesStructType type = new QuesStructType();
-//    	type.setId("1");
-//    	type.setTypeName("单选");
-//    	type.setTypeTitle("单项选择题");
-//    	Question questemp = new Question();
-//    	questemp.setCreateTime("1");
-//    	questemp.setQuesAnswer("B");
-//    	questemp.setQuesBody("5乘以3等于几");
-//    	questemp.setQuesOptions(opts);
-//    	questemp.setQuesStructType(type);
-//    	
-//      String quesJson = gson.toJson(questemp);
-//      Question ques = gson.fromJson(quesJson,Question.class);
-      Question qus = quesService.saveQuestion(ques);
-      ResponseEntity rse2 = new ResponseEntity(qus,HttpStatus.OK);
-      return rse2;
+    public ResponseEntity addQuestion(@ModelAttribute Question question){
+      return new ResponseEntity(quesRepo.save(question),HttpStatus.CREATED);
     }
 
     /**
      * 删除试题
-     * @param ques_id
+     * @param id
      * @return
      */
-    @DeleteMapping(value = "/ques/{ques_id}")
-    public ResponseEntity removeQuestion(@PathVariable String ques_id){
-    	quesService.deleteQuestion(ques_id);
-    	ResponseEntity rse2 = new ResponseEntity(ques_id,HttpStatus.OK);
-    	return rse2;
+    @ApiOperation(value="删除试题",notes="删除试题")
+    @DeleteMapping(value = "/question/{id}")
+    public ResponseEntity removeQuestion(@PathVariable String id){
+    	quesRepo.delete(id);
+    	return new ResponseEntity(HttpStatus.OK);
     }
 }

+ 0 - 83
cqb-question-resource/src/main/java/com/qmth/cqb/question/web/QuestionTypeController.java

@@ -1,83 +0,0 @@
-package com.qmth.cqb.question.web;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.google.gson.Gson;
-import com.qmth.cqb.question.model.QuestionType;
-import com.qmth.cqb.question.service.QuesStructTypeService;
-import com.qmth.cqb.utils.modal.NormalResponse;
-import com.qmth.cqb.utils.modal.PagingAndSortingResponse;
-
-/**
- * Created by songyue on 16/12/29.
- */
-@RestController
-@RequestMapping("${api_cqb}/")
-public class QuestionTypeController {
-    @Autowired
-    QuesStructTypeService quesStructTypeService;
-      
-    @Autowired
-    Gson gson;
-
-
-    /**
-     * 获取试题结构类型
-     * @param ques_id
-     * @return
-     */
-    @GetMapping(value = "/quesStructType/{quesStype_id}")
-    public QuestionType getQuesById(@PathVariable String quesStype_id){
-        return quesStructTypeService.findById(quesStype_id);
-    }
-
-    /**
-     * 获取全部试卷结构
-     * @return
-     */
-    @GetMapping(value = "/quesStructType/all/{curPage}/{paseSize}")
-    public PagingAndSortingResponse<QuestionType> getAllQuesStructType(@ModelAttribute QuestionType searchCondition, @PathVariable int curPage, @PathVariable int pageSize){
-      PagingAndSortingResponse<QuestionType> psr = quesStructTypeService.findAll(searchCondition, curPage, pageSize);
-      return psr;
-    }
-
-    /**
-     * 更新试卷结构信息
-     * @param 
-     * @return
-     */
-    @PutMapping(value = "/quesStructType")
-    public NormalResponse updateQuesStructType(@ModelAttribute QuestionType ques){
-    	return quesStructTypeService.saveQuesStructType(ques);
-    	
-    }
-
-    /**
-     * 新增试卷结构
-     * @param quesStype
-     * @return
-     */
-    @PostMapping(value = "/quesStructType")
-    public NormalResponse addQuesStructType(@ModelAttribute QuestionType quesStype){
-    	return quesStructTypeService.saveQuesStructType(quesStype);
-    }
-
-    /**
-     * 删除试卷结构
-     * @param quesStype_id
-     * @return
-     */
-    @DeleteMapping(value = "/quesStructType/{quesStype_id}")
-    public NormalResponse removeQuesStructType(@PathVariable String quesStype_id){
-    	return quesStructTypeService.deleteQuesStructType(quesStype_id);
-    }
-}

BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/dao/QuesOptionRepo.class


BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/dao/QuestionTypeRepo.class


BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/model/QuesOption.class


BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/model/Question.class


BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/model/QuestionType.class


BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/service/QuesService.class


BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/service/QuesStructTypeService.class


BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/web/QuesController.class


BIN
cqb-question-resource/target/classes/com/qmth/cqb/question/web/QuestionTypeController.class


+ 1 - 1
cqb-question-resource/target/maven-archiver/pom.properties

@@ -1,5 +1,5 @@
 #Generated by Apache Maven
-#Mon Feb 27 14:53:21 CST 2017
+#Mon Mar 20 18:27:20 CST 2017
 version=0.1.0
 groupId=com.qmth.cqb
 artifactId=cqb-question-resource

+ 12 - 0
cqb-starter/pom.xml

@@ -60,7 +60,19 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>

+ 2 - 1
cqb-starter/src/main/resources/application.properties

@@ -1,4 +1,5 @@
 spring.data.mongodb.uri=mongodb://192.168.1.99:27017/comm-ques-bank
 spring.data.mongodb.grid-fs-database=comm-ques-bank
 server.port=8888
-api_cqb=/api/ecs_ques
+logging.config=classpath:log4j2.xml
+api_cqb=/api/ecs_ques

+ 25 - 0
cqb-starter/src/main/resources/log4j2.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN">
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT" follow="true">
+            <PatternLayout>
+                <pattern>%d %p %C{1.} [%t] %m%n</pattern>
+            </PatternLayout>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <!-- 输出info级别信息 -->
+        <Root level="info">
+            <AppenderRef ref="Console" />
+        </Root>
+
+        <Root level="error">
+            <AppenderRef ref="Console" />
+        </Root>
+
+        <Root level="debug">
+            <AppenderRef ref="Console" />
+        </Root>
+
+    </Loggers>
+</Configuration>

+ 89 - 13
cqb-starter/src/test/java/com/qmth/cqb/AppTest.java

@@ -1,22 +1,33 @@
 package com.qmth.cqb;
 
+import com.google.gson.Gson;
 import com.qmth.cqb.base.dao.UserRepo;
 import com.qmth.cqb.base.model.User;
 import com.qmth.cqb.base.service.UserService;
 import com.qmth.cqb.paper.dao.*;
 import com.qmth.cqb.paper.model.*;
+import com.qmth.cqb.paper.service.ExportPaperService;
+import com.qmth.cqb.paper.service.ImportPaperService;
+import com.qmth.cqb.paper.service.PaperDetailUnitService;
 import com.qmth.cqb.question.dao.QuesRepo;
 import com.qmth.cqb.question.model.QuesOption;
 import com.qmth.cqb.question.model.Question;
 import com.qmth.cqb.question.model.QuestionType;
 import com.qmth.cqb.utils.GridFSUtil;
-import com.qmth.cqb.utils.enumeration.ExtractPolicy;
-import com.qmth.cqb.utils.enumeration.QuesStructType;
+import com.qmth.cqb.utils.enums.ExtractPolicy;
+import com.qmth.cqb.utils.enums.QuesStructType;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.util.List;
+
+import com.qmth.cqb.utils.word.DocxProcessUtil;
+import org.apache.log4j.Logger;
+import org.docx4j.Docx4J;
+import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
+import org.docx4j.openpackaging.parts.relationships.Namespaces;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -33,6 +44,7 @@ import java.util.ArrayList;
 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class AppTest {
+    protected final Logger log = Logger.getLogger(AppTest.class);
     @Autowired
     UserRepo userRepo;
 
@@ -60,6 +72,18 @@ public class AppTest {
     @Autowired
     ExtractConfigRepo extractConfigRepo;
 
+    @Autowired
+    ImportPaperService importPaperService;
+
+    @Autowired
+    ExportPaperService exportPaperService;
+
+    @Autowired
+    Gson gson;
+
+    @Autowired
+    PaperDetailUnitService paperDetailUnitService;
+
     @Test
     public void testGridFs() throws FileNotFoundException {
         String fileName = "testXml";
@@ -117,10 +141,9 @@ public class AppTest {
                 "材料在外力作用下发生形变(套题题干)。\n" +
                 "</span></span></span></p></body></html>");
         QuestionType questionType = new QuestionType();
-        questionType.setId(1);
         questionType.setName("阅读理解");
         questionType.setQuesType(QuesStructType.NESTED_ANSWER_QUESTION);
-        question.setQuesStructType(questionType);
+        question.setQuestionType(questionType);
         List<Question> subquestionList = new ArrayList<Question>();
 
 
@@ -141,13 +164,11 @@ public class AppTest {
             quesOptionList.add(quesOption2);
             subquestion.setQuesOptions(quesOptionList);
             QuestionType questionType1 = new QuestionType();
-            questionType1.setId(1);
-            questionType1.setName("单项选择题");
             questionType1.setQuesType(QuesStructType.SINGLE_ANSWER_QUESTION);
-            subquestion.setQuesStructType(questionType1);
+            subquestion.setQuestionType(questionType1);
             subquestionList.add(subquestion);
         }
-        question.setSubQuestion(subquestionList);
+        question.setSubQuestions(subquestionList);
         quesRepo.save(question);
     }
 
@@ -163,14 +184,13 @@ public class AppTest {
         paper.setTitle("测试试卷");
         PaperDetail paperDetail = new PaperDetail();
         paperDetail.setName("选择题");
-        paperDetail.setScore(20);
+        paperDetail.setScore((double)20);
         paperDetail.setNumber(1);
         paperDetail.setPaper(paper);
         QuestionType questionType1 = new QuestionType();
-        questionType1.setId(1);
         questionType1.setName("单项选择题");
         questionType1.setQuesType(QuesStructType.SINGLE_ANSWER_QUESTION);
-        paperDetail.setQuesStructType(questionType1);
+        paperDetail.setQuestionType(questionType1);
         paperDetail.setUnitCount(3);
 
         paperRepo.save(paper);
@@ -181,11 +201,11 @@ public class AppTest {
         int i = 0;
         for(Question ques:questionList){
             PaperDetailUnit paperDetailUnit = new PaperDetailUnit();
-            paperDetailUnit.setQuesStructType(ques.getQuesStructType());
+            paperDetailUnit.setQuestionType(ques.getQuestionType());
             paperDetailUnit.setNumber(i);
             paperDetailUnit.setPaper(paper);
             paperDetailUnit.setPaperDetail(paperDetail);
-            paperDetailUnit.setScore(10);
+            paperDetailUnit.setScore((double)10);
             paperDetailUnit.setQuestion(ques);
             i++;
             paperDetailUnitRepo.save(paperDetailUnit);
@@ -211,6 +231,62 @@ public class AppTest {
             extractConfigRepo.save(extractConfig);
         }
 
+        @Test
+        public void testImport(){
+            paperRepo.deleteAll();
+            paperDetailRepo.deleteAll();
+            quesRepo.deleteAll();
+            paperDetailUnitRepo.deleteAll();
+            String inputFilePath = "/Users/songyue/docxImport/ceshi2.docx";
+            try {
+                File inputFile = new File(inputFilePath);
+                FileInputStream inputStream = new FileInputStream(inputFile);
+                System.out.println(inputFilePath);
+                long startTime = System.currentTimeMillis();    //获取开始时间
+
+                String errorInfo = importPaperService.ImportPaper(inputStream);
+                System.out.println("errorInfo:"+errorInfo);
+
+                long endTime = System.currentTimeMillis();    //获取结束时间
+
+                System.out.println("程序运行时间:" + (endTime - startTime)/1000 + "s");    //输出程序运行时间
+
+
 
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+
+        }
+
+        @Test
+        public void testExport()throws Exception{
+            long startTime = System.currentTimeMillis();    //获取开始时间
+            exportPaperService.exportPaper("58cb82a8f6c5faef9b2a9f01");
+            long endTime = System.currentTimeMillis();    //获取结束时间
+            System.out.println("程序运行时间:" + (endTime - startTime)/1000 + "s");    //输出程序运行时间
+        }
+
+        @Test
+        public void testImport1(){
+            String inputFilePath = "/Users/songyue/docxImport/ceshi2.docx";
+            String outFilePath = "/Users/songyue/docxImport/ceshi11111.docx";
+            try {
+                File inputFile = new File(inputFilePath);
+                FileInputStream inputStream = new FileInputStream(inputFile);
+                System.out.println(inputFilePath);
+
+                WordprocessingMLPackage wordMLPackage = Docx4J.load(inputFile);
+
+                DocxProcessUtil.initPkgImage(wordMLPackage);
+                Docx4J.save(wordMLPackage,new FileOutputStream(outFilePath));
+
+
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        }
 
 }

+ 2 - 1
pom.xml

@@ -8,7 +8,7 @@
   <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
-    <version>1.5.1.RELEASE</version>
+    <version>1.4.3.RELEASE</version>
   </parent>
   <modules>
     <module>cqb-starter</module>
@@ -60,6 +60,7 @@
           <version>${maven-surefire-plugin.version}</version>
           <configuration>
             <testFailureIgnore>true</testFailureIgnore>
+              <skipTests>true</skipTests>
           </configuration>
         </plugin>