OSDN Git Service

000c43ed4faa724551904d71aa10f4c4886ab0a5
[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     /**
26      * Hidden constructor.
27      */
28     private DatatypeIo(){
29         assert false;
30     }
31
32     /**
33      * Converts an int value into a string as xsd:int.
34      *
35      * @param iVal int value
36      * @return xsd:int type text
37      */
38     public static String printInt(int iVal){
39         String result;
40         result = String.valueOf(iVal);
41         return result;
42     }
43
44     /**
45      * Converts an float value into a string as xsd:float.
46      *
47      * <p>Infinite value will be "INF".
48      *
49      * @param fVal float value
50      * @return xsd:float type text
51      */
52     public static String printFloat(float fVal){
53         String result;
54
55         if(fVal == Float.POSITIVE_INFINITY){
56             result = "INF";
57         }else if(fVal == Float.NEGATIVE_INFINITY){
58             result = "-INF";
59         }else{
60             result = String.valueOf(fVal);
61         }
62
63         return result;
64     }
65
66     /**
67      * trimming whitespace around XSD datatypes value.
68      *
69      * @param txt XSD value
70      * @return trimmed text
71      */
72     public static CharSequence xsdTrim(CharSequence txt){
73         int length = txt.length();
74         int startPos = 0;
75         int endPos = length;
76
77         for(int pt = 0; pt < length; pt++){
78             char ch = txt.charAt(pt);
79             if(!isXsdWhitespace(ch)){
80                 startPos = pt;
81                 break;
82             }
83         }
84
85         for(int pt = length - 1; pt >= 0; pt--){
86             char ch = txt.charAt(pt);
87             if(!isXsdWhitespace(ch)){
88                 endPos = pt + 1;
89                 break;
90             }
91         }
92
93         CharSequence result = txt.subSequence(startPos, endPos);
94
95         return result;
96     }
97
98     /**
99      * checking whitespace character around XSD datattypes.
100      *
101      * <p>\n, \r, \t, and &#x5c;0020 are whitespace.
102      *
103      * @param ch character
104      * @return true if whitespace
105      */
106     public static boolean isXsdWhitespace(char ch){
107         boolean result;
108
109         switch(ch){
110         case '\n':
111         case '\r':
112         case '\t':
113         case '\u0020':
114             result = true;
115             break;
116         default:
117             result = false;
118             break;
119         }
120
121         return result;
122     }
123
124     /**
125      * Converts the xsd:boolean string argument into a boolean value.
126      *
127      * <p>{"true", "1"} is true. {"false", "0"} is false.
128      *
129      * @param xsdVal xsd:boolean string
130      * @return true if true
131      * @throws IllegalArgumentException illegal xsd:boolean string
132      */
133     public static boolean parseBoolean(CharSequence xsdVal)
134             throws IllegalArgumentException{
135         boolean result;
136
137         CharSequence trimmed = xsdTrim(xsdVal);
138
139         if("true".contentEquals(trimmed)){
140             result = true;
141         }else if("false".contentEquals(trimmed)){
142             result = false;
143         }else if("0".contentEquals(trimmed)){
144             result = false;
145         }else if("1".contentEquals(trimmed)){
146             result = true;
147         }else{
148             throw new IllegalArgumentException(trimmed.toString());
149         }
150
151         return result;
152     }
153
154     /**
155      * Converts the xsd:byte string argument into a byte value.
156      *
157      * @param xsdVal xsd:byte string
158      * @return byte value
159      * @throws NumberFormatException illegal xsd:byte
160      */
161     public static byte parseByte(CharSequence xsdVal)
162             throws NumberFormatException{
163         CharSequence trimmed = xsdTrim(xsdVal);
164
165         int iVal;
166         iVal = Integer.parseInt(trimmed.toString());
167
168         if(iVal < -128 || 127 < iVal){
169             throw new NumberFormatException(xsdVal.toString());
170         }
171
172         byte result;
173         result = (byte)iVal;
174
175         return result;
176     }
177
178     /**
179      * Converts the xsd:int string argument into a int value.
180      *
181      * @param xsdVal xsd:int string
182      * @return int value
183      * @throws NumberFormatException illegal xsd:int
184      */
185     public static int parseInt(CharSequence xsdVal)
186             throws NumberFormatException{
187         CharSequence trimmed = xsdTrim(xsdVal);
188         int result;
189         result = Integer.parseInt(trimmed.toString());
190         return result;
191     }
192
193     /**
194      * Converts the xsd:float string argument into a float value.
195      *
196      * @param xsdVal xsd:float string
197      * @return float value
198      * @throws NumberFormatException illegal xsd:float
199      */
200     public static float parseFloat(CharSequence xsdVal)
201             throws NumberFormatException{
202         String trimmed = xsdTrim(xsdVal).toString();
203
204         float result;
205         if("INF".equals(trimmed)){
206             result = Float.POSITIVE_INFINITY;
207         }else if("-INF".equals(trimmed)){
208             result = Float.NEGATIVE_INFINITY;
209         }else if(trimmed.endsWith("Infinity")){
210             throw new NumberFormatException(trimmed);
211         }else if(trimmed.contains("x") || trimmed.contains("X")){
212             // HexFloatingPointLiteral
213             throw new NumberFormatException(trimmed);
214         }else{
215             // zero will happen when underflow.
216             // infinite will happen when overflow.
217             // NaN is NaN.
218             // -0 is minus zero.
219             result = Float.parseFloat(trimmed);
220         }
221
222         return result;
223     }
224
225 }