001package com.hfg.xml.msofficexml; 002 003 004import java.io.BufferedReader; 005import java.io.InputStream; 006import java.io.InputStreamReader; 007import java.io.Reader; 008import java.util.ArrayList; 009import java.util.List; 010import java.util.logging.Level; 011import java.util.logging.Logger; 012import java.util.zip.GZIPInputStream; 013import java.util.zip.ZipEntry; 014import java.util.zip.ZipInputStream; 015 016import com.hfg.util.StringBuilderPlus; 017import com.hfg.util.StringUtil; 018import com.hfg.xml.XMLException; 019import com.hfg.xml.msofficexml.docx.wordprocessingml.WmlXML; 020import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXML; 021import com.hfg.xml.xsd.Xsd; 022 023//------------------------------------------------------------------------------ 024/** 025 XML xsd specification for OfficeOpenXml files. This information is need when 026 producing OfficeOpenXml documents because, for some reason, MS Office applications 027 are extremely picky about XML tag order. 028 <div> 029 xsd files downloaded from: 030 <a href='http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-376,%20Fourth%20Edition,%20Part%201%20-%20Fundamentals%20And%20Markup%20Language%20Reference.zip'> 031 http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-376,%20Fourth%20Edition,%20Part%201%20-%20Fundamentals%20And%20Markup%20Language%20Reference.zip 032 </a> 033 </div> 034 <div> 035 @author J. Alex Taylor, hairyfatguy.com 036 </div> 037 */ 038//------------------------------------------------------------------------------ 039// com.hfg XML/HTML Coding Library 040// 041// This library is free software; you can redistribute it and/or 042// modify it under the terms of the GNU Lesser General Public 043// License as published by the Free Software Foundation; either 044// version 2.1 of the License, or (at your option) any later version. 045// 046// This library is distributed in the hope that it will be useful, 047// but WITHOUT ANY WARRANTY; without even the implied warranty of 048// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 049// Lesser General Public License for more details. 050// 051// You should have received a copy of the GNU Lesser General Public 052// License along with this library; if not, write to the Free Software 053// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 054// 055// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 056// jataylor@hairyfatguy.com 057//------------------------------------------------------------------------------ 058 059public class OfficeOpenXmlXsd extends Xsd 060{ 061 private static OfficeOpenXmlXsd sInstance; 062 063 private static final List<String> sXsdResources; 064 static 065 { 066 sXsdResources = new ArrayList<>(5); 067 sXsdResources.add("rsrc/OfficeOpenXML-XMLSchema-Strict.zip"); 068 // From https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/aa12452a-467d-4192-8ebf-0a90d86dd64b 069 sXsdResources.add("rsrc/xlbasictypes.xsd.gz"); // http://schemas.microsoft.com/office/excel/2006/main 070 sXsdResources.add("rsrc/xlslicercache.xsd.gz"); // http://schemas.microsoft.com/office/spreadsheetml/2009/9/main 071 sXsdResources.add("rsrc/xl15.xsd.gz"); // http://schemas.microsoft.com/office/spreadsheetml/2010/11/main 072 sXsdResources.add("rsrc/xlpivot16.xsd.gz"); // http://schemas.microsoft.com/office/spreadsheetml/2014/11/main 073 } 074 075 private final static Logger LOGGER = Logger.getLogger(OfficeOpenXmlXsd.class.getPackage().getName()); 076 077 078 //########################################################################### 079 // CONSTRUCTORS 080 //########################################################################### 081 082 //--------------------------------------------------------------------------- 083 private OfficeOpenXmlXsd() 084 throws Exception 085 { 086 super(); 087 088 // If we don't start by initializing namespaces then some parsed xsd data will lack a prefix 089 // and values can collide. 090 SsmlXML.initializeNamespaces(); 091 WmlXML.initializeNamespaces(); 092 093 for (String rsrc : sXsdResources) 094 { 095 InputStream is = OfficeXML.class.getResourceAsStream(rsrc); 096 if (null == is) 097 { 098 throw new RuntimeException("The resource " + StringUtil.singleQuote(rsrc) + " couldn't be found!"); 099 } 100 101 if (rsrc.endsWith(".zip")) 102 { 103 ZipInputStream zis = new ZipInputStream(is); 104 ZipEntry zipEntry; 105 while ((zipEntry = zis.getNextEntry()) != null) 106 { 107 LOGGER.log(Level.FINE, "Extracting: " + zipEntry + " ..."); 108 109 Reader reader = new BufferedReader(new InputStreamReader(zis)); 110 parse(reader); 111 112 zis.closeEntry(); 113 } 114 } 115 else 116 { 117 if (rsrc.endsWith(".gz")) 118 { 119 is = new GZIPInputStream(is); 120 } 121 122 LOGGER.log(Level.FINE, "Extracting: " + rsrc + " ..."); 123 Reader reader = new BufferedReader(new InputStreamReader(is)); 124 parse(reader); 125 } 126 } 127 128 integrateTypesWithElements(); 129 } 130 131 //########################################################################### 132 // PUBLIC METHODS 133 //########################################################################### 134 135 //--------------------------------------------------------------------------- 136 public synchronized static OfficeOpenXmlXsd getInstance() 137 { 138 if (null == sInstance) 139 { 140 try 141 { 142 sInstance = new OfficeOpenXmlXsd(); 143 } 144 catch (Exception e) 145 { 146 throw new XMLException("Problem initializing the OfficeOpenXML XSD info!", e); 147 } 148 } 149 150 return sInstance; 151 } 152 153 //--------------------------------------------------------------------------- 154 public static Logger getLogger() 155 { 156 return LOGGER; 157 } 158 159 //--------------------------------------------------------------------------- 160 public CharSequence getConfigSummary() 161 { 162 StringBuilderPlus buffer = new StringBuilderPlus(); 163 buffer.appendln("Loaded XSD resources:"); 164 for (String rsrc : sXsdResources) 165 { 166 buffer.appendln(" " + rsrc); 167 } 168 buffer.appendln(); 169 buffer.appendln(super.getConfigSummary()); 170 171 return buffer; 172 } 173 174}