| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| |
| package org.apache.poi; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.lang.ref.WeakReference; |
| import java.net.URL; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import javax.xml.stream.XMLStreamReader; |
| |
| import org.apache.poi.openxml4j.opc.PackageNamespaces; |
| import org.apache.poi.util.DocumentHelper; |
| import org.apache.poi.util.Removal; |
| import org.apache.xmlbeans.SchemaType; |
| import org.apache.xmlbeans.SchemaTypeLoader; |
| import org.apache.xmlbeans.XmlBeans; |
| import org.apache.xmlbeans.XmlException; |
| import org.apache.xmlbeans.XmlObject; |
| import org.apache.xmlbeans.XmlOptions; |
| import org.apache.xmlbeans.xml.stream.XMLInputStream; |
| import org.apache.xmlbeans.xml.stream.XMLStreamException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Node; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| |
| @SuppressWarnings("deprecation") |
| public class POIXMLTypeLoader { |
| |
| private static ThreadLocal<SchemaTypeLoader> typeLoader = new ThreadLocal<SchemaTypeLoader>(); |
| |
| // TODO: Do these have a good home like o.a.p.openxml4j.opc.PackageNamespaces and PackageRelationshipTypes? |
| // These constants should be common to all of POI and easy to use by other applications such as Tika |
| private static final String MS_OFFICE_URN = "urn:schemas-microsoft-com:office:office"; |
| private static final String MS_EXCEL_URN = "urn:schemas-microsoft-com:office:excel"; |
| private static final String MS_WORD_URN = "urn:schemas-microsoft-com:office:word"; |
| private static final String MS_VML_URN = "urn:schemas-microsoft-com:vml"; |
| |
| public static final XmlOptions DEFAULT_XML_OPTIONS; |
| static { |
| DEFAULT_XML_OPTIONS = new XmlOptions(); |
| DEFAULT_XML_OPTIONS.setSaveOuter(); |
| DEFAULT_XML_OPTIONS.setUseDefaultNamespace(); |
| DEFAULT_XML_OPTIONS.setSaveAggressiveNamespaces(); |
| DEFAULT_XML_OPTIONS.setCharacterEncoding("UTF-8"); |
| // Piccolo is disabled for POI builts, i.e. JAXP is used for parsing |
| // so only user code using XmlObject/XmlToken.Factory.parse |
| // directly can bypass the entity check, which is probably unlikely (... and not within our responsibility :)) |
| // DEFAULT_XML_OPTIONS.setLoadEntityBytesLimit(4096); |
| |
| // POI is not thread-safe - so we can switch to unsynchronized xmlbeans mode - see #61350 |
| // Update: disabled again for now as it caused strange NPEs and other problems |
| // when reading properties in separate workbooks in multiple threads |
| // DEFAULT_XML_OPTIONS.setUnsynchronized(); |
| |
| Map<String, String> map = new HashMap<String, String>(); |
| map.put("http://schemas.openxmlformats.org/drawingml/2006/main", "a"); |
| map.put("http://schemas.openxmlformats.org/drawingml/2006/chart", "c"); |
| map.put("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", "wp"); |
| map.put(PackageNamespaces.MARKUP_COMPATIBILITY, "ve"); |
| map.put("http://schemas.openxmlformats.org/officeDocument/2006/math", "m"); |
| map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); |
| map.put("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", "vt"); |
| map.put("http://schemas.openxmlformats.org/presentationml/2006/main", "p"); |
| map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); |
| map.put("http://schemas.microsoft.com/office/word/2006/wordml", "wne"); |
| map.put(MS_OFFICE_URN, "o"); |
| map.put(MS_EXCEL_URN, "x"); |
| map.put(MS_WORD_URN, "w10"); |
| map.put(MS_VML_URN, "v"); |
| DEFAULT_XML_OPTIONS.setSaveSuggestedPrefixes(Collections.unmodifiableMap(map)); |
| } |
| |
| private static XmlOptions getXmlOptions(XmlOptions options) { |
| return options == null ? DEFAULT_XML_OPTIONS : options; |
| } |
| |
| /** |
| * Sets the {@link ClassLoader} which is used, when XmlBeans are dynamically instantiated - |
| * opposed to being loaded by the factory class which is accompanied by each generated XmlBeans interface. |
| * <p> |
| * This is especially necessary in a context which doesn't guarantee that the current (thread) context |
| * cassloader has access to all XmlBeans schema definitions (*.xsb) - which is typically in OSGI the case. |
| * <p> |
| * The classloader will be only set for the current thread in a {@link ThreadLocal}. Although the |
| * ThreadLocal is implemented via a {@link WeakReference}, it's good style to {@code null} the classloader |
| * when the user code is finalized. |
| * |
| * @param cl the classloader to be used when XmlBeans classes and definitions are looked up |
| * @deprecated in POI 3.17 - setting a classloader from the outside is now obsolete, |
| * the classloader of the SchemaType will be used |
| */ |
| @Deprecated |
| @Removal(version="4.0") |
| public static void setClassLoader(ClassLoader cl) { |
| } |
| |
| private static SchemaTypeLoader getTypeLoader(SchemaType type) { |
| SchemaTypeLoader tl = typeLoader.get(); |
| if (tl == null) { |
| ClassLoader cl = type.getClass().getClassLoader(); |
| tl = XmlBeans.typeLoaderForClassLoader(cl); |
| typeLoader.set(tl); |
| } |
| return tl; |
| } |
| |
| public static XmlObject newInstance(SchemaType type, XmlOptions options) { |
| return getTypeLoader(type).newInstance(type, getXmlOptions(options)); |
| } |
| |
| public static XmlObject parse(String xmlText, SchemaType type, XmlOptions options) throws XmlException { |
| try { |
| return parse(new StringReader(xmlText), type, options); |
| } catch (IOException e) { |
| throw new XmlException("Unable to parse xml bean", e); |
| } |
| } |
| |
| public static XmlObject parse(File file, SchemaType type, XmlOptions options) throws XmlException, IOException { |
| InputStream is = new FileInputStream(file); |
| try { |
| return parse(is, type, options); |
| } finally { |
| is.close(); |
| } |
| } |
| |
| public static XmlObject parse(URL file, SchemaType type, XmlOptions options) throws XmlException, IOException { |
| InputStream is = file.openStream(); |
| try { |
| return parse(is, type, options); |
| } finally { |
| is.close(); |
| } |
| } |
| |
| public static XmlObject parse(InputStream jiois, SchemaType type, XmlOptions options) throws XmlException, IOException { |
| try { |
| Document doc = DocumentHelper.readDocument(jiois); |
| return getTypeLoader(type).parse(doc.getDocumentElement(), type, getXmlOptions(options)); |
| } catch (SAXException e) { |
| throw new IOException("Unable to parse xml bean", e); |
| } |
| } |
| |
| public static XmlObject parse(XMLStreamReader xsr, SchemaType type, XmlOptions options) throws XmlException { |
| return getTypeLoader(type).parse(xsr, type, getXmlOptions(options)); |
| } |
| |
| public static XmlObject parse(Reader jior, SchemaType type, XmlOptions options) throws XmlException, IOException { |
| try { |
| Document doc = DocumentHelper.readDocument(new InputSource(jior)); |
| return getTypeLoader(type).parse(doc.getDocumentElement(), type, getXmlOptions(options)); |
| } catch (SAXException e) { |
| throw new XmlException("Unable to parse xml bean", e); |
| } |
| } |
| |
| public static XmlObject parse(Node node, SchemaType type, XmlOptions options) throws XmlException { |
| return getTypeLoader(type).parse(node, type, getXmlOptions(options)); |
| } |
| |
| public static XmlObject parse(XMLInputStream xis, SchemaType type, XmlOptions options) throws XmlException, XMLStreamException { |
| return getTypeLoader(type).parse(xis, type, getXmlOptions(options)); |
| } |
| |
| public static XMLInputStream newValidatingXMLInputStream ( XMLInputStream xis, SchemaType type, XmlOptions options ) throws XmlException, XMLStreamException { |
| return getTypeLoader(type).newValidatingXMLInputStream(xis, type, getXmlOptions(options)); |
| } |
| } |