All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.common.util.XML Maven / Gradle / Ivy

The newest version!
/*
 * 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,  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 static final 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 static final 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 attrs)
      throws IOException {
    writeXML(
        out,
        tag,
        val,
        attrs.entrySet().stream()
            .flatMap((entry) -> Stream.of(entry.getKey(), entry.getValue()))
            .toArray());
  }

  /**
   * @lucene.internal
   */
  public static final 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);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy