Java tutorial
/* * 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.solr.common.util; import java.io.IOException; import java.io.Writer; import java.util.Map; import java.util.stream.Stream; /** * */ public class XML { // // copied from some of my personal code... -YCS // table created from python script. // only have to escape quotes in attribute values, and don't really have to escape '>' // many chars less than 0x20 are *not* valid XML, even when escaped! // for example, <foo>�<foo> is invalid XML. private static final String[] chardata_escapes = { "#0;", "#1;", "#2;", "#3;", "#4;", "#5;", "#6;", "#7;", "#8;", null, null, "#11;", "#12;", null, "#14;", "#15;", "#16;", "#17;", "#18;", "#19;", "#20;", "#21;", "#22;", "#23;", "#24;", "#25;", "#26;", "#27;", "#28;", "#29;", "#30;", "#31;", null, null, null, null, null, null, "&", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "<", null, ">" }; private static final String[] attribute_escapes = { "#0;", "#1;", "#2;", "#3;", "#4;", "#5;", "#6;", "#7;", "#8;", null, null, "#11;", "#12;", null, "#14;", "#15;", "#16;", "#17;", "#18;", "#19;", "#20;", "#21;", "#22;", "#23;", "#24;", "#25;", "#26;", "#27;", "#28;", "#29;", "#30;", "#31;", null, null, """, null, null, null, "&", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "<" }; /* #Simple python script used to generate the escape table above. -YCS # #use individual char arrays or one big char array for better efficiency # or byte array? #other={'&':'amp', '<':'lt', '>':'gt', "'":'apos', '"':'quot'} # other={'&':'amp', '<':'lt'} maxi=ord(max(other.keys()))+1 table=[None] * maxi #NOTE: invalid XML chars are "escaped" as #nn; *not* &#nn; because #a real XML escape would cause many strict XML parsers to choke. for i in range(0x20): table[i]='#%d;' % i for i in '\n\r\t ': table[ord(i)]=None for k,v in other.items(): table[ord(k)]='&%s;' % v result="" for i in range(maxi): val=table[i] if not val: val='null' else: val='"%s"' % val result += val + ',' print result */ public static void escapeCharData(String str, Writer out) throws IOException { escape(str, out, chardata_escapes); } public static void escapeAttributeValue(String str, Writer out) throws IOException { escape(str, out, attribute_escapes); } public static void escapeAttributeValue(char[] chars, int start, int length, Writer out) throws IOException { escape(chars, start, length, out, attribute_escapes); } /** does NOT escape character data in val; it must already be valid XML. Attributes are always escaped. */ public final static void writeUnescapedXML(Writer out, String tag, String val, Object... attrs) throws IOException { writeXML(out, tag, (writer1) -> writer1.write(val), attrs); } /** escapes character data in val and attributes */ public final static void writeXML(Writer out, String tag, String val, Object... attrs) throws IOException { final Writable writable = val != null ? (writer1) -> XML.escapeCharData(val, writer1) : null; writeXML(out, tag, writable, attrs); } /** escapes character data in val and attributes */ public static void writeXML(Writer out, String tag, String val, Map<String, String> attrs) throws IOException { writeXML(out, tag, val, attrs.entrySet().stream() .flatMap((entry) -> Stream.of(entry.getKey(), entry.getValue())).toArray()); } /** @lucene.internal */ public final static void writeXML(Writer out, String tag, Writable valWritable, Object... attrs) throws IOException { out.write('<'); out.write(tag); final int attrsLen = attrs == null ? 0 : attrs.length; for (int i = 0; i < attrsLen; i++) { out.write(' '); out.write(attrs[i++].toString()); out.write('='); out.write('"'); escapeAttributeValue(attrs[i].toString(), out); out.write('"'); } if (valWritable == null) { out.write('/'); out.write('>'); } else { out.write('>'); valWritable.write(out); out.write('<'); out.write('/'); out.write(tag); out.write('>'); } } @FunctionalInterface public interface Writable { void write(Writer w) throws IOException; } private static void escape(char[] chars, int offset, int length, Writer out, String[] escapes) throws IOException { for (int i = offset; i < length; i++) { char ch = chars[i]; if (ch < escapes.length) { String replacement = escapes[ch]; if (replacement != null) { out.write(replacement); continue; } } out.write(ch); } } private static void escape(String str, Writer out, String[] escapes) throws IOException { for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); if (ch < escapes.length) { String replacement = escapes[ch]; if (replacement != null) { out.write(replacement); continue; } } out.write(ch); } } }