OSDN Git Service

use String constants.
[mikutoga/TogaGem.git] / src / main / java / jp / sfjp / mikutoga / xml / DatatypeIo.java
1 /*
2  * XML Schema datatypes input/output
3  *
4  * License : The MIT License
5  * Copyright(c) 2019 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.xml;
9
10 /**
11  * XSD datatypes I/O utilities.
12  *
13  * <p>This class replaces javax.xml.bind.DatatypeConverter(JAXB) subset.
14  * JAXB is not part of JDK9 or later.
15  *
16  * @see <a href="https://www.w3.org/TR/xmlschema-2/">
17  * XML Schema Part 2: Datatypes Second Edition
18  * </a>
19  * @see <a href="https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/DatatypeConverter.html">
20  * JavaSE8:DatatypeConverter
21  * </a>
22  */
23 public final class DatatypeIo {
24
25     private static final String XSD_POS_INF = "INF";
26     private static final String XSD_NEG_INF = "-INF";
27     private static final String JAVA_INF = "Infinity";
28
29
30     /**
31      * Hidden constructor.
32      */
33     private DatatypeIo(){
34         assert false;
35     }
36
37     /**
38      * Converts an int value into a string as xsd:int.
39      *
40      * @param iVal int value
41      * @return xsd:int type text
42      */
43     public static String printInt(int iVal){
44         String result;
45         result = String.valueOf(iVal);
46         return result;
47     }
48
49     /**
50      * Converts an float value into a string as xsd:float.
51      *
52      * <p>Infinite value will be "INF".
53      *
54      * @param fVal float value
55      * @return xsd:float type text
56      */
57     public static String printFloat(float fVal){
58         String result;
59
60         if(fVal == Float.POSITIVE_INFINITY){
61             result = XSD_POS_INF;
62         }else if(fVal == Float.NEGATIVE_INFINITY){
63             result = XSD_NEG_INF;
64         }else{
65             result = String.valueOf(fVal);
66         }
67
68         return result;
69     }
70
71     /**
72      * trimming whitespace around XSD datatypes value.
73      *
74      * @param txt XSD value
75      * @return trimmed text
76      */
77     public static CharSequence xsdTrim(CharSequence txt){
78         int length = txt.length();
79         int startPos = 0;
80         int endPos = length;
81
82         for(int pt = 0; pt < length; pt++){
83             char ch = txt.charAt(pt);
84             if(!isXsdWhitespace(ch)){
85                 startPos = pt;
86                 break;
87             }
88         }
89
90         for(int pt = length - 1; pt >= 0; pt--){
91             char ch = txt.charAt(pt);
92             if(!isXsdWhitespace(ch)){
93                 endPos = pt + 1;
94                 break;
95             }
96         }
97
98         CharSequence result = txt.subSequence(startPos, endPos);
99
100         return result;
101     }
102
103     /**
104      * checking whitespace character around XSD datattypes.
105      *
106      * <p>\n, \r, \t, and &#x5c;0020 are whitespace.
107      *
108      * @param ch character
109      * @return true if whitespace
110      */
111     public static boolean isXsdWhitespace(char ch){
112         boolean result;
113
114         switch(ch){
115         case '\n':
116         case '\r':
117         case '\t':
118         case '\u0020':
119             result = true;
120             break;
121         default:
122             result = false;
123             break;
124         }
125
126         return result;
127     }
128
129     /**
130      * Converts the xsd:boolean string argument into a boolean value.
131      *
132      * <p>{"true", "1"} is true. {"false", "0"} is false.
133      *
134      * @param xsdVal xsd:boolean string
135      * @return true if true
136      * @throws IllegalArgumentException illegal xsd:boolean string
137      */
138     public static boolean parseBoolean(CharSequence xsdVal)
139             throws IllegalArgumentException{
140         boolean result;
141
142         CharSequence trimmed = xsdTrim(xsdVal);
143
144         if("true".contentEquals(trimmed)){
145             result = true;
146         }else if("false".contentEquals(trimmed)){
147             result = false;
148         }else if("0".contentEquals(trimmed)){
149             result = false;
150         }else if("1".contentEquals(trimmed)){
151             result = true;
152         }else{
153             throw new IllegalArgumentException(trimmed.toString());
154         }
155
156         return result;
157     }
158
159     /**
160      * Converts the xsd:byte string argument into a byte value.
161      *
162      * @param xsdVal xsd:byte string
163      * @return byte value
164      * @throws NumberFormatException illegal xsd:byte
165      */
166     public static byte parseByte(CharSequence xsdVal)
167             throws NumberFormatException{
168         CharSequence trimmed = xsdTrim(xsdVal);
169
170         int iVal;
171         iVal = Integer.parseInt(trimmed.toString());
172
173         if(iVal < -128 || 127 < iVal){
174             throw new NumberFormatException(xsdVal.toString());
175         }
176
177         byte result;
178         result = (byte)iVal;
179
180         return result;
181     }
182
183     /**
184      * Converts the xsd:int string argument into a int value.
185      *
186      * @param xsdVal xsd:int string
187      * @return int value
188      * @throws NumberFormatException illegal xsd:int
189      */
190     public static int parseInt(CharSequence xsdVal)
191             throws NumberFormatException{
192         CharSequence trimmed = xsdTrim(xsdVal);
193         int result;
194         result = Integer.parseInt(trimmed.toString());
195         return result;
196     }
197
198     /**
199      * Converts the xsd:float string argument into a float value.
200      *
201      * @param xsdVal xsd:float string
202      * @return float value
203      * @throws NumberFormatException illegal xsd:float
204      */
205     public static float parseFloat(CharSequence xsdVal)
206             throws NumberFormatException{
207         String trimmed = xsdTrim(xsdVal).toString();
208
209         float result;
210         if(XSD_POS_INF.equals(trimmed)){
211             result = Float.POSITIVE_INFINITY;
212         }else if(XSD_NEG_INF.equals(trimmed)){
213             result = Float.NEGATIVE_INFINITY;
214         }else if(trimmed.endsWith(JAVA_INF)){
215             throw new NumberFormatException(trimmed);
216         }else if(trimmed.contains("x") || trimmed.contains("X")){
217             // HexFloatingPointLiteral
218             throw new NumberFormatException(trimmed);
219         }else{
220             // zero will happen when underflow.
221             // infinite will happen when overflow.
222             // NaN is NaN.
223             // -0 is minus zero.
224             result = Float.parseFloat(trimmed);
225         }
226
227         return result;
228     }
229
230 }