Home | History | Annotate | Download | only in impl
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  ******************************************************************************
      5  * Copyright (C) 2007-2010, International Business Machines Corporation and   *
      6  * others. All Rights Reserved.                                               *
      7  ******************************************************************************
      8  */
      9 
     10 package com.ibm.icu.impl.duration.impl;
     11 
     12 import java.io.IOException;
     13 import java.io.Writer;
     14 import java.util.ArrayList;
     15 import java.util.List;
     16 
     17 import com.ibm.icu.lang.UCharacter;
     18 
     19 public class XMLRecordWriter implements RecordWriter {
     20     private Writer w;
     21     private List<String> nameStack;
     22 
     23     public XMLRecordWriter(Writer w) {
     24         this.w = w;
     25         this.nameStack = new ArrayList<String>();
     26     }
     27 
     28     @Override
     29     public boolean open(String title) {
     30         newline();
     31         writeString("<" + title + ">");
     32         nameStack.add(title);
     33         return true;
     34     }
     35 
     36     @Override
     37     public boolean close() {
     38         int ix = nameStack.size() - 1;
     39         if (ix >= 0) {
     40             String name = nameStack.remove(ix);
     41             newline();
     42             writeString("</" + name + ">");
     43             return true;
     44         }
     45         return false;
     46     }
     47 
     48     public void flush() {
     49         try {
     50             w.flush();
     51         } catch (IOException e) {
     52         }
     53     }
     54 
     55     @Override
     56     public void bool(String name, boolean value) {
     57         internalString(name, String.valueOf(value));
     58     }
     59 
     60     @Override
     61     public void boolArray(String name, boolean[] values) {
     62         if (values != null) {
     63             String[] stringValues = new String[values.length];
     64             for (int i = 0; i < values.length; ++i) {
     65                 stringValues[i] = String.valueOf(values[i]);
     66             }
     67             stringArray(name, stringValues);
     68         }
     69     }
     70 
     71     private static String ctos(char value) {
     72         if (value == '<') {
     73             return "&lt;";
     74         }
     75         if (value == '&') {
     76             return "&amp;";
     77         }
     78         return String.valueOf(value);
     79     }
     80 
     81     @Override
     82     public void character(String name, char value) {
     83         if (value != '\uffff') {
     84             internalString(name, ctos(value));
     85         }
     86     }
     87 
     88     @Override
     89     public void characterArray(String name, char[] values) {
     90         if (values != null) {
     91             String[] stringValues = new String[values.length];
     92             for (int i = 0; i < values.length; ++i) {
     93                 char value = values[i];
     94                 if (value == '\uffff') {
     95                     stringValues[i] = NULL_NAME;
     96                 } else {
     97                     stringValues[i] = ctos(value);
     98                 }
     99             }
    100             internalStringArray(name, stringValues);
    101         }
    102     }
    103 
    104     @Override
    105     public void namedIndex(String name, String[] names, int value) {
    106         if (value >= 0) {
    107             internalString(name, names[value]);
    108         }
    109     }
    110 
    111     @Override
    112     public void namedIndexArray(String name, String[] names, byte[] values) {
    113         if (values != null) {
    114             String[] stringValues = new String[values.length];
    115             for (int i = 0; i < values.length; ++i) {
    116                 int value = values[i];
    117                 if (value < 0) {
    118                     stringValues[i] = NULL_NAME;
    119                 } else {
    120                     stringValues[i] = names[value];
    121                 }
    122             }
    123             internalStringArray(name, stringValues);
    124         }
    125     }
    126 
    127     public static String normalize(String str) {
    128         if (str == null) {
    129             return null;
    130         }
    131         StringBuilder sb = null;
    132         boolean inWhitespace = false;
    133         char c = '\0';
    134         boolean special = false;
    135         for (int i = 0; i < str.length(); ++i) {
    136             c = str.charAt(i);
    137             if (UCharacter.isWhitespace(c)) {
    138                 if (sb == null && (inWhitespace || c != ' ')) {
    139                     sb = new StringBuilder(str.substring(0, i));
    140                 }
    141                 if (inWhitespace) {
    142                     continue;
    143                 }
    144                 inWhitespace = true;
    145                 special = false;
    146                 c = ' ';
    147             } else {
    148                 inWhitespace = false;
    149                 special = c == '<' || c == '&';
    150                 if (special && sb == null) {
    151                     sb = new StringBuilder(str.substring(0, i));
    152                 }
    153             }
    154             if (sb != null) {
    155                 if (special) {
    156                     sb.append(c == '<' ? "&lt;" : "&amp;");
    157                 } else {
    158                     sb.append(c);
    159                 }
    160             }
    161         }
    162         if (sb != null) {
    163             /*
    164              * if (c == ' ') { int len = sb.length(); if (len == 0) { return
    165              * " "; } if (len > 1 && c == ' ') { sb.deleteCharAt(len - 1); } }
    166              */
    167             return sb.toString();
    168         }
    169         return str;
    170     }
    171 
    172     private void internalString(String name, String normalizedValue) {
    173         if (normalizedValue != null) {
    174             newline();
    175             writeString("<" + name + ">" + normalizedValue + "</" + name + ">");
    176         }
    177     }
    178 
    179     private void internalStringArray(String name, String[] normalizedValues) {
    180         if (normalizedValues != null) {
    181             push(name + "List");
    182             for (int i = 0; i < normalizedValues.length; ++i) {
    183                 String value = normalizedValues[i];
    184                 if (value == null) {
    185                     value = NULL_NAME;
    186                 }
    187                 string(name, value);
    188             }
    189             pop();
    190         }
    191     }
    192 
    193     @Override
    194     public void string(String name, String value) {
    195         internalString(name, normalize(value));
    196     }
    197 
    198     @Override
    199     public void stringArray(String name, String[] values) {
    200         if (values != null) {
    201             push(name + "List");
    202             for (int i = 0; i < values.length; ++i) {
    203                 String value = normalize(values[i]);
    204                 if (value == null) {
    205                     value = NULL_NAME;
    206                 }
    207                 internalString(name, value);
    208             }
    209             pop();
    210         }
    211     }
    212 
    213     @Override
    214     public void stringTable(String name, String[][] values) {
    215         if (values != null) {
    216             push(name + "Table");
    217             for (int i = 0; i < values.length; ++i) {
    218                 String[] rowValues = values[i];
    219                 if (rowValues == null) {
    220                     internalString(name + "List", NULL_NAME);
    221                 } else {
    222                     stringArray(name, rowValues);
    223                 }
    224             }
    225             pop();
    226         }
    227     }
    228 
    229     private void push(String name) {
    230         newline();
    231         writeString("<" + name + ">");
    232         nameStack.add(name);
    233     }
    234 
    235     private void pop() {
    236         int ix = nameStack.size() - 1;
    237         String name = nameStack.remove(ix);
    238         newline();
    239         writeString("</" + name + ">");
    240     }
    241 
    242     private void newline() {
    243         writeString("\n");
    244         for (int i = 0; i < nameStack.size(); ++i) {
    245             writeString(INDENT);
    246         }
    247     }
    248 
    249     private void writeString(String str) {
    250         if (w != null) {
    251             try {
    252                 w.write(str);
    253             } catch (IOException e) {
    254                 // if there's a problem, record it and stop writing
    255                 System.err.println(e.getMessage());
    256                 w = null;
    257             }
    258         }
    259     }
    260 
    261     static final String NULL_NAME = "Null";
    262     private static final String INDENT = "    ";
    263 }
    264