• R/O
  • SSH

TogaGem: Commit

TogaGemは、3D動画制作ツール、MikuMikuDance(MMD)で用いられる各種データファイルを読み書きするためのJavaライブラリです。
旧TogaParserライブラリの資産は、TogaGemライブラリに吸収されました。


Commit MetaInfo

Revisionec69393f6ebc1aebfd4758a16bda221828bc6fac (tree)
Zeit2013-06-08 13:30:16
Autor <olyutorskii@user...>

Log Message

MMD Ver7.40 対応

Ändern Zusammenfassung

Diff

diff -r 35f967fe1b71 -r ec69393f6ebc CHANGELOG.txt
--- a/CHANGELOG.txt Tue May 21 23:10:18 2013 +0900
+++ b/CHANGELOG.txt Sat Jun 08 13:30:16 2013 +0900
@@ -9,6 +9,7 @@
99 ・ジンバルロック判定を甘くした。
1010 ・多言語対応に際してデフォルトロケールへのフォールバックを禁止。
1111 ・コールバックpmdIKInfo()がpmdIKChainInfo()より先に呼ばれるよう変更。
12+ ・MikuMikuDance Ver7.40以降の新VMDファイルフォーマットに対応
1213
1314 2.102.2 (2013-03-17)
1415 ・Maven3対応。
diff -r 35f967fe1b71 -r ec69393f6ebc pom.xml
--- a/pom.xml Tue May 21 23:10:18 2013 +0900
+++ b/pom.xml Sat Jun 08 13:30:16 2013 +0900
@@ -16,7 +16,7 @@
1616 <groupId>jp.sourceforge.mikutoga</groupId>
1717 <artifactId>togagem</artifactId>
1818
19- <version>2.102.5-SNAPSHOT</version>
19+ <version>2.102.7-SNAPSHOT</version>
2020
2121 <packaging>jar</packaging>
2222 <name>TogaGem</name>
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/vmd/VmdConst.java
--- a/src/main/java/jp/sfjp/mikutoga/vmd/VmdConst.java Tue May 21 23:10:18 2013 +0900
+++ b/src/main/java/jp/sfjp/mikutoga/vmd/VmdConst.java Sat Jun 08 13:30:16 2013 +0900
@@ -37,6 +37,13 @@
3737 */
3838 public static final int MORPHNAME_MAX = 15;
3939
40+ /**
41+ * IK ON/OFFスイッチ用ボーン名最大長。バイト単位。
42+ * <p>※MikuMikuDance Ver7.40からの機能。
43+ * <p>モーション指定用ボーン名と長さが違うので注意。
44+ */
45+ public static final int IKSWBONENAME_MAX = 20;
46+
4047
4148 /**
4249 * 隠しコンストラクタ。
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdBoolHandler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdBoolHandler.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,52 @@
1+/*
2+ * VMD boolean info handler
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2013 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.vmd.parser;
9+
10+import jp.sfjp.mikutoga.bin.parser.LoopHandler;
11+import jp.sfjp.mikutoga.bin.parser.MmdFormatException;
12+import jp.sfjp.mikutoga.bin.parser.ParseStage;
13+
14+/**
15+ * VMDモーションファイルの各種ON/OFF情報(モデル表示・IK有効無効)
16+ * の通知用ハンドラ。
17+ * <p>MikuMikuDance Ver7.40よりVMDファイルに導入された新仕様。
18+ */
19+public interface VmdBoolHandler extends LoopHandler {
20+
21+ /** モデル表示スイッチ抽出ループ識別子。 */
22+ ParseStage MODELSIGHT_LIST = new ParseStage();
23+
24+ /** IK有効スイッチ抽出ループ識別子。 */
25+ ParseStage IKSW_LIST = new ParseStage();
26+
27+
28+ /**
29+ * モデルの表示フラグを通知する。
30+ * <p>{@link #MODELSIGHT_LIST}ループの構成要素。
31+ * @param show モデルの表示が行われる場合true
32+ * @param keyFrameNo キーフレーム番号
33+ * @throws MmdFormatException 不正フォーマットによる
34+ * パース処理の中断をパーサに指示
35+ */
36+ void vmdModelSight(boolean show, int keyFrameNo)
37+ throws MmdFormatException;
38+
39+ /**
40+ * IKボーン別のIK処理のON/OFFを通知する。
41+ * <p>{@link #MODELSIGHT_LIST}ループの下位
42+ * {@link #IKSW_LIST}ループの構成要素。
43+ * @param boneName IKボーン名
44+ * @param validIk IK処理が無効になる場合false
45+ * @param keyFrameNo キーフレーム番号
46+ * @throws MmdFormatException 不正フォーマットによる
47+ * パース処理の中断をパーサに指示
48+ */
49+ void vmdIkSwitch(String boneName, boolean validIk, int keyFrameNo)
50+ throws MmdFormatException;
51+
52+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdBoolParser.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdBoolParser.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,121 @@
1+/*
2+ * VMD boolean data parser
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2013 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.vmd.parser;
9+
10+import java.io.IOException;
11+import jp.sfjp.mikutoga.bin.parser.BinParser;
12+import jp.sfjp.mikutoga.bin.parser.MmdFormatException;
13+import jp.sfjp.mikutoga.bin.parser.ProxyParser;
14+import jp.sfjp.mikutoga.bin.parser.TextDecoder;
15+import jp.sfjp.mikutoga.vmd.VmdConst;
16+
17+/**
18+ * VMDモーションファイルの各種ON/OFF情報(モデル表示・IK有効無効)
19+ * パーサ。
20+ * <p>MikuMikuDance Ver7.40以降でサポート
21+ */
22+class VmdBoolParser extends ProxyParser {
23+
24+ private final TextDecoder decoderWin31j =
25+ new TextDecoder(VmdBasicParser.CS_WIN31J);
26+
27+ private VmdBoolHandler handler = VmdUnifiedHandler.EMPTY;
28+
29+
30+ /**
31+ * コンストラクタ。
32+ * @param parser 委譲先パーサ
33+ */
34+ VmdBoolParser(BinParser parser){
35+ super(parser);
36+ this.decoderWin31j.setZeroChopMode(true);
37+ return;
38+ }
39+
40+
41+ /**
42+ * ON/OFF情報通知用ハンドラを登録する。
43+ * @param boolHandler ハンドラ
44+ */
45+ void setBoolHandler(VmdBoolHandler boolHandler){
46+ if(boolHandler == null){
47+ this.handler = VmdUnifiedHandler.EMPTY;
48+ }else{
49+ this.handler = boolHandler;
50+ }
51+
52+ return;
53+ }
54+
55+ /**
56+ * データのパースと通知。
57+ * @throws IOException IOエラー
58+ * @throws MmdFormatException フォーマットエラー
59+ */
60+ void parse() throws IOException, MmdFormatException {
61+ if( ! hasMore() ) return;
62+
63+ parseVmdModelSight();
64+
65+ return;
66+ }
67+
68+ /**
69+ * モデル表示フラグデータのパースと通知。
70+ * @throws IOException IOエラー
71+ * @throws MmdFormatException フォーマットエラー
72+ */
73+ private void parseVmdModelSight()
74+ throws IOException, MmdFormatException{
75+ int modelSightNo = parseLeInt();
76+
77+ this.handler.loopStart(VmdBoolHandler.MODELSIGHT_LIST,
78+ modelSightNo );
79+
80+ for(int ct = 0; ct < modelSightNo; ct++){
81+ int keyFrameNo = parseLeInt();
82+ boolean show = parseBoolean();
83+ this.handler.vmdModelSight(show, keyFrameNo);
84+
85+ parseVmdIkSwitch(keyFrameNo);
86+
87+ this.handler.loopNext(VmdBoolHandler.MODELSIGHT_LIST);
88+ }
89+
90+ this.handler.loopEnd(VmdBoolHandler.MODELSIGHT_LIST);
91+
92+ return;
93+ }
94+
95+ /**
96+ * IK有効スイッチデータのパースと通知。
97+ * @param keyFrameNo キーフレーム番号
98+ * @throws IOException IOエラー
99+ * @throws MmdFormatException フォーマットエラー
100+ */
101+ private void parseVmdIkSwitch(int keyFrameNo)
102+ throws IOException, MmdFormatException{
103+ int ikSwitchNo = parseLeInt();
104+
105+ this.handler.loopStart(VmdBoolHandler.IKSW_LIST, ikSwitchNo);
106+
107+ for(int ct = 0; ct < ikSwitchNo; ct++){
108+ String boneName = parseString(this.decoderWin31j,
109+ VmdConst.IKSWBONENAME_MAX );
110+ boolean valid = parseBoolean();
111+ this.handler.vmdIkSwitch(boneName, valid, keyFrameNo);
112+
113+ this.handler.loopNext(VmdBoolHandler.IKSW_LIST);
114+ }
115+
116+ this.handler.loopEnd(VmdBoolHandler.IKSW_LIST);
117+
118+ return;
119+ }
120+
121+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdParser.java
--- a/src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdParser.java Tue May 21 23:10:18 2013 +0900
+++ b/src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdParser.java Sat Jun 08 13:30:16 2013 +0900
@@ -23,10 +23,10 @@
2323 private final VmdBasicParser basicParser;
2424 private final VmdCameraParser cameraParser;
2525 private final VmdLightingParser lightingParser;
26+ private final VmdBoolParser boolParser;
2627
2728 private VmdBasicHandler basicHandler = VmdUnifiedHandler.EMPTY;
2829
29- private boolean ignoreName = true;
3030 private boolean redundantCheck = false;
3131
3232
@@ -46,6 +46,7 @@
4646 this.basicParser = new VmdBasicParser(parser);
4747 this.cameraParser = new VmdCameraParser(parser);
4848 this.lightingParser = new VmdLightingParser(parser);
49+ this.boolParser = new VmdBoolParser(parser);
4950
5051 return;
5152 }
@@ -94,15 +95,11 @@
9495 }
9596
9697 /**
97- * カメラ・ライティングデータのパースを試みるか否かの判断で、
98- * 特殊モデル名判定を無視するか否か設定する。
99- * デフォルトではモデル名を無視。
100- * <p>※MMDVer7.30前後のVMD出力不具合を回避したい場合は、
101- * オフにするとパースに成功する場合がある。
102- * @param mode モデル名を無視するならtrue
98+ * ON/OFF情報通知用ハンドラを登録する。
99+ * @param boolHandler ハンドラ
103100 */
104- public void setIgnoreName(boolean mode){
105- this.ignoreName = mode;
101+ public void setBoolHandler(VmdBoolHandler boolHandler){
102+ this.boolParser.setBoolHandler(boolHandler);
106103 return;
107104 }
108105
@@ -111,6 +108,7 @@
111108 * デフォルトではチェックを行わない。
112109 * <p>※MMDVer7.30前後のVMD出力不具合を回避したい場合は、
113110 * オフにするとパースに成功する場合がある。
111+ * <p>※MMD Ver7.39x64以降はチェック回避必須。
114112 * @param mode チェックさせたければtrue
115113 */
116114 public void setRedundantCheck(boolean mode){
@@ -125,7 +123,6 @@
125123 * @throws MmdFormatException フォーマットエラー
126124 */
127125 public void parseVmd() throws IOException, MmdFormatException {
128- setIgnoreName(this.ignoreName);
129126 setRedundantCheck(this.redundantCheck);
130127
131128 this.basicHandler.vmdParseStart();
@@ -140,20 +137,21 @@
140137
141138 /**
142139 * VMDファイル本体のパースを開始する。
143- * <p>モデル名がボーンモーション用と推測され、
144- * かつパーサがStrict-modeでない場合、
145- * カメラ、ライティングデータのパースは行われない。
146140 * @throws IOException IOエラー
147141 * @throws MmdFormatException フォーマットエラー
148142 */
149143 private void parseBody() throws IOException, MmdFormatException{
150144 this.basicParser.parse();
151145
152- if(this.basicParser.hasStageActName() || this.ignoreName){
146+ if(this.cameraParser.hasMore()){
153147 this.cameraParser.parse();
154148 this.lightingParser.parse();
155149 }
156150
151+ if(this.boolParser.hasMore()){
152+ this.boolParser.parse();
153+ }
154+
157155 return;
158156 }
159157
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdUnifiedHandler.java
--- a/src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdUnifiedHandler.java Tue May 21 23:10:18 2013 +0900
+++ b/src/main/java/jp/sfjp/mikutoga/vmd/parser/VmdUnifiedHandler.java Sat Jun 08 13:30:16 2013 +0900
@@ -15,7 +15,8 @@
1515 public interface VmdUnifiedHandler
1616 extends VmdBasicHandler,
1717 VmdCameraHandler,
18- VmdLightingHandler {
18+ VmdLightingHandler,
19+ VmdBoolHandler {
1920
2021 /** 何もしない統合ハンドラ。 */
2122 VmdUnifiedHandler EMPTY =
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/AbstractXmlExporter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/AbstractXmlExporter.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,699 @@
1+/*
2+ * abstract xml exporter
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2013 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.io.IOException;
11+import java.util.regex.Matcher;
12+import java.util.regex.Pattern;
13+import javax.xml.bind.DatatypeConverter;
14+
15+/**
16+ * Appendable実装に依存したXMLエクスポータの半実装。
17+ * UCS4は未サポート。
18+ */
19+abstract class AbstractXmlExporter implements XmlExporter{
20+
21+ /** デフォルトの改行文字列。 */
22+ private static final String DEF_NL = "\n"; // 0x0a(LF)
23+ /** デフォルトのインデント単位。 */
24+ private static final String DEF_INDENT_UNIT = "\u0020\u0020"; // ␣␣
25+
26+ private static final char CH_SP = '\u0020'; // ␣
27+ private static final char CH_YEN = '\u00a5'; // ¥
28+ private static final char CH_BSLASH = (char)0x005c; // \
29+ private static final char CH_DQ = '\u0022'; // "
30+ private static final char CH_SQ = (char)0x0027; // '
31+ private static final char CH_EQ = '='; // =
32+ private static final char CH_LT = '<';
33+ private static final char CH_GT = '>';
34+
35+ private static final String COMM_START = "<!--";
36+ private static final String COMM_END = "-->";
37+
38+ private static final Pattern NUM_FUZZY =
39+ Pattern.compile("([^.]*\\.[0-9][0-9]*?)0+");
40+
41+ private static final String REF_HEX = "&#x";
42+ private static final int HEX_EXP = 4; // 2 ** 4 == 16
43+ private static final int MASK_1HEX = (1 << HEX_EXP) - 1; // 0b00001111
44+ private static final int MAX_OCTET = (1 << Byte.SIZE) - 1; // 0xff
45+ private static final char[] HEXCHAR_TABLE = {
46+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
47+ 'A', 'B', 'C', 'D', 'E', 'F',
48+ };
49+
50+ static{
51+ assert HEX_EXP * 2 == Byte.SIZE;
52+ assert HEXCHAR_TABLE.length == (1 << HEX_EXP);
53+ }
54+
55+
56+ private boolean basicLatinOnlyOut = true;
57+ private String newline = DEF_NL;
58+ private String indentUnit = DEF_INDENT_UNIT;
59+ private int indentNest = 0;
60+
61+
62+ /**
63+ * コンストラクタ。
64+ */
65+ protected AbstractXmlExporter(){
66+ super();
67+ return;
68+ }
69+
70+
71+ /**
72+ * ASCIIコード相当(UCS:Basic-Latin)の文字か否か判定する。
73+ * <p>※ Basic-Latinには各種制御文字も含まれる。
74+ * @param ch 判定対象文字
75+ * @return Basic-Latin文字ならtrue
76+ * <a href="http://www.unicode.org/charts/PDF/U0000.pdf">
77+ * Unicode 6.2 Controls and Basic Latin
78+ * </a>
79+ */
80+ protected static boolean isBasicLatin(char ch){
81+ if('\u0000' <= ch && ch <= '\u007f'){
82+ return true;
83+ }
84+ return false;
85+ }
86+
87+ /**
88+ * 冗長な実数出力を抑止する。
89+ * <p>DatatypeConverterにおけるJDK1.6系と1.7系の仕様変更を吸収する。
90+ * <p>0.001fは"0.0010"ではなく"0.001"と出力される。
91+ * <p>指数表記での冗長桁は無視する。
92+ * @param numTxt 実数表記
93+ * @return 冗長桁が抑止された実数表記
94+ * @see javax.xml.bind.DatatypeConverter
95+ */
96+ protected static String chopFuzzyZero(String numTxt){
97+ String result;
98+
99+ Matcher matcher = NUM_FUZZY.matcher(numTxt);
100+ if(matcher.matches()){
101+ result = matcher.group(1);
102+ }else{
103+ result = numTxt;
104+ }
105+
106+ return result;
107+ }
108+
109+
110+ /**
111+ * {@inheritDoc}
112+ * @param ch {@inheritDoc}
113+ * @return {@inheritDoc}
114+ * @throws IOException {@inheritDoc}
115+ */
116+ @Override
117+ public abstract Appendable append(char ch) throws IOException;
118+
119+ /**
120+ * {@inheritDoc}
121+ * @param seq {@inheritDoc}
122+ * @return {@inheritDoc}
123+ * @throws IOException {@inheritDoc}
124+ */
125+ @Override
126+ public abstract Appendable append(CharSequence seq) throws IOException;
127+
128+ /**
129+ * {@inheritDoc}
130+ * @param seq {@inheritDoc}
131+ * @param start {@inheritDoc}
132+ * @param end {@inheritDoc}
133+ * @return {@inheritDoc}
134+ * @throws IOException {@inheritDoc}
135+ */
136+ @Override
137+ public abstract Appendable append(CharSequence seq, int start, int end)
138+ throws IOException;
139+
140+ /**
141+ * {@inheritDoc}
142+ * @throws IOException {@inheritDoc}
143+ */
144+ @Override
145+ public abstract void flush() throws IOException;
146+
147+ /**
148+ * {@inheritDoc}
149+ * @throws IOException {@inheritDoc}
150+ */
151+ @Override
152+ public abstract void close() throws IOException;
153+
154+
155+ /**
156+ * {@inheritDoc}
157+ * @param ch {@inheritDoc}
158+ * @return {@inheritDoc}
159+ * @throws IOException {@inheritDoc}
160+ */
161+ @Override
162+ public XmlExporter putRawCh(char ch) throws IOException{
163+ append(ch);
164+ return this;
165+ }
166+
167+ /**
168+ * {@inheritDoc}
169+ * @param seq {@inheritDoc}
170+ * @return {@inheritDoc}
171+ * @throws IOException {@inheritDoc}
172+ */
173+ @Override
174+ public XmlExporter putRawText(CharSequence seq)
175+ throws IOException{
176+ append(seq);
177+ return this;
178+ }
179+
180+ /**
181+ * {@inheritDoc}
182+ * @return {@inheritDoc}
183+ * @throws IOException {@inheritDoc}
184+ */
185+ @Override
186+ public XmlExporter sp() throws IOException{
187+ putRawCh(CH_SP);
188+ return this;
189+ }
190+
191+ /**
192+ * {@inheritDoc}
193+ * @param count {@inheritDoc}
194+ * @return {@inheritDoc}
195+ * @throws IOException {@inheritDoc}
196+ */
197+ @Override
198+ public XmlExporter sp(int count) throws IOException{
199+ for(int ct = 1; ct <= count; ct++){
200+ sp();
201+ }
202+ return this;
203+ }
204+
205+ /**
206+ * {@inheritDoc}
207+ * @return {@inheritDoc}
208+ */
209+ @Override
210+ public String getNewLine(){
211+ return this.newline;
212+ }
213+
214+ /**
215+ * {@inheritDoc}
216+ * @param newLine {@inheritDoc}
217+ * @throws NullPointerException {@inheritDoc}
218+ */
219+ @Override
220+ public void setNewLine(String newLine) throws NullPointerException{
221+ if(newLine == null) throw new NullPointerException();
222+ this.newline = newLine;
223+ return;
224+ }
225+
226+ /**
227+ * {@inheritDoc}
228+ * @return {@inheritDoc}
229+ * @throws IOException {@inheritDoc}
230+ */
231+ @Override
232+ public XmlExporter ln() throws IOException{
233+ putRawText(getNewLine());
234+ return this;
235+ }
236+
237+ /**
238+ * {@inheritDoc}
239+ * @param count {@inheritDoc}
240+ * @return {@inheritDoc}
241+ * @throws IOException {@inheritDoc}
242+ */
243+ @Override
244+ public XmlExporter ln(int count) throws IOException{
245+ for(int ct = 1; ct <= count; ct++){
246+ ln();
247+ }
248+ return this;
249+ }
250+
251+ /**
252+ * {@inheritDoc}
253+ * @return {@inheritDoc}
254+ */
255+ @Override
256+ public String getIndentUnit(){
257+ return this.indentUnit;
258+ }
259+
260+ /**
261+ * {@inheritDoc}
262+ * @param indUnit {@inheritDoc}
263+ * @throws NullPointerException {@inheritDoc}
264+ */
265+ @Override
266+ public void setIndentUnit(String indUnit) throws NullPointerException{
267+ if(indUnit == null) throw new NullPointerException();
268+ this.indentUnit = indUnit;
269+ return;
270+ }
271+
272+ /**
273+ * {@inheritDoc}
274+ */
275+ @Override
276+ public void pushNest(){
277+ this.indentNest++;
278+ return;
279+ }
280+
281+ /**
282+ * {@inheritDoc}
283+ */
284+ @Override
285+ public void popNest(){
286+ this.indentNest--;
287+ if(this.indentNest < 0) this.indentNest = 0;
288+ return;
289+ }
290+
291+ /**
292+ * {@inheritDoc}
293+ * @return {@inheritDoc}
294+ */
295+ @Override
296+ public int getIndentLevel(){
297+ return this.indentNest;
298+ }
299+
300+ /**
301+ * {@inheritDoc}
302+ * @return {@inheritDoc}
303+ * @throws IOException {@inheritDoc}
304+ */
305+ @Override
306+ public XmlExporter ind() throws IOException{
307+ int level = getIndentLevel();
308+ for(int ct = 1; ct <= level; ct++){
309+ putRawText(getIndentUnit());
310+ }
311+ return this;
312+ }
313+
314+ /**
315+ * {@inheritDoc}
316+ * @return {@inheritDoc}
317+ */
318+ @Override
319+ public boolean isBasicLatinOnlyOut(){
320+ return this.basicLatinOnlyOut;
321+ }
322+
323+ /**
324+ * {@inheritDoc}
325+ * @param bool {@inheritDoc}
326+ */
327+ @Override
328+ public void setBasicLatinOnlyOut(boolean bool){
329+ this.basicLatinOnlyOut = bool;
330+ return;
331+ }
332+
333+ /**
334+ * {@inheritDoc}
335+ * @param ch {@inheritDoc}
336+ * @return {@inheritDoc}
337+ * @throws IOException {@inheritDoc}
338+ */
339+ @Override
340+ public XmlExporter putCharRef2Hex(char ch) throws IOException{
341+ if(ch > MAX_OCTET) return putCharRef4Hex(ch);
342+
343+ int ibits = ch; // 常に正なので符号拡張なし
344+
345+ int idx4 = ibits & MASK_1HEX;
346+ ibits >>= HEX_EXP;
347+ int idx3 = ibits & MASK_1HEX;
348+
349+ char hex3 = HEXCHAR_TABLE[idx3];
350+ char hex4 = HEXCHAR_TABLE[idx4];
351+
352+ putRawText(REF_HEX).putRawCh(hex3).putRawCh(hex4)
353+ .putRawCh(';');
354+
355+ return this;
356+ }
357+
358+ /**
359+ * {@inheritDoc}
360+ * @param ch {@inheritDoc}
361+ * @return {@inheritDoc}
362+ * @throws IOException {@inheritDoc}
363+ */
364+ @Override
365+ public XmlExporter putCharRef4Hex(char ch) throws IOException{
366+ int ibits = ch; // 常に正なので符号拡張なし
367+
368+ int idx4 = ibits & MASK_1HEX;
369+ ibits >>= HEX_EXP;
370+ int idx3 = ibits & MASK_1HEX;
371+ ibits >>= HEX_EXP;
372+ int idx2 = ibits & MASK_1HEX;
373+ ibits >>= HEX_EXP;
374+ int idx1 = ibits & MASK_1HEX;
375+
376+ char hex1 = HEXCHAR_TABLE[idx1];
377+ char hex2 = HEXCHAR_TABLE[idx2];
378+ char hex3 = HEXCHAR_TABLE[idx3];
379+ char hex4 = HEXCHAR_TABLE[idx4];
380+
381+ putRawText(REF_HEX).putRawCh(hex1).putRawCh(hex2)
382+ .putRawCh(hex3).putRawCh(hex4)
383+ .putRawCh(';');
384+
385+ return this;
386+ }
387+
388+ /**
389+ * {@inheritDoc}
390+ * @param ch {@inheritDoc}
391+ * @return {@inheritDoc}
392+ * @throws IOException {@inheritDoc}
393+ */
394+ @Override
395+ public XmlExporter putCh(char ch) throws IOException{
396+ if(Character.isISOControl(ch)){
397+ putCharRef2Hex(ch);
398+ return this;
399+ }
400+
401+ String escTxt;
402+ switch(ch){
403+ case '&': escTxt = "&amp;"; break;
404+ case CH_LT: escTxt = "&lt;"; break;
405+ case CH_GT: escTxt = "&gt;"; break;
406+ case CH_DQ: escTxt = "&quot;"; break;
407+ case CH_SQ: escTxt = "&apos;"; break;
408+ default: escTxt = null; break;
409+ }
410+
411+ if(escTxt != null){
412+ putRawText(escTxt);
413+ }else{
414+ putRawCh(ch);
415+ }
416+
417+ return this;
418+ }
419+
420+ /**
421+ * {@inheritDoc}
422+ * @param content {@inheritDoc}
423+ * @return {@inheritDoc}
424+ * @throws IOException {@inheritDoc}
425+ */
426+ @Override
427+ public XmlExporter putContent(CharSequence content)
428+ throws IOException{
429+ int length = content.length();
430+
431+ char prev = '\0';
432+ for(int pos = 0; pos < length; pos++){
433+ char ch = content.charAt(pos);
434+
435+ if( isBasicLatinOnlyOut() && ! isBasicLatin(ch) ){
436+ putCharRef4Hex(ch);
437+ }else if(ch == CH_YEN){
438+ putRawCh(CH_BSLASH);
439+ }else if(Character.isSpaceChar(ch)){
440+ if(ch == CH_SP && prev != CH_SP){
441+ putRawCh(ch);
442+ }else{
443+ putCharRef2Hex(ch);
444+ }
445+ }else{
446+ putCh(ch);
447+ }
448+
449+ prev = ch;
450+ }
451+
452+ return this;
453+ }
454+
455+ /**
456+ * {@inheritDoc}
457+ * @param comment {@inheritDoc}
458+ * @return {@inheritDoc}
459+ * @throws IOException {@inheritDoc}
460+ */
461+ @Override
462+ public XmlExporter putCommentContent(CharSequence comment)
463+ throws IOException{
464+ int length = comment.length();
465+
466+ char prev = '\0';
467+ for(int pos = 0; pos < length; pos++){
468+ char ch = comment.charAt(pos);
469+
470+ if(ch == '\n'){
471+ ln();
472+ }else if('\u0000' <= ch && ch <= '\u001f'){
473+ putRawCh((char)('\u2400' + ch));
474+ }else if(ch == '\u007f'){
475+ putRawCh('\u2421');
476+ }else if(prev == '-' && ch == '-'){
477+ sp().putRawCh(ch);
478+ }else{
479+ putRawCh(ch);
480+ }
481+
482+ prev = ch;
483+ }
484+
485+ return this;
486+ }
487+
488+ /**
489+ * {@inheritDoc}
490+ * @param comment {@inheritDoc}
491+ * @return {@inheritDoc}
492+ * @throws IOException {@inheritDoc}
493+ */
494+ @Override
495+ public XmlExporter putLineComment(CharSequence comment)
496+ throws IOException{
497+ putRawText(COMM_START).sp();
498+ putCommentContent(comment);
499+ sp().putRawText(COMM_END);
500+ return this;
501+ }
502+
503+ /**
504+ * {@inheritDoc}
505+ * @param comment {@inheritDoc}
506+ * @return {@inheritDoc}
507+ * @throws IOException {@inheritDoc}
508+ */
509+ @Override
510+ public XmlExporter putBlockComment(CharSequence comment)
511+ throws IOException{
512+ putRawText(COMM_START).ln();
513+
514+ putCommentContent(comment);
515+
516+ int commentLength = comment.length();
517+ if(commentLength > 0){
518+ char lastCh = comment.charAt(commentLength - 1);
519+ if(lastCh != '\n'){
520+ ln();
521+ }
522+ }
523+
524+ putRawText(COMM_END).ln();
525+
526+ return this;
527+ }
528+
529+ /**
530+ * {@inheritDoc}
531+ * @param tagName {@inheritDoc}
532+ * @return {@inheritDoc}
533+ * @throws IOException {@inheritDoc}
534+ */
535+ @Override
536+ public XmlExporter putOpenSTag(CharSequence tagName)
537+ throws IOException{
538+ putRawCh(CH_LT);
539+ putRawText(tagName);
540+ return this;
541+ }
542+
543+ /**
544+ * {@inheritDoc}
545+ * @return {@inheritDoc}
546+ * @throws IOException {@inheritDoc}
547+ */
548+ @Override
549+ public XmlExporter putCloseSTag()
550+ throws IOException{
551+ putRawCh(CH_GT);
552+ return this;
553+ }
554+
555+ /**
556+ * {@inheritDoc}
557+ * @param tagName {@inheritDoc}
558+ * @return {@inheritDoc}
559+ * @throws IOException {@inheritDoc}
560+ */
561+ @Override
562+ public XmlExporter putSimpleSTag(CharSequence tagName)
563+ throws IOException{
564+ putRawCh(CH_LT);
565+ putRawText(tagName);
566+ putRawCh(CH_GT);
567+ return this;
568+ }
569+
570+ /**
571+ * {@inheritDoc}
572+ * @param tagName {@inheritDoc}
573+ * @return {@inheritDoc}
574+ * @throws IOException {@inheritDoc}
575+ */
576+ @Override
577+ public XmlExporter putETag(CharSequence tagName)
578+ throws IOException{
579+ putRawText("</");
580+ putRawText(tagName);
581+ putRawCh(CH_GT);
582+ return this;
583+ }
584+
585+ /**
586+ * {@inheritDoc}
587+ * @param tagName {@inheritDoc}
588+ * @return {@inheritDoc}
589+ * @throws IOException {@inheritDoc}
590+ */
591+ @Override
592+ public XmlExporter putSimpleEmpty(CharSequence tagName)
593+ throws IOException{
594+ putRawCh(CH_LT);
595+ putRawText(tagName).sp();
596+ putCloseEmpty();
597+ return this;
598+ }
599+
600+ /**
601+ * {@inheritDoc}
602+ * @return {@inheritDoc}
603+ * @throws IOException {@inheritDoc}
604+ */
605+ @Override
606+ public XmlExporter putCloseEmpty()
607+ throws IOException{
608+ putRawText("/>");
609+ return this;
610+ }
611+
612+ /**
613+ * {@inheritDoc}
614+ * @param iVal {@inheritDoc}
615+ * @return {@inheritDoc}
616+ * @throws IOException {@inheritDoc}
617+ */
618+ @Override
619+ public XmlExporter putXsdInt(int iVal) throws IOException{
620+ String value = DatatypeConverter.printInt(iVal);
621+ putRawText(value);
622+ return this;
623+ }
624+
625+ /**
626+ * {@inheritDoc}
627+ * @param fVal {@inheritDoc}
628+ * @return {@inheritDoc}
629+ * @throws IOException {@inheritDoc}
630+ */
631+ @Override
632+ public XmlExporter putXsdFloat(float fVal) throws IOException{
633+ String value = DatatypeConverter.printFloat(fVal);
634+ value = chopFuzzyZero(value);
635+ putRawText(value);
636+ return this;
637+ }
638+
639+ /**
640+ * {@inheritDoc}
641+ * @param attrName {@inheritDoc}
642+ * @param iVal {@inheritDoc}
643+ * @return {@inheritDoc}
644+ * @throws IOException {@inheritDoc}
645+ */
646+ @Override
647+ public XmlExporter putIntAttr(CharSequence attrName,
648+ int iVal)
649+ throws IOException{
650+ putRawText(attrName).putRawCh(CH_EQ);
651+
652+ putRawCh(CH_DQ);
653+ putXsdInt(iVal);
654+ putRawCh(CH_DQ);
655+
656+ return this;
657+ }
658+
659+ /**
660+ * {@inheritDoc}
661+ * @param attrName {@inheritDoc}
662+ * @param fVal {@inheritDoc}
663+ * @return {@inheritDoc}
664+ * @throws IOException {@inheritDoc}
665+ */
666+ @Override
667+ public XmlExporter putFloatAttr(CharSequence attrName,
668+ float fVal)
669+ throws IOException{
670+ putRawText(attrName).putRawCh(CH_EQ);
671+
672+ putRawCh(CH_DQ);
673+ putXsdFloat(fVal);
674+ putRawCh(CH_DQ);
675+
676+ return this;
677+ }
678+
679+ /**
680+ * {@inheritDoc}
681+ * @param attrName {@inheritDoc}
682+ * @param content {@inheritDoc}
683+ * @return {@inheritDoc}
684+ * @throws IOException {@inheritDoc}
685+ */
686+ @Override
687+ public XmlExporter putAttr(CharSequence attrName,
688+ CharSequence content)
689+ throws IOException{
690+ putRawText(attrName).putRawCh(CH_EQ);
691+
692+ putRawCh(CH_DQ);
693+ putContent(content);
694+ putRawCh(CH_DQ);
695+
696+ return this;
697+ }
698+
699+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/BasicXmlExporter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/BasicXmlExporter.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,106 @@
1+/*
2+ * basic xml exporter
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2010 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.io.Closeable;
11+import java.io.Flushable;
12+import java.io.IOException;
13+
14+/**
15+ * Appendable用XMLエクスポータ実装。
16+ */
17+public class BasicXmlExporter extends AbstractXmlExporter{
18+
19+ private Appendable appendable = null;
20+
21+
22+ /**
23+ * コンストラクタ。
24+ */
25+ public BasicXmlExporter(){
26+ super();
27+ return;
28+ }
29+
30+
31+ /**
32+ * 出力先アペンダを指定する。
33+ * @param app 出力先
34+ * @throws NullPointerException 引数がnull
35+ */
36+ public void setAppendable(Appendable app) throws NullPointerException{
37+ if(app == null) throw new NullPointerException();
38+
39+ this.appendable = app;
40+
41+ return;
42+ }
43+
44+ /**
45+ * {@inheritDoc}
46+ * @param ch {@inheritDoc}
47+ * @return {@inheritDoc}
48+ * @throws IOException {@inheritDoc}
49+ */
50+ @Override
51+ public Appendable append(char ch) throws IOException{
52+ return this.appendable.append(ch);
53+ }
54+
55+ /**
56+ * {@inheritDoc}
57+ * @param seq {@inheritDoc}
58+ * @return {@inheritDoc}
59+ * @throws IOException {@inheritDoc}
60+ */
61+ @Override
62+ public Appendable append(CharSequence seq) throws IOException{
63+ return this.appendable.append(seq);
64+ }
65+
66+ /**
67+ * {@inheritDoc}
68+ * @param seq {@inheritDoc}
69+ * @param start {@inheritDoc}
70+ * @param end {@inheritDoc}
71+ * @return {@inheritDoc}
72+ * @throws IOException {@inheritDoc}
73+ */
74+ @Override
75+ public Appendable append(CharSequence seq, int start, int end)
76+ throws IOException{
77+ return this.appendable.append(seq, start, end);
78+ }
79+
80+ /**
81+ * {@inheritDoc}
82+ * 可能であれば出力をフラッシュする。
83+ * @throws IOException {@inheritDoc}
84+ */
85+ @Override
86+ public void flush() throws IOException{
87+ if(this.appendable instanceof Flushable){
88+ ((Flushable)this.appendable).flush();
89+ }
90+ return;
91+ }
92+
93+ /**
94+ * {@inheritDoc}
95+ * 可能であれば出力をクローズする。
96+ * @throws IOException {@inheritDoc}
97+ */
98+ @Override
99+ public void close() throws IOException{
100+ if(this.appendable instanceof Closeable){
101+ ((Closeable)this.appendable).close();
102+ }
103+ return;
104+ }
105+
106+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/BotherHandler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/BotherHandler.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,63 @@
1+/*
2+ * XML custom error-handler
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2010 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import org.xml.sax.ErrorHandler;
11+import org.xml.sax.SAXException;
12+import org.xml.sax.SAXParseException;
13+
14+/**
15+ * 自製エラーハンドラ。
16+ * 例外を渡されれば即投げる。
17+ */
18+public final class BotherHandler implements ErrorHandler{
19+
20+ /**
21+ * 唯一のシングルトン。
22+ */
23+ public static final ErrorHandler HANDLER = new BotherHandler();
24+
25+ /**
26+ * 隠しコンストラクタ。
27+ */
28+ private BotherHandler(){
29+ super();
30+ return;
31+ }
32+
33+ /**
34+ * {@inheritDoc}
35+ * @param exception {@inheritDoc}
36+ * @throws SAXException {@inheritDoc}
37+ */
38+ @Override
39+ public void error(SAXParseException exception) throws SAXException{
40+ throw exception;
41+ }
42+
43+ /**
44+ * {@inheritDoc}
45+ * @param exception {@inheritDoc}
46+ * @throws SAXException {@inheritDoc}
47+ */
48+ @Override
49+ public void fatalError(SAXParseException exception) throws SAXException{
50+ throw exception;
51+ }
52+
53+ /**
54+ * {@inheritDoc}
55+ * @param exception {@inheritDoc}
56+ * @throws SAXException {@inheritDoc}
57+ */
58+ @Override
59+ public void warning(SAXParseException exception) throws SAXException{
60+ throw exception;
61+ }
62+
63+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/DomNsUtils.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/DomNsUtils.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,291 @@
1+/*
2+ * XML DOM utilities with namespace
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2011 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.text.MessageFormat;
11+import java.util.Iterator;
12+import javax.xml.bind.DatatypeConverter;
13+import org.w3c.dom.DOMException;
14+import org.w3c.dom.Element;
15+import org.w3c.dom.Node;
16+
17+/**
18+ * DOMユーティリティ(名前空間対応)。
19+ * <p>各種名前空間引数にnullが渡された場合、全ての名前空間にマッチする。
20+ * <p>各種ローカル名引数にnullが渡された場合、全てのローカル名にマッチする。
21+ * <p>ノードの持つ名前空間がnullの場合、全ての名前空間引数にマッチする。
22+ */
23+public final class DomNsUtils {
24+
25+ private static final String ERRMSG_NOELEM =
26+ "Elem:[{0}] was not found in Elem:[{1}]";
27+ private static final String ERRMSG_NOATTR =
28+ "Attr:[{0}] was not found in Elem:[{1}]";
29+ private static final String ERRMSG_INVATTR =
30+ "Invalid attribute form Attr[{0}] Value[{1}]";
31+
32+
33+ /**
34+ * 隠しコンストラクタ。
35+ */
36+ private DomNsUtils(){
37+ assert false;
38+ throw new AssertionError();
39+ }
40+
41+
42+ /**
43+ * 名前空間とローカル名が一致するノードか判定する。
44+ * @param node ノード
45+ * @param nsuri 名前空間URI
46+ * @param localName ローカル名。
47+ * @return ノードの名前空間およびローカル名が一致したらtrue
48+ */
49+ public static boolean hasNsLocalNameNode(Node node,
50+ String nsuri,
51+ String localName ){
52+ String nodeLocalName = node.getLocalName();
53+ String nodeNsUri = node.getNamespaceURI();
54+
55+ if(localName != null){
56+ if( ! localName.equals(nodeLocalName) ) return false;
57+ }
58+
59+ if(nsuri != null && nodeNsUri != null){
60+ if( ! nsuri.equals(nodeNsUri) ) return false;
61+ }
62+
63+ return true;
64+ }
65+
66+ /**
67+ * 名前空間とローカル名が一致する要素か判定する。
68+ * @param node ノード
69+ * @param nsuri 名前空間URI
70+ * @param localName ローカル名。
71+ * @return 名前空間およびローカル名が一致する要素であればtrue
72+ */
73+ public static boolean hasNsLocalNameElem(Node node,
74+ String nsuri,
75+ String localName ){
76+ if(node.getNodeType() != Node.ELEMENT_NODE) return false;
77+ if( ! hasNsLocalNameNode(node, nsuri, localName) ) return false;
78+ return true;
79+ }
80+
81+ /**
82+ * 親要素が指定された名前の子要素を持つか判定する。
83+ * @param parent 親要素
84+ * @param nsuri 名前空間URI
85+ * @param localName ローカル名
86+ * @return 指定名の子要素が存在すればtrue
87+ */
88+ public static boolean hasChild(Element parent,
89+ String nsuri,
90+ String localName ){
91+ for(Node node = parent.getFirstChild();
92+ node != null;
93+ node = node.getNextSibling() ){
94+
95+ if(hasNsLocalNameElem(node, nsuri, localName)){
96+ return true;
97+ }
98+ }
99+
100+ return false;
101+ }
102+
103+ /**
104+ * 指定された名前空間とローカル名に合致する最初の直下子要素を返す。
105+ * @param parent 親要素
106+ * @param nsuri 名前空間URI
107+ * @param localName ローカル名
108+ * @return 最初の直下子要素。見つからなければnull。
109+ */
110+ public static Element pickFirstChild(Node parent,
111+ String nsuri,
112+ String localName ){
113+ Node node = parent.getFirstChild();
114+ while(node != null){
115+ if(hasNsLocalNameElem(node, nsuri, localName)){
116+ break;
117+ }
118+ node = node.getNextSibling();
119+ }
120+ return (Element) node;
121+ }
122+
123+ /**
124+ * 指定された名前空間とローカル名に合致する最初の直下子要素を返す。
125+ * <p>見つからなければ例外を投げる。
126+ * @param parent 親要素
127+ * @param nsuri 名前空間URI
128+ * @param localName ローカル名
129+ * @return 最初の直下子要素。
130+ * @throws TogaXmlException 1つも見つからなかった
131+ */
132+ public static Element getFirstChild(Element parent,
133+ String nsuri,
134+ String localName )
135+ throws TogaXmlException{
136+ Element elem = pickFirstChild(parent, nsuri, localName);
137+
138+ if(elem == null){
139+ String message = MessageFormat.format(ERRMSG_NOELEM,
140+ localName,
141+ parent.getLocalName() );
142+ throw new TogaXmlException(message);
143+ }
144+
145+ return elem;
146+ }
147+
148+ /**
149+ * 指定された名前の子要素のforeachを返す。
150+ * @param parent 親要素
151+ * @param nsuri 名前空間URI
152+ * @param localName 子要素名
153+ * @return 子要素のforeach
154+ */
155+ public static Iterable<Element> getEachChild(final Element parent,
156+ final String nsuri,
157+ final String localName ){
158+ Iterable<Element> result = new Iterable<Element>(){
159+ @Override
160+ public Iterator<Element> iterator(){
161+ return new SiblingElemIterator(parent, nsuri, localName);
162+ }
163+ };
164+ return result;
165+ }
166+
167+ /**
168+ * 要素に属性が存在するか判定する。
169+ * @param elem 要素
170+ * @param nsuri 名前空間URI
171+ * @param localName ローカル名
172+ * @return 存在するならtrue
173+ */
174+ public static boolean hasAttrNS(Element elem,
175+ String nsuri,
176+ String localName ){
177+ return elem.hasAttributeNS(nsuri, localName);
178+ }
179+
180+ /**
181+ * 要素からxsd:string型属性値を読み取る。
182+ * @param elem 要素
183+ * @param nsuri 名前空間URI
184+ * @param localName 属性名
185+ * @return 文字列
186+ * @throws TogaXmlException 属性値が見つからなかった。
187+ */
188+ public static String getStringAttrNS(Element elem,
189+ String nsuri,
190+ String localName )
191+ throws TogaXmlException{
192+ if( ! hasAttrNS(elem, nsuri, localName) ){
193+ String message = MessageFormat.format(ERRMSG_NOATTR,
194+ localName,
195+ elem.getLocalName() );
196+ throw new TogaXmlException(message);
197+ }
198+
199+ String result;
200+ try{
201+ result = elem.getAttributeNS(nsuri, localName);
202+ }catch(DOMException e){
203+ assert false;
204+ throw new AssertionError(e);
205+ }
206+
207+ return result;
208+ }
209+
210+ /**
211+ * 要素からxsd:boolean型属性値を読み取る。
212+ * @param elem 要素
213+ * @param nsuri 名前空間URI
214+ * @param localName 属性名
215+ * @return 真ならtrue
216+ * @throws TogaXmlException 属性値が見つからなかった。
217+ */
218+ public static boolean getBooleanAttrNS(Element elem,
219+ String nsuri,
220+ String localName )
221+ throws TogaXmlException{
222+ String value = getStringAttrNS(elem, nsuri, localName);
223+
224+ boolean result;
225+ try{
226+ result = DatatypeConverter.parseBoolean(value);
227+ }catch(IllegalArgumentException e){
228+ String message = MessageFormat.format(ERRMSG_INVATTR,
229+ localName,
230+ value );
231+ throw new TogaXmlException(message, e);
232+ }
233+
234+ return result;
235+ }
236+
237+ /**
238+ * 要素からxsd:integer型属性値を読み取る。
239+ * @param elem 要素
240+ * @param nsuri 名前空間URI
241+ * @param localName 属性名
242+ * @return int値
243+ * @throws TogaXmlException 属性値が見つからなかった。
244+ */
245+ public static int getIntegerAttrNS(Element elem,
246+ String nsuri,
247+ String localName )
248+ throws TogaXmlException{
249+ String value = getStringAttrNS(elem, nsuri, localName);
250+
251+ int result;
252+ try{
253+ result = DatatypeConverter.parseInt(value);
254+ }catch(NumberFormatException e){
255+ String message = MessageFormat.format(ERRMSG_INVATTR,
256+ localName,
257+ value );
258+ throw new TogaXmlException(message, e);
259+ }
260+
261+ return result;
262+ }
263+
264+ /**
265+ * 要素からxsd:float型属性値を読み取る。
266+ * @param elem 要素
267+ * @param nsuri 名前空間URI
268+ * @param localName 属性名
269+ * @return float値
270+ * @throws TogaXmlException 属性値が見つからなかった。
271+ */
272+ public static float getFloatAttrNS(Element elem,
273+ String nsuri,
274+ String localName )
275+ throws TogaXmlException{
276+ String value = getStringAttrNS(elem, nsuri, localName);
277+
278+ float result;
279+ try{
280+ result = DatatypeConverter.parseFloat(value);
281+ }catch(NumberFormatException e){
282+ String message = MessageFormat.format(ERRMSG_INVATTR,
283+ localName,
284+ value );
285+ throw new TogaXmlException(message, e);
286+ }
287+
288+ return result;
289+ }
290+
291+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/DomUtils.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/DomUtils.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,363 @@
1+/*
2+ * XML DOM utilities
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2010 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.util.Iterator;
11+import java.util.LinkedList;
12+import java.util.List;
13+import java.util.NoSuchElementException;
14+import javax.xml.bind.DatatypeConverter;
15+import org.w3c.dom.Element;
16+import org.w3c.dom.Node;
17+
18+/**
19+ * DOMユーティリティ。
20+ */
21+public final class DomUtils {
22+
23+ // 構文解析バグ回避。
24+ private static final char BS_CHAR = (char) 0x005c;
25+
26+ /**
27+ * 隠しコンストラクタ。
28+ */
29+ private DomUtils(){
30+ super();
31+ assert false;
32+ throw new AssertionError();
33+ }
34+
35+ /**
36+ * 要素からxsd:string型属性値を読み取る。
37+ * @param elem 要素
38+ * @param attrName 属性名
39+ * @return 文字列
40+ * @throws TogaXmlException 属性値が見つからなかった。
41+ */
42+ public static String getStringAttr(Element elem, String attrName)
43+ throws TogaXmlException{
44+ if( ! elem.hasAttribute(attrName) ){
45+ String message = "Attr:[" + attrName + "] "
46+ + "was not found in "
47+ + "Elem:[" + elem.getTagName()+"]";
48+ throw new TogaXmlException(message);
49+ }
50+
51+ String result;
52+ try{
53+ result = elem.getAttribute(attrName);
54+ }catch(IllegalArgumentException e){
55+ String message = "Invalid attribute form [" + attrName + "]";
56+ throw new TogaXmlException(message, e);
57+ }
58+
59+ return result;
60+ }
61+
62+ /**
63+ * 要素からxsd:boolean型属性値を読み取る。
64+ * @param elem 要素
65+ * @param attrName 属性名
66+ * @return 真ならtrue
67+ * @throws TogaXmlException 属性値が見つからなかった。
68+ */
69+ public static boolean getBooleanAttr(Element elem, String attrName)
70+ throws TogaXmlException{
71+ String value = getStringAttr(elem, attrName);
72+
73+ boolean result;
74+ try{
75+ result = DatatypeConverter.parseBoolean(value);
76+ }catch(IllegalArgumentException e){
77+ String message =
78+ "Invalid boolean attribute form "
79+ + "[" + attrName + "][" + value + "]";
80+ throw new TogaXmlException(message, e);
81+ }
82+
83+ return result;
84+ }
85+
86+ /**
87+ * 要素からxsd:integer型属性値を読み取る。
88+ * @param elem 要素
89+ * @param attrName 属性名
90+ * @return int値
91+ * @throws TogaXmlException 属性値が見つからなかった。
92+ */
93+ public static int getIntegerAttr(Element elem, String attrName)
94+ throws TogaXmlException{
95+ String value = getStringAttr(elem, attrName);
96+
97+ int result;
98+ try{
99+ result = DatatypeConverter.parseInt(value);
100+ }catch(IllegalArgumentException e){
101+ String message =
102+ "Invalid integer attribute form "
103+ + "[" + attrName + "][" + value + "]";
104+ throw new TogaXmlException(message, e);
105+ }
106+
107+ return result;
108+ }
109+
110+ /**
111+ * 要素からxsd:float型属性値を読み取る。
112+ * @param elem 要素
113+ * @param attrName 属性名
114+ * @return float値
115+ * @throws TogaXmlException 属性値が見つからなかった。
116+ */
117+ public static float getFloatAttr(Element elem, String attrName)
118+ throws TogaXmlException{
119+ String value = getStringAttr(elem, attrName);
120+
121+ float result;
122+ try{
123+ result = DatatypeConverter.parseFloat(value);
124+ }catch(IllegalArgumentException e){
125+ String message =
126+ "Invalid float attribute form "
127+ + "[" + attrName + "][" + value + "]";
128+ throw new TogaXmlException(message, e);
129+ }
130+
131+ return result;
132+ }
133+
134+ /**
135+ * 要素から日本語Windows用ファイル名を属性値として読み取る。
136+ * 念のため文字U+00A5は文字U-005Cに変換される。
137+ * @param elem 要素
138+ * @param attrName 属性名
139+ * @return ファイル名
140+ * @throws TogaXmlException 属性値が見つからなかった。
141+ */
142+ public static String getSjisFileNameAttr(Element elem, String attrName)
143+ throws TogaXmlException{
144+ String result;
145+ try{
146+ result = getStringAttr(elem, attrName);
147+ }catch(IllegalArgumentException e){
148+ String message =
149+ "Invalid winfile attribute form "
150+ + "[" + attrName + "]";
151+ throw new TogaXmlException(message, e);
152+ }
153+
154+ result = result.replace("" + '\u00a5', "" + BS_CHAR);
155+
156+ return result;
157+ }
158+
159+ /**
160+ * 指定された名前の子要素を1つだけ返す。
161+ * @param parent 親要素
162+ * @param tagName 子要素名
163+ * @return 子要素
164+ * @throws TogaXmlException 1つも見つからなかった
165+ */
166+ public static Element getChild(Element parent, String tagName)
167+ throws TogaXmlException{
168+ Element result = null;
169+
170+ for(Node node = parent.getFirstChild();
171+ node != null;
172+ node = node.getNextSibling() ){
173+
174+ if(node.getNodeType() != Node.ELEMENT_NODE) continue;
175+ Element elem = (Element) node;
176+
177+ String elemTagName = elem.getTagName();
178+ if( tagName.equals(elemTagName) ){
179+ result = elem;
180+ break;
181+ }
182+ }
183+
184+ if(result == null){
185+ String message =
186+ "Elem:[" + tagName + "] was not found in "
187+ +"Elem:[" + parent.getTagName() + "]";
188+ throw new TogaXmlException(message);
189+ }
190+
191+ return result;
192+ }
193+
194+ /**
195+ * 親要素が指定された名前の子要素を持つか判定する。
196+ * @param parent 親要素
197+ * @param tagName 子要素名
198+ * @return 指定名の子要素が存在すればtrue
199+ */
200+ public static boolean hasChild(Element parent, String tagName){
201+ for(Node node = parent.getFirstChild();
202+ node != null;
203+ node = node.getNextSibling() ){
204+
205+ if(node.getNodeType() != Node.ELEMENT_NODE) continue;
206+ Element elem = (Element) node;
207+
208+ String elemTagName = elem.getTagName();
209+ if( tagName.equals(elemTagName) ) return true;
210+ }
211+
212+ return false;
213+ }
214+
215+ /**
216+ * 指定された名前の子要素のリストを返す。
217+ * @param parent 親要素
218+ * @param childTag 子要素名
219+ * @return 子要素のリスト
220+ */
221+ public static List<Element> getChildList(Element parent,
222+ String childTag){
223+ List<Element> result = new LinkedList<Element>();
224+
225+ for(Node node = parent.getFirstChild();
226+ node != null;
227+ node = node.getNextSibling() ){
228+
229+ if(node.getNodeType() != Node.ELEMENT_NODE) continue;
230+ Element elem = (Element) node;
231+
232+ String tagName = elem.getTagName();
233+ if( ! childTag.equals(tagName) ) continue;
234+
235+ result.add(elem);
236+ }
237+
238+ return result;
239+ }
240+
241+ /**
242+ * 指定された名前の子要素の列挙子を返す。
243+ * @param parent 親要素
244+ * @param childTag 子要素名
245+ * @return 子要素の列挙子
246+ */
247+ public static Iterator<Element> getChildIterator(Element parent,
248+ String childTag){
249+ Element firstElem;
250+ try{
251+ firstElem = getChild(parent, childTag);
252+ }catch(TogaXmlException e){
253+ firstElem = null;
254+ }
255+
256+ Iterator<Element> result = new ElemIterator(firstElem);
257+
258+ return result;
259+ }
260+
261+ /**
262+ * 指定された名前の子要素のforeachを返す。
263+ * @param parent 親要素
264+ * @param childTag 子要素名
265+ * @return 子要素のforeach
266+ */
267+ public static Iterable<Element> getEachChild(Element parent,
268+ String childTag){
269+ final Iterator<Element> iterator = getChildIterator(parent, childTag);
270+ Iterable<Element> result = new Iterable<Element>(){
271+ @Override
272+ public Iterator<Element> iterator(){
273+ return iterator;
274+ }
275+ };
276+ return result;
277+ }
278+
279+ /**
280+ * 要素の次の要素を返す。
281+ * @param elem 要素
282+ * @return 次の要素。なければnull
283+ */
284+ public static Element nextElement(Element elem){
285+ Node nextNode = elem;
286+ for(;;){
287+ nextNode = nextNode.getNextSibling();
288+ if(nextNode == null) break;
289+ if(nextNode.getNodeType() == Node.ELEMENT_NODE){
290+ break;
291+ }
292+ }
293+
294+ return (Element) nextNode;
295+ }
296+
297+ /**
298+ * 同じ要素名を持つ次の要素を返す。
299+ * @param elem 要素
300+ * @return 次の要素。なければnull
301+ */
302+ public static Element nextNamedElement(Element elem){
303+ String tagName = elem.getTagName();
304+ Element nextElem = elem;
305+ for(;;){
306+ nextElem = nextElement(nextElem);
307+ if(nextElem == null) break;
308+ if(tagName.equals(nextElem.getTagName())) break;
309+ }
310+
311+ return nextElem;
312+ }
313+
314+ /**
315+ * 同じ親要素と同じ要素名を持つ兄弟要素を列挙する列挙子。
316+ */
317+ private static final class ElemIterator implements Iterator<Element> {
318+ private Element next;
319+
320+ /**
321+ * コンストラクタ。
322+ * @param elem 最初の要素。nullを指定すれば空列挙子となる。
323+ */
324+ ElemIterator(Element elem){
325+ super();
326+ this.next = elem;
327+ }
328+
329+ /**
330+ * {@inheritDoc}
331+ * @return {@inheritDoc}
332+ */
333+ @Override
334+ public boolean hasNext(){
335+ if(this.next == null) return false;
336+ return true;
337+ }
338+
339+ /**
340+ * {@inheritDoc}
341+ * @return {@inheritDoc}
342+ * @throws NoSuchElementException {@inheritDoc}
343+ */
344+ @Override
345+ public Element next() throws NoSuchElementException{
346+ if(this.next == null) throw new NoSuchElementException();
347+ Element result = this.next;
348+ this.next = nextNamedElement(this.next);
349+ return result;
350+ }
351+
352+ /**
353+ * {@inheritDoc}
354+ * ※ 未サポート。
355+ */
356+ @Override
357+ public void remove(){
358+ throw new UnsupportedOperationException();
359+ }
360+
361+ }
362+
363+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/LocalXmlResource.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/LocalXmlResource.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,31 @@
1+/*
2+ * xml local resource map
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2013 olyutorskii
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.net.URI;
11+
12+/**
13+ * 代用ローカルリソースの管理を行う。
14+ * <p>ネットワークを介したグローバルなリソースと、
15+ * アプリ上のローカルな代用リソースとを対応付ける。
16+ */
17+public interface LocalXmlResource {
18+
19+ /**
20+ * オリジナル版XMLリソースのURIを返す。
21+ * @return オリジナル版リソースのURL。
22+ */
23+ URI getOriginalResource();
24+
25+ /**
26+ * ローカル版XMLリソースのURIを返す。
27+ * @return ローカル版リソースのURL。
28+ */
29+ URI getLocalResource();
30+
31+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/ProxyXmlExporter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/ProxyXmlExporter.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,195 @@
1+/*
2+ * proxy xml exporter
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2013 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.io.IOException;
11+
12+/**
13+ * 委譲型XMLエクスポータ。
14+ */
15+public class ProxyXmlExporter extends AbstractXmlExporter{
16+
17+ private final XmlExporter delegate;
18+
19+
20+ /**
21+ * コンストラクタ。
22+ * @param delegate 委譲先
23+ */
24+ public ProxyXmlExporter(XmlExporter delegate){
25+ super();
26+ this.delegate = delegate;
27+ return;
28+ }
29+
30+
31+ /**
32+ * {@inheritDoc}
33+ * @param ch {@inheritDoc}
34+ * @return {@inheritDoc}
35+ * @throws IOException {@inheritDoc}
36+ */
37+ @Override
38+ public Appendable append(char ch) throws IOException{
39+ return this.delegate.append(ch);
40+ }
41+
42+ /**
43+ * {@inheritDoc}
44+ * @param seq {@inheritDoc}
45+ * @return {@inheritDoc}
46+ * @throws IOException {@inheritDoc}
47+ */
48+ @Override
49+ public Appendable append(CharSequence seq) throws IOException{
50+ return this.delegate.append(seq);
51+ }
52+
53+ /**
54+ * {@inheritDoc}
55+ * @param seq {@inheritDoc}
56+ * @param start {@inheritDoc}
57+ * @param end {@inheritDoc}
58+ * @return {@inheritDoc}
59+ * @throws IOException {@inheritDoc}
60+ */
61+ @Override
62+ public Appendable append(CharSequence seq, int start, int end)
63+ throws IOException{
64+ return this.delegate.append(seq, start, end);
65+ }
66+
67+ /**
68+ * {@inheritDoc}
69+ * @throws IOException {@inheritDoc}
70+ */
71+ @Override
72+ public void flush() throws IOException{
73+ this.delegate.flush();
74+ return;
75+ }
76+
77+ /**
78+ * {@inheritDoc}
79+ * @throws IOException {@inheritDoc}
80+ */
81+ @Override
82+ public void close() throws IOException{
83+ this.delegate.close();
84+ return;
85+ }
86+
87+ /**
88+ * {@inheritDoc}
89+ * @param ch {@inheritDoc}
90+ * @return {@inheritDoc}
91+ * @throws IOException {@inheritDoc}
92+ */
93+ @Override
94+ public XmlExporter putRawCh(char ch) throws IOException{
95+ return this.delegate.putRawCh(ch);
96+ }
97+
98+ /**
99+ * {@inheritDoc}
100+ * @param seq {@inheritDoc}
101+ * @return {@inheritDoc}
102+ * @throws IOException {@inheritDoc}
103+ */
104+ @Override
105+ public XmlExporter putRawText(CharSequence seq) throws IOException{
106+ return this.delegate.putRawText(seq);
107+ }
108+
109+ /**
110+ * {@inheritDoc}
111+ * @return {@inheritDoc}
112+ */
113+ @Override
114+ public boolean isBasicLatinOnlyOut(){
115+ return this.delegate.isBasicLatinOnlyOut();
116+ }
117+
118+ /**
119+ * {@inheritDoc}
120+ * @param bool {@inheritDoc}
121+ */
122+ @Override
123+ public void setBasicLatinOnlyOut(boolean bool){
124+ this.delegate.setBasicLatinOnlyOut(bool);
125+ return;
126+ }
127+
128+ /**
129+ * {@inheritDoc}
130+ * @return {@inheritDoc}
131+ */
132+ @Override
133+ public String getNewLine(){
134+ return this.delegate.getNewLine();
135+ }
136+
137+ /**
138+ * {@inheritDoc}
139+ * @param newLine {@inheritDoc}
140+ * @throws NullPointerException {@inheritDoc}
141+ */
142+ @Override
143+ public void setNewLine(String newLine) throws NullPointerException{
144+ this.delegate.setNewLine(newLine);
145+ return;
146+ }
147+
148+ /**
149+ * {@inheritDoc}
150+ * @return {@inheritDoc}
151+ */
152+ @Override
153+ public String getIndentUnit(){
154+ return this.delegate.getIndentUnit();
155+ }
156+
157+ /**
158+ * {@inheritDoc}
159+ * @param indUnit {@inheritDoc}
160+ * @throws NullPointerException {@inheritDoc}
161+ */
162+ @Override
163+ public void setIndentUnit(String indUnit) throws NullPointerException{
164+ this.delegate.setIndentUnit(indUnit);
165+ return;
166+ }
167+
168+ /**
169+ * {@inheritDoc}
170+ */
171+ @Override
172+ public void pushNest(){
173+ this.delegate.pushNest();
174+ return;
175+ }
176+
177+ /**
178+ * {@inheritDoc}
179+ */
180+ @Override
181+ public void popNest(){
182+ this.delegate.popNest();
183+ return;
184+ }
185+
186+ /**
187+ * {@inheritDoc}
188+ * @return {@inheritDoc}
189+ */
190+ @Override
191+ public int getIndentLevel(){
192+ return this.delegate.getIndentLevel();
193+ }
194+
195+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/SaxAttr.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/SaxAttr.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,130 @@
1+/*
2+ * Sax 2 Xsd-types converter
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2013 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import javax.xml.bind.DatatypeConverter;
11+import org.xml.sax.Attributes;
12+
13+/**
14+ * XSD各種型のSAX属性値をJavaプリミティブ型へ変換する。
15+ */
16+public final class SaxAttr {
17+
18+ /**
19+ * 隠しコンストラクタ。
20+ */
21+ private SaxAttr(){
22+ assert false;
23+ throw new AssertionError();
24+ }
25+
26+
27+ /**
28+ * 属性名に対応する属性値があるか否か判定する。
29+ * @param attr 属性群
30+ * @param name 属性名
31+ * @return 属性名に対応する属性値がある場合はtrue
32+ */
33+ public static boolean hasAttr(Attributes attr, String name){
34+ if(attr.getValue(name) == null) return false;
35+ return true;
36+ }
37+
38+ /**
39+ * xsd:string型属性値の読み込み。
40+ * @param attr 属性群
41+ * @param name 属性名
42+ * @return 属性値。該当する属性が無ければnull。
43+ */
44+ public static String getStringAttr(Attributes attr, String name){
45+ String attrVal = attr.getValue(name);
46+ return attrVal;
47+ }
48+
49+ /**
50+ * xsd:boolean型属性値の読み込み。
51+ * @param attr 属性群
52+ * @param name 属性名
53+ * @return 属性値。
54+ * @throws IllegalArgumentException boolean型表記ではない
55+ */
56+ public static boolean getBooleanAttr(Attributes attr, String name)
57+ throws IllegalArgumentException{
58+ String attrVal = attr.getValue(name);
59+ boolean bVal;
60+ bVal = DatatypeConverter.parseBoolean(attrVal);
61+ return bVal;
62+ }
63+
64+ /**
65+ * xsd:boolean型属性値の読み込み。
66+ * @param attr 属性群
67+ * @param name 属性名
68+ * @param def 属性が無い場合のデフォルト値
69+ * @return 属性値。
70+ * @throws IllegalArgumentException boolean型表記ではない
71+ */
72+ public static boolean getBooleanAttr(Attributes attr,
73+ String name,
74+ boolean def )
75+ throws IllegalArgumentException{
76+ String attrVal = attr.getValue(name);
77+ if(attrVal == null) return def;
78+
79+ boolean bVal;
80+ bVal = DatatypeConverter.parseBoolean(attrVal);
81+
82+ return bVal;
83+ }
84+
85+ /**
86+ * xsd:byte型属性の読み込み。
87+ * @param attr 属性群
88+ * @param name 属性名
89+ * @return 属性値。
90+ * @throws NumberFormatException byte型表記ではない
91+ */
92+ public static byte getByteAttr(Attributes attr, String name)
93+ throws NumberFormatException{
94+ String attrVal = attr.getValue(name);
95+ byte bVal;
96+ bVal = DatatypeConverter.parseByte(attrVal);
97+ return bVal;
98+ }
99+
100+ /**
101+ * xsd:float型属性値の読み込み。
102+ * @param attr 属性群
103+ * @param name 属性名
104+ * @return 属性値。
105+ * @throws NumberFormatException float型表記ではない
106+ */
107+ public static float getFloatAttr(Attributes attr, String name)
108+ throws NumberFormatException {
109+ String attrVal = attr.getValue(name);
110+ float fVal;
111+ fVal = DatatypeConverter.parseFloat(attrVal);
112+ return fVal;
113+ }
114+
115+ /**
116+ * xsd:int型属性値の読み込み。
117+ * @param attr 属性群
118+ * @param name 属性名
119+ * @return 属性値。
120+ * @throws NumberFormatException int型表記ではない
121+ */
122+ public static int getIntAttr(Attributes attr, String name)
123+ throws NumberFormatException {
124+ String attrVal = attr.getValue(name);
125+ int iVal;
126+ iVal = DatatypeConverter.parseInt(attrVal);
127+ return iVal;
128+ }
129+
130+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/SchemaUtil.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/SchemaUtil.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,151 @@
1+/*
2+ * xml schema utility
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2013 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.io.BufferedInputStream;
11+import java.io.IOException;
12+import java.io.InputStream;
13+import java.net.MalformedURLException;
14+import java.net.URI;
15+import java.net.URL;
16+import java.util.ArrayList;
17+import java.util.List;
18+import javax.xml.XMLConstants;
19+import javax.xml.transform.Source;
20+import javax.xml.transform.stream.StreamSource;
21+import javax.xml.validation.Schema;
22+import javax.xml.validation.SchemaFactory;
23+import org.w3c.dom.ls.LSResourceResolver;
24+import org.xml.sax.SAXException;
25+
26+/**
27+ * XMLスキーマの各種ビルダ。
28+ */
29+public final class SchemaUtil {
30+
31+ /**
32+ * 隠しコンストラクタ。
33+ */
34+ private SchemaUtil(){
35+ assert false;
36+ throw new AssertionError();
37+ }
38+
39+
40+ /**
41+ * XML Schema 用のスキーマファクトリを返す。
42+ * @return スキーマファクトリ
43+ */
44+ public static SchemaFactory newSchemaFactory(){
45+ SchemaFactory result = newSchemaFactory(null);
46+ return result;
47+ }
48+
49+ /**
50+ * XML Schema 用のスキーマファクトリを返す。
51+ * @param resolver カスタムリゾルバ。nullも可。
52+ * @return スキーマファクトリ
53+ */
54+ public static SchemaFactory newSchemaFactory(
55+ LSResourceResolver resolver ){
56+ SchemaFactory schemaFactory =
57+ SchemaFactory.newInstance(
58+ XMLConstants.W3C_XML_SCHEMA_NS_URI
59+ );
60+
61+// schemaFactory.setFeature(name, value);
62+// schemaFactory.setProperty(name, object);
63+
64+ schemaFactory.setErrorHandler(BotherHandler.HANDLER);
65+ schemaFactory.setResourceResolver(resolver);
66+
67+ return schemaFactory;
68+ }
69+
70+ /**
71+ * ローカルリソースをSourceに変換する。
72+ * @param resource ローカルリソース
73+ * @return XML Source
74+ * @throws MalformedURLException 不正なURI
75+ * @throws IOException オープンエラー
76+ */
77+ private static Source toLocalSource(LocalXmlResource resource)
78+ throws MalformedURLException, IOException{
79+ URI localUri = resource.getLocalResource();
80+ URL localUrl = localUri.toURL();
81+
82+ InputStream is = localUrl.openStream();
83+ is = new BufferedInputStream(is);
84+
85+ Source result = new StreamSource(is);
86+ return result;
87+ }
88+
89+ /**
90+ * ローカルリソース群をSource群に変換する。
91+ * @param resArray ローカルリソースURI並び
92+ * @return XML Source並び
93+ * @throws MalformedURLException 不正なURI
94+ * @throws IOException オープンエラー
95+ */
96+ private static Source[] toLocalSourceArray(LocalXmlResource[] resArray)
97+ throws MalformedURLException, IOException{
98+ List<Source> sourceList = new ArrayList<Source>(resArray.length);
99+
100+ for(LocalXmlResource resource : resArray){
101+ Source localSource = toLocalSource(resource);
102+ sourceList.add(localSource);
103+ }
104+
105+ Source[] result = new Source[sourceList.size()];
106+ result = sourceList.toArray(result);
107+ return result;
108+ }
109+
110+ /**
111+ * ローカルスキーマをロードする。
112+ * <p>任意のリゾルバを指定可能
113+ * @param resolver リゾルバ
114+ * @param resArray ローカルスキーマ情報並び
115+ * @return スキーマ
116+ */
117+ public static Schema newSchema(XmlResourceResolver resolver,
118+ LocalXmlResource... resArray ){
119+ for(LocalXmlResource resource : resArray){
120+ resolver.putRedirected(resource);
121+ }
122+
123+ Source[] sources;
124+ try{
125+ sources = toLocalSourceArray(resArray);
126+ }catch(IOException e){ // ビルド障害
127+ assert false;
128+ throw new AssertionError(e);
129+ }
130+
131+ SchemaFactory schemaFactory = newSchemaFactory(resolver);
132+
133+ Schema result;
134+ try{
135+ if(sources.length <= 0){
136+ // ドキュメント埋め込みスキーマURLにリゾルバ経由でアクセス
137+ result = schemaFactory.newSchema();
138+ }else{
139+ result = schemaFactory.newSchema(sources);
140+ }
141+ }catch(SAXException e){ // Build error
142+ assert false;
143+ throw new AssertionError(e);
144+ }
145+
146+ // TODO: Sourceを閉めるのは誰の責務?
147+
148+ return result;
149+ }
150+
151+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/SiblingElemIterator.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/SiblingElemIterator.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,126 @@
1+/*
2+ * sibling element iterator on DOM tree
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2011 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.util.Iterator;
11+import java.util.NoSuchElementException;
12+import org.w3c.dom.Element;
13+import org.w3c.dom.Node;
14+
15+/**
16+ * 兄弟要素間用Iterator。
17+ * <p>同じ親と名前空間とローカル名を持つ要素同士を「兄弟要素」とする。
18+ * <p>ノードの持つ名前空間がnullの場合、全ての名前空間引数にマッチする。
19+ * <p>削除操作は未サポート。
20+ */
21+public class SiblingElemIterator implements Iterator<Element> {
22+
23+ private Element next;
24+ private final String nsuri;
25+ private final String localName;
26+
27+
28+ /**
29+ * コンストラクタ。
30+ * @param first 最初の兄弟要素。nullだと一度もiterateしない。
31+ */
32+ public SiblingElemIterator(Element first){
33+ super();
34+
35+ this.next = first;
36+
37+ if(this.next == null){
38+ this.nsuri = null;
39+ this.localName = null;
40+ }else{
41+ this.nsuri = this.next.getNamespaceURI();
42+ this.localName = this.next.getLocalName();
43+ }
44+
45+ return;
46+ }
47+
48+ /**
49+ * コンストラクタ。
50+ * <p>名前空間引数にnullが渡された場合、全ての名前空間にマッチする。
51+ * <p>ローカル名引数にnullが渡された場合、全てのローカル名にマッチする。
52+ * @param parent 親要素
53+ * @param nsuri 子要素の名前空間URI
54+ * @param localName 子要素のローカル名
55+ */
56+ public SiblingElemIterator(Element parent,
57+ String nsuri,
58+ String localName ){
59+ super();
60+
61+ this.next = DomNsUtils.pickFirstChild(parent, nsuri, localName);
62+
63+ if(this.next == null){
64+ this.nsuri = null;
65+ this.localName = null;
66+ }else{
67+ this.nsuri = nsuri;
68+ this.localName = localName;
69+ }
70+
71+ return;
72+ }
73+
74+
75+ /**
76+ * {@inheritDoc}
77+ * @return {@inheritDoc}
78+ */
79+ @Override
80+ public boolean hasNext(){
81+ if(this.next != null) return true;
82+ return false;
83+ }
84+
85+ /**
86+ * {@inheritDoc}
87+ * @return {@inheritDoc}
88+ * @throws NoSuchElementException {@inheritDoc}
89+ */
90+ @Override
91+ public Element next() throws NoSuchElementException {
92+ if(this.next == null) throw new NoSuchElementException();
93+
94+ Element result = this.next;
95+
96+ Node sibNode = result;
97+ do{
98+ sibNode = sibNode.getNextSibling();
99+ if(sibNode == null) break;
100+ }while( ! matchElemName(sibNode) );
101+ this.next = (Element) sibNode;
102+
103+ return result;
104+ }
105+
106+ /**
107+ * 兄弟要素にふさわしい名前を持つか判定する。
108+ * @param node 判定対象
109+ * @return 兄弟にふさわしい名前を持つならtrue
110+ */
111+ private boolean matchElemName(Node node){
112+ return DomNsUtils.hasNsLocalNameElem(node,
113+ this.nsuri, this.localName );
114+ }
115+
116+ /**
117+ * {@inheritDoc}
118+ * ※削除不可。
119+ * @throws UnsupportedOperationException 削除を試みたので失敗した
120+ */
121+ @Override
122+ public void remove() throws UnsupportedOperationException {
123+ throw new UnsupportedOperationException();
124+ }
125+
126+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/TogaXmlException.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/TogaXmlException.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,52 @@
1+/*
2+ * exception about xml
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2010 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+/**
11+ * 意図しないXML文書を検出した際の例外。
12+ */
13+@SuppressWarnings("serial")
14+public class TogaXmlException extends Exception{
15+
16+ /**
17+ * コンストラクタ。
18+ */
19+ public TogaXmlException(){
20+ super();
21+ return;
22+ }
23+
24+ /**
25+ * コンストラクタ。
26+ * @param message メッセージ
27+ */
28+ public TogaXmlException(String message){
29+ super(message);
30+ return;
31+ }
32+
33+ /**
34+ * コンストラクタ。
35+ * @param message メッセージ
36+ * @param cause 原因の例外
37+ */
38+ public TogaXmlException(String message, Throwable cause){
39+ super(message, cause);
40+ return;
41+ }
42+
43+ /**
44+ * コンストラクタ。
45+ * @param cause 原因の例外
46+ */
47+ public TogaXmlException(Throwable cause){
48+ super(cause);
49+ return;
50+ }
51+
52+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/XmlExporter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/XmlExporter.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,318 @@
1+/*
2+ * xml exporter
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2013 MikuToga Partners
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.io.Closeable;
11+import java.io.Flushable;
12+import java.io.IOException;
13+
14+/**
15+ * XMLエクスポータ基本機能のセット。
16+ */
17+public interface XmlExporter extends Appendable, Flushable, Closeable{
18+
19+ /**
20+ * 1文字を生出力する。
21+ * @param ch 文字
22+ * @return this本体
23+ * @throws IOException 出力エラー
24+ */
25+ XmlExporter putRawCh(char ch) throws IOException;
26+
27+ /**
28+ * 文字列を生出力する。
29+ * @param seq 文字列
30+ * @return this本体
31+ * @throws IOException 出力エラー
32+ */
33+ XmlExporter putRawText(CharSequence seq) throws IOException;
34+
35+ /**
36+ * 空白を出力する。
37+ * @return this本体
38+ * @throws IOException 出力エラー
39+ */
40+ XmlExporter sp() throws IOException;
41+
42+ /**
43+ * 空白を指定回数出力する。
44+ * @param count 空白回数。0以下の場合は何も出力しない。
45+ * @return this本体
46+ * @throws IOException 出力エラー
47+ */
48+ XmlExporter sp(int count) throws IOException;
49+
50+ /**
51+ * 改行文字列を返す。
52+ * @return 改行文字列
53+ */
54+ String getNewLine();
55+
56+ /**
57+ * 改行文字列を設定する。
58+ * @param newLine 改行文字列
59+ * @throws NullPointerException 引数がnull
60+ */
61+ void setNewLine(String newLine) throws NullPointerException;
62+
63+ /**
64+ * 改行を出力する。
65+ * @return this本体
66+ * @throws IOException 出力エラー
67+ */
68+ XmlExporter ln() throws IOException;
69+
70+ /**
71+ * 改行を指定回数出力する。
72+ * @param count 改行回数。0以下の場合は何も出力しない。
73+ * @return this本体
74+ * @throws IOException 出力エラー
75+ */
76+ XmlExporter ln(int count) throws IOException;
77+
78+ /**
79+ * インデント単位文字列を返す。
80+ * @return インデント単位文字列
81+ */
82+ String getIndentUnit();
83+
84+ /**
85+ * インデント単位文字列を設定する。
86+ * <p>デフォルトでは空白2個。
87+ * @param indUnit インデント単位文字列。
88+ * @throws NullPointerException 引数がnull
89+ */
90+ void setIndentUnit(String indUnit) throws NullPointerException;
91+
92+ /**
93+ * インデントレベルを一段下げる。
94+ */
95+ void pushNest();
96+
97+ /**
98+ * インデントレベルを一段上げる。
99+ * インデントレベル0の状態をさらに上げようとした場合、何も起こらない。
100+ */
101+ void popNest();
102+
103+ /**
104+ * インデントレベルを返す。
105+ * <p>深さ1の場合1を返す。
106+ * @return インデントレベル
107+ */
108+ int getIndentLevel();
109+
110+ /**
111+ * インデントを出力する。
112+ * インデント単位文字列をネストレベル回数分出力する。
113+ * @return this本体
114+ * @throws IOException 出力エラー
115+ */
116+ XmlExporter ind() throws IOException;
117+
118+ /**
119+ * BasicLatin文字だけを出力する状態か判定する。
120+ * <p>コメント部中身は対象外。
121+ * @return BasicLatin文字だけで出力するならtrue
122+ */
123+ boolean isBasicLatinOnlyOut();
124+
125+ /**
126+ * BasicLatin文字だけで出力するか設定する。
127+ * <p>BasicLatin以外の文字(≒日本語)を、そのまま出力するか、
128+ * 文字参照で出力するか、の設定が可能。
129+ * <p>コメント部中身は対象外。
130+ * @param bool BasicLatin文字だけで出力するならtrue
131+ */
132+ void setBasicLatinOnlyOut(boolean bool);
133+
134+ /**
135+ * 指定された文字を16進2桁の文字参照形式で出力する。
136+ * <p>「A」は「&amp;#x41;」になる。
137+ * <p>2桁で出力できない場合(>0x00ff)は4桁で出力する。
138+ * @param ch 文字
139+ * @return this本体
140+ * @throws IOException 出力エラー
141+ * @see <a href="http://www.w3.org/TR/xml11/#NT-CharRef">
142+ * W3C XML1.1 Character Reference
143+ * </a>
144+ */
145+ XmlExporter putCharRef2Hex(char ch) throws IOException;
146+
147+ /**
148+ * 指定された文字を16進4桁の文字参照形式で出力する。
149+ * <p>「亜」は「&amp;#x4E9C;」になる。
150+ * <p>UCS4に伴うサロゲートペアは未サポート
151+ * @param ch 文字
152+ * @return this本体
153+ * @throws IOException 出力エラー
154+ * @see <a href="http://www.w3.org/TR/xml11/#NT-CharRef">
155+ * W3C XML1.1 Character Reference
156+ * </a>
157+ */
158+ XmlExporter putCharRef4Hex(char ch) throws IOException;
159+
160+ /**
161+ * 要素の中身および属性値中身を出力する。
162+ * <p>XMLの構文規則を守る上で必要な各種エスケープ処理が行われる。
163+ * @param ch 文字
164+ * @return this本体
165+ * @throws IOException 出力エラー
166+ */
167+ XmlExporter putCh(char ch) throws IOException;
168+
169+ /**
170+ * 要素の中身および属性値中身を出力する。
171+ * <p>必要に応じてXML定義済み実体文字が割り振られた文字、
172+ * コントロールコード、および非BasicLatin文字がエスケープされる。
173+ * <p>半角円通貨記号U+00A5はバックスラッシュU+005Cに置換される。
174+ * <p>連続するスペースU+0020の2文字目以降は文字参照化される。
175+ * <p>全角スペースその他空白文字は無条件に文字参照化される。
176+ * @param content 内容
177+ * @return this本体
178+ * @throws IOException 出力エラー
179+ */
180+ XmlExporter putContent(CharSequence content) throws IOException;
181+
182+ /**
183+ * コメントの内容を出力する。
184+ * <p>コメント中の'\n'記号出現に伴い、
185+ * あらかじめ指定された改行文字が出力される。
186+ * <p>コメント中の'\n'以外のコントロールコードは
187+ * Control Pictures(U+2400〜)で代替される。
188+ * <p>それ以外の非BasicLatin文字はそのまま出力される。
189+ * <p>連続するハイフン(-)記号間には強制的にスペースが挿入される。
190+ * @param comment コメント内容
191+ * @return this本体
192+ * @throws IOException 出力エラー
193+ * <a href="http://www.unicode.org/charts/PDF/U2400.pdf">
194+ * Unicode 6.2 Controll Pictures
195+ * </a>
196+ */
197+ XmlExporter putCommentContent(CharSequence comment) throws IOException;
198+
199+ /**
200+ * 1行コメントを出力する。
201+ * コメント内部の頭及び末尾に空白が1つ挿入される。
202+ * @param comment コメント内容
203+ * @return this本体
204+ * @throws IOException 出力エラー
205+ */
206+ XmlExporter putLineComment(CharSequence comment) throws IOException;
207+
208+ /**
209+ * ブロックコメントを出力する。
210+ * <p>コメント内部の頭の前に改行が出力される。
211+ * <p>コメント内部の末尾が改行でない場合、改行が挿入される。
212+ * <p>ブロックコメント末尾は改行で終わる。
213+ * <p>インデント設定は無視される。
214+ * @param comment コメント内容
215+ * @return this本体
216+ * @throws IOException 出力エラー
217+ */
218+ XmlExporter putBlockComment(CharSequence comment) throws IOException;
219+
220+ /**
221+ * 開始タグ開き表記を出力する。
222+ * @param tagName タグ名
223+ * @return this本体
224+ * @throws IOException 出力エラー
225+ */
226+ XmlExporter putOpenSTag(CharSequence tagName) throws IOException;
227+
228+ /**
229+ * 開始タグ閉じ表記を出力する。
230+ * @return this本体
231+ * @throws IOException 出力エラー
232+ */
233+ XmlExporter putCloseSTag() throws IOException;
234+
235+ /**
236+ * 属性の無いシンプルな開始タグ表記を出力する。
237+ * @param tagName タグ名
238+ * @return this本体
239+ * @throws IOException 出力エラー
240+ */
241+ XmlExporter putSimpleSTag(CharSequence tagName) throws IOException;
242+
243+ /**
244+ * 終了タグ表記を出力する。
245+ * @param tagName タグ名
246+ * @return this本体
247+ * @throws IOException 出力エラー
248+ */
249+ XmlExporter putETag(CharSequence tagName) throws IOException;
250+
251+ /**
252+ * 属性の無い単出タグ表記を出力する。
253+ * @param tagName タグ名
254+ * @return this本体
255+ * @throws IOException 出力エラー
256+ */
257+ XmlExporter putSimpleEmpty(CharSequence tagName) throws IOException;
258+
259+ /**
260+ * 単出タグ閉じ表記を出力する。
261+ * @return this本体
262+ * @throws IOException 出力エラー
263+ */
264+ XmlExporter putCloseEmpty() throws IOException;
265+
266+ /**
267+ * xsd:int値をXMLスキーマ準拠の形式で出力する。
268+ * @param iVal int値
269+ * @return this本体
270+ * @throws IOException 出力エラー
271+ * @see <a href="http://www.w3.org/TR/xmlschema11-2/#int">
272+ * XML Schema 1.1 Datatypes int
273+ * </a>
274+ */
275+ XmlExporter putXsdInt(int iVal) throws IOException;
276+
277+ /**
278+ * xsd:float値をXMLスキーマ準拠の形式で出力する。
279+ * @param fVal float値
280+ * @return this本体
281+ * @throws IOException 出力エラー
282+ * @see <a href="http://www.w3.org/TR/xmlschema11-2/#sec-lex-float">
283+ * XML Schema 1.1 Datatypes float Lexical Mapping
284+ * </a>
285+ */
286+ XmlExporter putXsdFloat(float fVal) throws IOException;
287+
288+ /**
289+ * int型属性値を出力する。
290+ * @param attrName 属性名
291+ * @param iVal int値
292+ * @return this本体
293+ * @throws IOException 出力エラー
294+ */
295+ XmlExporter putIntAttr(CharSequence attrName, int iVal)
296+ throws IOException;
297+
298+ /**
299+ * float型属性値を出力する。
300+ * @param attrName 属性名
301+ * @param fVal float値
302+ * @return this本体
303+ * @throws IOException 出力エラー
304+ */
305+ XmlExporter putFloatAttr(CharSequence attrName, float fVal)
306+ throws IOException;
307+
308+ /**
309+ * 属性値を出力する。
310+ * @param attrName 属性名
311+ * @param content 属性内容
312+ * @return this本体
313+ * @throws IOException 出力エラー
314+ */
315+ XmlExporter putAttr(CharSequence attrName, CharSequence content)
316+ throws IOException;
317+
318+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/XmlResourceResolver.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/XmlResourceResolver.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,472 @@
1+/*
2+ * xml resource resolver
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2009 olyutorskii
6+ */
7+
8+package jp.sfjp.mikutoga.xml;
9+
10+import java.io.IOException;
11+import java.io.InputStream;
12+import java.io.Reader;
13+import java.net.URI;
14+import java.net.URISyntaxException;
15+import java.net.URL;
16+import java.util.Collections;
17+import java.util.HashMap;
18+import java.util.Map;
19+import org.w3c.dom.ls.LSInput;
20+import org.w3c.dom.ls.LSResourceResolver;
21+import org.xml.sax.EntityResolver;
22+import org.xml.sax.InputSource;
23+import org.xml.sax.SAXException;
24+
25+/**
26+ * URL変換マップに従い、XML文書からの外部参照をリダイレクトする。
27+ * 相対URIはこのクラスをベースに解決される。
28+ * 主な用途は外部スキーマのリソース化など。
29+ */
30+public class XmlResourceResolver
31+ implements LSResourceResolver, EntityResolver {
32+
33+ /** XML Schema. */
34+ public static final String SCHEMA_XML =
35+ "http://www.w3.org/2001/xml.xsd";
36+
37+ /** XSD名前空間。 */
38+ public static final String NS_XSD =
39+ "http://www.w3.org/2001/XMLSchema-instance";
40+
41+ private static final String LOCAL_SCHEMA_XML =
42+ "resources/xmlspace.xsd";
43+
44+ private static final URI EMPTY_URI = URI.create("");
45+
46+ private static final Class<?> THISCLASS = XmlResourceResolver.class;
47+
48+
49+ private final Map<URI, URI> uriMap;
50+
51+
52+ /**
53+ * コンストラクタ。
54+ */
55+ public XmlResourceResolver(){
56+ super();
57+
58+ assert this.getClass().equals(THISCLASS);
59+
60+ Map<URI, URI> map;
61+ map = new HashMap<URI, URI>();
62+ map = Collections.synchronizedMap(map);
63+ this.uriMap = map;
64+
65+ URL redirectRes = THISCLASS.getResource(LOCAL_SCHEMA_XML);
66+ String redirectResName = redirectRes.toString();
67+
68+ URI originalURI = URI.create(SCHEMA_XML);
69+ URI redirectURI = URI.create(redirectResName);
70+
71+ putRedirectedImpl(originalURI, redirectURI);
72+
73+ return;
74+ }
75+
76+
77+ /**
78+ * 絶対URIと相対URIを合成したURIを返す。
79+ * 正規化も行われる。
80+ * @param base 絶対URIでなければならない。nullでもよい。
81+ * @param relative 絶対URIでもよいがその場合baseは無視される。null可。
82+ * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
83+ * @throws java.net.URISyntaxException URIとして変。
84+ * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
85+ */
86+ protected static URI buildBaseRelativeURI(String base, String relative)
87+ throws URISyntaxException,
88+ IllegalArgumentException {
89+ URI baseURI;
90+ if(base != null){
91+ baseURI = new URI(base);
92+ if( ! baseURI.isAbsolute() ){
93+ throw new IllegalArgumentException();
94+ }
95+ }else{
96+ baseURI = null;
97+ }
98+
99+ URI relativeURI;
100+ if(relative != null){
101+ relativeURI = new URI(relative);
102+ }else{
103+ relativeURI = EMPTY_URI;
104+ }
105+
106+ URI resultURI;
107+ if(baseURI == null || relativeURI.isAbsolute()){
108+ resultURI = relativeURI;
109+ }else{
110+ resultURI = baseURI.resolve(relativeURI);
111+ }
112+
113+ if( ! resultURI.isAbsolute() ){
114+ throw new IllegalArgumentException();
115+ }
116+
117+ resultURI = resultURI.normalize();
118+
119+ return resultURI;
120+ }
121+
122+ /**
123+ * LSInput実装を生成する。
124+ * @return LSInput実装
125+ */
126+ public static LSInput createLSInput(){
127+ LSInput input = new LSInputImpl();
128+ return input;
129+ }
130+
131+
132+ /**
133+ * オリジナルURIとリダイレクト先のURIを登録する。
134+ * オリジナルURIへのアクセスはリダイレクトされる。
135+ * @param original オリジナルURI
136+ * @param redirect リダイレクトURI
137+ */
138+ private void putRedirectedImpl(URI original, URI redirect){
139+ URI oridinalNorm = original.normalize();
140+ URI redirectNorm = redirect.normalize();
141+
142+ this.uriMap.put(oridinalNorm, redirectNorm);
143+
144+ return;
145+ }
146+
147+ /**
148+ * オリジナルURIとリダイレクト先のURIを登録する。
149+ * オリジナルURIへのアクセスはリダイレクトされる。
150+ * @param original オリジナルURI
151+ * @param redirect リダイレクトURI
152+ */
153+ public void putRedirected(URI original, URI redirect){
154+ putRedirectedImpl(original, redirect);
155+ return;
156+ }
157+
158+ /**
159+ * ローカル版リソース参照解決を登録する。
160+ * @param lsc ローカル版リソース参照解決
161+ */
162+ public void putRedirected(LocalXmlResource lsc){
163+ URI original = lsc.getOriginalResource();
164+ if(original == null) return;
165+
166+ URI local = lsc.getLocalResource();
167+
168+ putRedirected(original, local);
169+
170+ return;
171+ }
172+
173+ /**
174+ * 別リゾルバの登録内容を追加登録する。
175+ * @param other 別リゾルバ
176+ */
177+ public void putRedirected(XmlResourceResolver other){
178+ this.uriMap.putAll(other.uriMap);
179+ return;
180+ }
181+
182+ /**
183+ * 登録済みリダイレクト先URIを返す。
184+ * @param original オリジナルURI
185+ * @return リダイレクト先URI。未登録の場合はnull
186+ */
187+ public URI getRedirected(URI original){
188+ URI keyURI = original.normalize();
189+ URI resourceURI = this.uriMap.get(keyURI);
190+ return resourceURI;
191+ }
192+
193+ /**
194+ * 登録済みリダイレクト先URIを返す。
195+ * @param original オリジナルURI
196+ * @return リダイレクト先URI。未登録の場合はオリジナルを返す
197+ */
198+ public URI resolveRedirected(URI original){
199+ URI result = getRedirected(original);
200+ if(result == null) result = original;
201+ return result;
202+ }
203+
204+ /**
205+ * 登録済みリダイレクト先リソースの入力ストリームを得る。
206+ * @param originalURI オリジナルURI
207+ * @return 入力ストリーム。リダイレクト先が未登録の場合はnull
208+ * @throws java.io.IOException 入出力エラー。
209+ * もしくはリソースが見つからない。
210+ */
211+ private InputStream getXMLResourceAsStream(URI originalURI)
212+ throws IOException{
213+ URI resourceURI = getRedirected(originalURI);
214+ if(resourceURI == null) return null;
215+
216+ URL resourceURL = resourceURI.toURL();
217+ InputStream is = resourceURL.openStream();
218+
219+ return is;
220+ }
221+
222+ /**
223+ * {@inheritDoc}
224+ * URL変換したあとの入力ソースを返す。
225+ * @param type {@inheritDoc}
226+ * @param namespaceURI {@inheritDoc}
227+ * @param publicId {@inheritDoc}
228+ * @param systemId {@inheritDoc}
229+ * @param baseURI {@inheritDoc}
230+ * @return {@inheritDoc}
231+ */
232+ @Override
233+ public LSInput resolveResource(String type,
234+ String namespaceURI,
235+ String publicId,
236+ String systemId,
237+ String baseURI ){
238+ if(systemId == null) return null;
239+
240+ URI originalURI;
241+ try{
242+ originalURI = buildBaseRelativeURI(baseURI, systemId);
243+ }catch(URISyntaxException e){
244+ return null;
245+ }
246+
247+ InputStream is;
248+ try{
249+ is = getXMLResourceAsStream(originalURI);
250+ }catch(IOException e){
251+ return null;
252+ }
253+ if(is == null) return null;
254+
255+ LSInput input = createLSInput();
256+ input.setBaseURI(baseURI);
257+ input.setPublicId(publicId);
258+ input.setSystemId(systemId);
259+ input.setByteStream(is);
260+
261+ return input;
262+ }
263+
264+ /**
265+ * {@inheritDoc}
266+ * URL変換したあとの入力ソースを返す。
267+ * @param publicId {@inheritDoc}
268+ * @param systemId {@inheritDoc}
269+ * @return {@inheritDoc}
270+ * @throws org.xml.sax.SAXException {@inheritDoc}
271+ * @throws java.io.IOException {@inheritDoc}
272+ */
273+ @Override
274+ public InputSource resolveEntity(String publicId, String systemId)
275+ throws SAXException, IOException{
276+ if(systemId == null) return null;
277+
278+ URI originalUri;
279+ try{
280+ originalUri = new URI(systemId);
281+ }catch(URISyntaxException e){
282+ return null;
283+ }
284+
285+ InputStream is = getXMLResourceAsStream(originalUri);
286+ if(is == null) return null;
287+
288+ InputSource source = new InputSource(is);
289+ source.setPublicId(publicId);
290+ source.setSystemId(systemId);
291+
292+ return source;
293+ }
294+
295+ /**
296+ * JRE1.5用LSInput実装。
297+ * JRE1.6なら
298+ * org.w3c.dom.ls.DOMImplementationLS#createLSInput()
299+ * で生成可能かも。
300+ */
301+ private static final class LSInputImpl implements LSInput {
302+
303+ private String baseURI = null;
304+ private InputStream byteStream = null;
305+ private boolean certifiedText = false;
306+ private Reader characterStream = null;
307+ private String encoding = null;
308+ private String publicId = null;
309+ private String stringData = null;
310+ private String systemId = null;
311+
312+ /**
313+ * コンストラクタ。
314+ */
315+ LSInputImpl(){
316+ super();
317+ return;
318+ }
319+
320+ /**
321+ * {@inheritDoc}
322+ * @return {@inheritDoc}
323+ */
324+ @Override
325+ public String getBaseURI(){
326+ return this.baseURI;
327+ }
328+
329+ /**
330+ * {@inheritDoc}
331+ * @param baseURI {@inheritDoc}
332+ */
333+ @Override
334+ public void setBaseURI(String baseURI){
335+ this.baseURI = baseURI;
336+ return;
337+ }
338+
339+ /**
340+ * {@inheritDoc}
341+ * @return {@inheritDoc}
342+ */
343+ @Override
344+ public InputStream getByteStream(){
345+ return this.byteStream;
346+ }
347+
348+ /**
349+ * {@inheritDoc}
350+ * @param byteStream {@inheritDoc}
351+ */
352+ @Override
353+ public void setByteStream(InputStream byteStream){
354+ this.byteStream = byteStream;
355+ }
356+
357+ /**
358+ * {@inheritDoc}
359+ * @return {@inheritDoc}
360+ */
361+ @Override
362+ public boolean getCertifiedText(){
363+ return this.certifiedText;
364+ }
365+
366+ /**
367+ * {@inheritDoc}
368+ * @param certifiedText {@inheritDoc}
369+ */
370+ @Override
371+ public void setCertifiedText(boolean certifiedText){
372+ this.certifiedText = certifiedText;
373+ return;
374+ }
375+
376+ /**
377+ * {@inheritDoc}
378+ * @return {@inheritDoc}
379+ */
380+ @Override
381+ public Reader getCharacterStream(){
382+ return this.characterStream;
383+ }
384+
385+ /**
386+ * {@inheritDoc}
387+ * @param characterStream {@inheritDoc}
388+ */
389+ @Override
390+ public void setCharacterStream(Reader characterStream){
391+ this.characterStream = characterStream;
392+ }
393+
394+ /**
395+ * {@inheritDoc}
396+ * @return {@inheritDoc}
397+ */
398+ @Override
399+ public String getEncoding(){
400+ return this.encoding;
401+ }
402+
403+ /**
404+ * {@inheritDoc}
405+ * @param encoding {@inheritDoc}
406+ */
407+ @Override
408+ public void setEncoding(String encoding){
409+ this.encoding = encoding;
410+ return;
411+ }
412+
413+ /**
414+ * {@inheritDoc}
415+ * @return {@inheritDoc}
416+ */
417+ @Override
418+ public String getPublicId(){
419+ return this.publicId;
420+ }
421+
422+ /**
423+ * {@inheritDoc}
424+ * @param publicId {@inheritDoc}
425+ */
426+ @Override
427+ public void setPublicId(String publicId){
428+ this.publicId = publicId;
429+ return;
430+ }
431+
432+ /**
433+ * {@inheritDoc}
434+ * @return {@inheritDoc}
435+ */
436+ @Override
437+ public String getStringData(){
438+ return this.stringData;
439+ }
440+
441+ /**
442+ * {@inheritDoc}
443+ * @param stringData {@inheritDoc}
444+ */
445+ @Override
446+ public void setStringData(String stringData){
447+ this.stringData = stringData;
448+ return;
449+ }
450+
451+ /**
452+ * {@inheritDoc}
453+ * @return {@inheritDoc}
454+ */
455+ @Override
456+ public String getSystemId(){
457+ return this.systemId;
458+ }
459+
460+ /**
461+ * {@inheritDoc}
462+ * @param systemId {@inheritDoc}
463+ */
464+ @Override
465+ public void setSystemId(String systemId){
466+ this.systemId = systemId;
467+ return;
468+ }
469+
470+ }
471+
472+}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sfjp/mikutoga/xml/package-info.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/jp/sfjp/mikutoga/xml/package-info.java Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,14 @@
1+/*
2+ * package information for Javadoc
3+ *
4+ * License : The MIT License
5+ * Copyright(c) 2010 MikuToga Partners
6+ */
7+
8+/**
9+ * MikuToga XML共通ライブラリ。
10+ */
11+
12+package jp.sfjp.mikutoga.xml;
13+
14+/* EOF */
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/AbstractXmlExporter.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/AbstractXmlExporter.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,699 +0,0 @@
1-/*
2- * abstract xml exporter
3- *
4- * License : The MIT License
5- * Copyright(c) 2013 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.io.IOException;
11-import java.util.regex.Matcher;
12-import java.util.regex.Pattern;
13-import javax.xml.bind.DatatypeConverter;
14-
15-/**
16- * Appendable実装に依存したXMLエクスポータの半実装。
17- * UCS4は未サポート。
18- */
19-abstract class AbstractXmlExporter implements XmlExporter{
20-
21- /** デフォルトの改行文字列。 */
22- private static final String DEF_NL = "\n"; // 0x0a(LF)
23- /** デフォルトのインデント単位。 */
24- private static final String DEF_INDENT_UNIT = "\u0020\u0020"; // ␣␣
25-
26- private static final char CH_SP = '\u0020'; // ␣
27- private static final char CH_YEN = '\u00a5'; // ¥
28- private static final char CH_BSLASH = (char)0x005c; // \
29- private static final char CH_DQ = '\u0022'; // "
30- private static final char CH_SQ = (char)0x0027; // '
31- private static final char CH_EQ = '='; // =
32- private static final char CH_LT = '<';
33- private static final char CH_GT = '>';
34-
35- private static final String COMM_START = "<!--";
36- private static final String COMM_END = "-->";
37-
38- private static final Pattern NUM_FUZZY =
39- Pattern.compile("([^.]*\\.[0-9][0-9]*?)0+");
40-
41- private static final String REF_HEX = "&#x";
42- private static final int HEX_EXP = 4; // 2 ** 4 == 16
43- private static final int MASK_1HEX = (1 << HEX_EXP) - 1; // 0b00001111
44- private static final int MAX_OCTET = (1 << Byte.SIZE) - 1; // 0xff
45- private static final char[] HEXCHAR_TABLE = {
46- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
47- 'A', 'B', 'C', 'D', 'E', 'F',
48- };
49-
50- static{
51- assert HEX_EXP * 2 == Byte.SIZE;
52- assert HEXCHAR_TABLE.length == (1 << HEX_EXP);
53- }
54-
55-
56- private boolean basicLatinOnlyOut = true;
57- private String newline = DEF_NL;
58- private String indentUnit = DEF_INDENT_UNIT;
59- private int indentNest = 0;
60-
61-
62- /**
63- * コンストラクタ。
64- */
65- protected AbstractXmlExporter(){
66- super();
67- return;
68- }
69-
70-
71- /**
72- * ASCIIコード相当(UCS:Basic-Latin)の文字か否か判定する。
73- * <p>※ Basic-Latinには各種制御文字も含まれる。
74- * @param ch 判定対象文字
75- * @return Basic-Latin文字ならtrue
76- * <a href="http://www.unicode.org/charts/PDF/U0000.pdf">
77- * Unicode 6.2 Controls and Basic Latin
78- * </a>
79- */
80- protected static boolean isBasicLatin(char ch){
81- if('\u0000' <= ch && ch <= '\u007f'){
82- return true;
83- }
84- return false;
85- }
86-
87- /**
88- * 冗長な実数出力を抑止する。
89- * <p>DatatypeConverterにおけるJDK1.6系と1.7系の仕様変更を吸収する。
90- * <p>0.001fは"0.0010"ではなく"0.001"と出力される。
91- * <p>指数表記での冗長桁は無視する。
92- * @param numTxt 実数表記
93- * @return 冗長桁が抑止された実数表記
94- * @see javax.xml.bind.DatatypeConverter
95- */
96- protected static String chopFuzzyZero(String numTxt){
97- String result;
98-
99- Matcher matcher = NUM_FUZZY.matcher(numTxt);
100- if(matcher.matches()){
101- result = matcher.group(1);
102- }else{
103- result = numTxt;
104- }
105-
106- return result;
107- }
108-
109-
110- /**
111- * {@inheritDoc}
112- * @param ch {@inheritDoc}
113- * @return {@inheritDoc}
114- * @throws IOException {@inheritDoc}
115- */
116- @Override
117- public abstract Appendable append(char ch) throws IOException;
118-
119- /**
120- * {@inheritDoc}
121- * @param seq {@inheritDoc}
122- * @return {@inheritDoc}
123- * @throws IOException {@inheritDoc}
124- */
125- @Override
126- public abstract Appendable append(CharSequence seq) throws IOException;
127-
128- /**
129- * {@inheritDoc}
130- * @param seq {@inheritDoc}
131- * @param start {@inheritDoc}
132- * @param end {@inheritDoc}
133- * @return {@inheritDoc}
134- * @throws IOException {@inheritDoc}
135- */
136- @Override
137- public abstract Appendable append(CharSequence seq, int start, int end)
138- throws IOException;
139-
140- /**
141- * {@inheritDoc}
142- * @throws IOException {@inheritDoc}
143- */
144- @Override
145- public abstract void flush() throws IOException;
146-
147- /**
148- * {@inheritDoc}
149- * @throws IOException {@inheritDoc}
150- */
151- @Override
152- public abstract void close() throws IOException;
153-
154-
155- /**
156- * {@inheritDoc}
157- * @param ch {@inheritDoc}
158- * @return {@inheritDoc}
159- * @throws IOException {@inheritDoc}
160- */
161- @Override
162- public XmlExporter putRawCh(char ch) throws IOException{
163- append(ch);
164- return this;
165- }
166-
167- /**
168- * {@inheritDoc}
169- * @param seq {@inheritDoc}
170- * @return {@inheritDoc}
171- * @throws IOException {@inheritDoc}
172- */
173- @Override
174- public XmlExporter putRawText(CharSequence seq)
175- throws IOException{
176- append(seq);
177- return this;
178- }
179-
180- /**
181- * {@inheritDoc}
182- * @return {@inheritDoc}
183- * @throws IOException {@inheritDoc}
184- */
185- @Override
186- public XmlExporter sp() throws IOException{
187- putRawCh(CH_SP);
188- return this;
189- }
190-
191- /**
192- * {@inheritDoc}
193- * @param count {@inheritDoc}
194- * @return {@inheritDoc}
195- * @throws IOException {@inheritDoc}
196- */
197- @Override
198- public XmlExporter sp(int count) throws IOException{
199- for(int ct = 1; ct <= count; ct++){
200- sp();
201- }
202- return this;
203- }
204-
205- /**
206- * {@inheritDoc}
207- * @return {@inheritDoc}
208- */
209- @Override
210- public String getNewLine(){
211- return this.newline;
212- }
213-
214- /**
215- * {@inheritDoc}
216- * @param newLine {@inheritDoc}
217- * @throws NullPointerException {@inheritDoc}
218- */
219- @Override
220- public void setNewLine(String newLine) throws NullPointerException{
221- if(newLine == null) throw new NullPointerException();
222- this.newline = newLine;
223- return;
224- }
225-
226- /**
227- * {@inheritDoc}
228- * @return {@inheritDoc}
229- * @throws IOException {@inheritDoc}
230- */
231- @Override
232- public XmlExporter ln() throws IOException{
233- putRawText(getNewLine());
234- return this;
235- }
236-
237- /**
238- * {@inheritDoc}
239- * @param count {@inheritDoc}
240- * @return {@inheritDoc}
241- * @throws IOException {@inheritDoc}
242- */
243- @Override
244- public XmlExporter ln(int count) throws IOException{
245- for(int ct = 1; ct <= count; ct++){
246- ln();
247- }
248- return this;
249- }
250-
251- /**
252- * {@inheritDoc}
253- * @return {@inheritDoc}
254- */
255- @Override
256- public String getIndentUnit(){
257- return this.indentUnit;
258- }
259-
260- /**
261- * {@inheritDoc}
262- * @param indUnit {@inheritDoc}
263- * @throws NullPointerException {@inheritDoc}
264- */
265- @Override
266- public void setIndentUnit(String indUnit) throws NullPointerException{
267- if(indUnit == null) throw new NullPointerException();
268- this.indentUnit = indUnit;
269- return;
270- }
271-
272- /**
273- * {@inheritDoc}
274- */
275- @Override
276- public void pushNest(){
277- this.indentNest++;
278- return;
279- }
280-
281- /**
282- * {@inheritDoc}
283- */
284- @Override
285- public void popNest(){
286- this.indentNest--;
287- if(this.indentNest < 0) this.indentNest = 0;
288- return;
289- }
290-
291- /**
292- * {@inheritDoc}
293- * @return {@inheritDoc}
294- */
295- @Override
296- public int getIndentLevel(){
297- return this.indentNest;
298- }
299-
300- /**
301- * {@inheritDoc}
302- * @return {@inheritDoc}
303- * @throws IOException {@inheritDoc}
304- */
305- @Override
306- public XmlExporter ind() throws IOException{
307- int level = getIndentLevel();
308- for(int ct = 1; ct <= level; ct++){
309- putRawText(getIndentUnit());
310- }
311- return this;
312- }
313-
314- /**
315- * {@inheritDoc}
316- * @return {@inheritDoc}
317- */
318- @Override
319- public boolean isBasicLatinOnlyOut(){
320- return this.basicLatinOnlyOut;
321- }
322-
323- /**
324- * {@inheritDoc}
325- * @param bool {@inheritDoc}
326- */
327- @Override
328- public void setBasicLatinOnlyOut(boolean bool){
329- this.basicLatinOnlyOut = bool;
330- return;
331- }
332-
333- /**
334- * {@inheritDoc}
335- * @param ch {@inheritDoc}
336- * @return {@inheritDoc}
337- * @throws IOException {@inheritDoc}
338- */
339- @Override
340- public XmlExporter putCharRef2Hex(char ch) throws IOException{
341- if(ch > MAX_OCTET) return putCharRef4Hex(ch);
342-
343- int ibits = ch; // 常に正なので符号拡張なし
344-
345- int idx4 = ibits & MASK_1HEX;
346- ibits >>= HEX_EXP;
347- int idx3 = ibits & MASK_1HEX;
348-
349- char hex3 = HEXCHAR_TABLE[idx3];
350- char hex4 = HEXCHAR_TABLE[idx4];
351-
352- putRawText(REF_HEX).putRawCh(hex3).putRawCh(hex4)
353- .putRawCh(';');
354-
355- return this;
356- }
357-
358- /**
359- * {@inheritDoc}
360- * @param ch {@inheritDoc}
361- * @return {@inheritDoc}
362- * @throws IOException {@inheritDoc}
363- */
364- @Override
365- public XmlExporter putCharRef4Hex(char ch) throws IOException{
366- int ibits = ch; // 常に正なので符号拡張なし
367-
368- int idx4 = ibits & MASK_1HEX;
369- ibits >>= HEX_EXP;
370- int idx3 = ibits & MASK_1HEX;
371- ibits >>= HEX_EXP;
372- int idx2 = ibits & MASK_1HEX;
373- ibits >>= HEX_EXP;
374- int idx1 = ibits & MASK_1HEX;
375-
376- char hex1 = HEXCHAR_TABLE[idx1];
377- char hex2 = HEXCHAR_TABLE[idx2];
378- char hex3 = HEXCHAR_TABLE[idx3];
379- char hex4 = HEXCHAR_TABLE[idx4];
380-
381- putRawText(REF_HEX).putRawCh(hex1).putRawCh(hex2)
382- .putRawCh(hex3).putRawCh(hex4)
383- .putRawCh(';');
384-
385- return this;
386- }
387-
388- /**
389- * {@inheritDoc}
390- * @param ch {@inheritDoc}
391- * @return {@inheritDoc}
392- * @throws IOException {@inheritDoc}
393- */
394- @Override
395- public XmlExporter putCh(char ch) throws IOException{
396- if(Character.isISOControl(ch)){
397- putCharRef2Hex(ch);
398- return this;
399- }
400-
401- String escTxt;
402- switch(ch){
403- case '&': escTxt = "&amp;"; break;
404- case CH_LT: escTxt = "&lt;"; break;
405- case CH_GT: escTxt = "&gt;"; break;
406- case CH_DQ: escTxt = "&quot;"; break;
407- case CH_SQ: escTxt = "&apos;"; break;
408- default: escTxt = null; break;
409- }
410-
411- if(escTxt != null){
412- putRawText(escTxt);
413- }else{
414- putRawCh(ch);
415- }
416-
417- return this;
418- }
419-
420- /**
421- * {@inheritDoc}
422- * @param content {@inheritDoc}
423- * @return {@inheritDoc}
424- * @throws IOException {@inheritDoc}
425- */
426- @Override
427- public XmlExporter putContent(CharSequence content)
428- throws IOException{
429- int length = content.length();
430-
431- char prev = '\0';
432- for(int pos = 0; pos < length; pos++){
433- char ch = content.charAt(pos);
434-
435- if( isBasicLatinOnlyOut() && ! isBasicLatin(ch) ){
436- putCharRef4Hex(ch);
437- }else if(ch == CH_YEN){
438- putRawCh(CH_BSLASH);
439- }else if(Character.isSpaceChar(ch)){
440- if(ch == CH_SP && prev != CH_SP){
441- putRawCh(ch);
442- }else{
443- putCharRef2Hex(ch);
444- }
445- }else{
446- putCh(ch);
447- }
448-
449- prev = ch;
450- }
451-
452- return this;
453- }
454-
455- /**
456- * {@inheritDoc}
457- * @param comment {@inheritDoc}
458- * @return {@inheritDoc}
459- * @throws IOException {@inheritDoc}
460- */
461- @Override
462- public XmlExporter putCommentContent(CharSequence comment)
463- throws IOException{
464- int length = comment.length();
465-
466- char prev = '\0';
467- for(int pos = 0; pos < length; pos++){
468- char ch = comment.charAt(pos);
469-
470- if(ch == '\n'){
471- ln();
472- }else if('\u0000' <= ch && ch <= '\u001f'){
473- putRawCh((char)('\u2400' + ch));
474- }else if(ch == '\u007f'){
475- putRawCh('\u2421');
476- }else if(prev == '-' && ch == '-'){
477- sp().putRawCh(ch);
478- }else{
479- putRawCh(ch);
480- }
481-
482- prev = ch;
483- }
484-
485- return this;
486- }
487-
488- /**
489- * {@inheritDoc}
490- * @param comment {@inheritDoc}
491- * @return {@inheritDoc}
492- * @throws IOException {@inheritDoc}
493- */
494- @Override
495- public XmlExporter putLineComment(CharSequence comment)
496- throws IOException{
497- putRawText(COMM_START).sp();
498- putCommentContent(comment);
499- sp().putRawText(COMM_END);
500- return this;
501- }
502-
503- /**
504- * {@inheritDoc}
505- * @param comment {@inheritDoc}
506- * @return {@inheritDoc}
507- * @throws IOException {@inheritDoc}
508- */
509- @Override
510- public XmlExporter putBlockComment(CharSequence comment)
511- throws IOException{
512- putRawText(COMM_START).ln();
513-
514- putCommentContent(comment);
515-
516- int commentLength = comment.length();
517- if(commentLength > 0){
518- char lastCh = comment.charAt(commentLength - 1);
519- if(lastCh != '\n'){
520- ln();
521- }
522- }
523-
524- putRawText(COMM_END).ln();
525-
526- return this;
527- }
528-
529- /**
530- * {@inheritDoc}
531- * @param tagName {@inheritDoc}
532- * @return {@inheritDoc}
533- * @throws IOException {@inheritDoc}
534- */
535- @Override
536- public XmlExporter putOpenSTag(CharSequence tagName)
537- throws IOException{
538- putRawCh(CH_LT);
539- putRawText(tagName);
540- return this;
541- }
542-
543- /**
544- * {@inheritDoc}
545- * @return {@inheritDoc}
546- * @throws IOException {@inheritDoc}
547- */
548- @Override
549- public XmlExporter putCloseSTag()
550- throws IOException{
551- putRawCh(CH_GT);
552- return this;
553- }
554-
555- /**
556- * {@inheritDoc}
557- * @param tagName {@inheritDoc}
558- * @return {@inheritDoc}
559- * @throws IOException {@inheritDoc}
560- */
561- @Override
562- public XmlExporter putSimpleSTag(CharSequence tagName)
563- throws IOException{
564- putRawCh(CH_LT);
565- putRawText(tagName);
566- putRawCh(CH_GT);
567- return this;
568- }
569-
570- /**
571- * {@inheritDoc}
572- * @param tagName {@inheritDoc}
573- * @return {@inheritDoc}
574- * @throws IOException {@inheritDoc}
575- */
576- @Override
577- public XmlExporter putETag(CharSequence tagName)
578- throws IOException{
579- putRawText("</");
580- putRawText(tagName);
581- putRawCh(CH_GT);
582- return this;
583- }
584-
585- /**
586- * {@inheritDoc}
587- * @param tagName {@inheritDoc}
588- * @return {@inheritDoc}
589- * @throws IOException {@inheritDoc}
590- */
591- @Override
592- public XmlExporter putSimpleEmpty(CharSequence tagName)
593- throws IOException{
594- putRawCh(CH_LT);
595- putRawText(tagName).sp();
596- putCloseEmpty();
597- return this;
598- }
599-
600- /**
601- * {@inheritDoc}
602- * @return {@inheritDoc}
603- * @throws IOException {@inheritDoc}
604- */
605- @Override
606- public XmlExporter putCloseEmpty()
607- throws IOException{
608- putRawText("/>");
609- return this;
610- }
611-
612- /**
613- * {@inheritDoc}
614- * @param iVal {@inheritDoc}
615- * @return {@inheritDoc}
616- * @throws IOException {@inheritDoc}
617- */
618- @Override
619- public XmlExporter putXsdInt(int iVal) throws IOException{
620- String value = DatatypeConverter.printInt(iVal);
621- putRawText(value);
622- return this;
623- }
624-
625- /**
626- * {@inheritDoc}
627- * @param fVal {@inheritDoc}
628- * @return {@inheritDoc}
629- * @throws IOException {@inheritDoc}
630- */
631- @Override
632- public XmlExporter putXsdFloat(float fVal) throws IOException{
633- String value = DatatypeConverter.printFloat(fVal);
634- value = chopFuzzyZero(value);
635- putRawText(value);
636- return this;
637- }
638-
639- /**
640- * {@inheritDoc}
641- * @param attrName {@inheritDoc}
642- * @param iVal {@inheritDoc}
643- * @return {@inheritDoc}
644- * @throws IOException {@inheritDoc}
645- */
646- @Override
647- public XmlExporter putIntAttr(CharSequence attrName,
648- int iVal)
649- throws IOException{
650- putRawText(attrName).putRawCh(CH_EQ);
651-
652- putRawCh(CH_DQ);
653- putXsdInt(iVal);
654- putRawCh(CH_DQ);
655-
656- return this;
657- }
658-
659- /**
660- * {@inheritDoc}
661- * @param attrName {@inheritDoc}
662- * @param fVal {@inheritDoc}
663- * @return {@inheritDoc}
664- * @throws IOException {@inheritDoc}
665- */
666- @Override
667- public XmlExporter putFloatAttr(CharSequence attrName,
668- float fVal)
669- throws IOException{
670- putRawText(attrName).putRawCh(CH_EQ);
671-
672- putRawCh(CH_DQ);
673- putXsdFloat(fVal);
674- putRawCh(CH_DQ);
675-
676- return this;
677- }
678-
679- /**
680- * {@inheritDoc}
681- * @param attrName {@inheritDoc}
682- * @param content {@inheritDoc}
683- * @return {@inheritDoc}
684- * @throws IOException {@inheritDoc}
685- */
686- @Override
687- public XmlExporter putAttr(CharSequence attrName,
688- CharSequence content)
689- throws IOException{
690- putRawText(attrName).putRawCh(CH_EQ);
691-
692- putRawCh(CH_DQ);
693- putContent(content);
694- putRawCh(CH_DQ);
695-
696- return this;
697- }
698-
699-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/BasicXmlExporter.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/BasicXmlExporter.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
1-/*
2- * basic xml exporter
3- *
4- * License : The MIT License
5- * Copyright(c) 2010 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.io.Closeable;
11-import java.io.Flushable;
12-import java.io.IOException;
13-
14-/**
15- * Appendable用XMLエクスポータ実装。
16- */
17-public class BasicXmlExporter extends AbstractXmlExporter{
18-
19- private Appendable appendable = null;
20-
21-
22- /**
23- * コンストラクタ。
24- */
25- public BasicXmlExporter(){
26- super();
27- return;
28- }
29-
30-
31- /**
32- * 出力先アペンダを指定する。
33- * @param app 出力先
34- * @throws NullPointerException 引数がnull
35- */
36- public void setAppendable(Appendable app) throws NullPointerException{
37- if(app == null) throw new NullPointerException();
38-
39- this.appendable = app;
40-
41- return;
42- }
43-
44- /**
45- * {@inheritDoc}
46- * @param ch {@inheritDoc}
47- * @return {@inheritDoc}
48- * @throws IOException {@inheritDoc}
49- */
50- @Override
51- public Appendable append(char ch) throws IOException{
52- return this.appendable.append(ch);
53- }
54-
55- /**
56- * {@inheritDoc}
57- * @param seq {@inheritDoc}
58- * @return {@inheritDoc}
59- * @throws IOException {@inheritDoc}
60- */
61- @Override
62- public Appendable append(CharSequence seq) throws IOException{
63- return this.appendable.append(seq);
64- }
65-
66- /**
67- * {@inheritDoc}
68- * @param seq {@inheritDoc}
69- * @param start {@inheritDoc}
70- * @param end {@inheritDoc}
71- * @return {@inheritDoc}
72- * @throws IOException {@inheritDoc}
73- */
74- @Override
75- public Appendable append(CharSequence seq, int start, int end)
76- throws IOException{
77- return this.appendable.append(seq, start, end);
78- }
79-
80- /**
81- * {@inheritDoc}
82- * 可能であれば出力をフラッシュする。
83- * @throws IOException {@inheritDoc}
84- */
85- @Override
86- public void flush() throws IOException{
87- if(this.appendable instanceof Flushable){
88- ((Flushable)this.appendable).flush();
89- }
90- return;
91- }
92-
93- /**
94- * {@inheritDoc}
95- * 可能であれば出力をクローズする。
96- * @throws IOException {@inheritDoc}
97- */
98- @Override
99- public void close() throws IOException{
100- if(this.appendable instanceof Closeable){
101- ((Closeable)this.appendable).close();
102- }
103- return;
104- }
105-
106-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/BotherHandler.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/BotherHandler.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
1-/*
2- * XML custom error-handler
3- *
4- * License : The MIT License
5- * Copyright(c) 2010 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import org.xml.sax.ErrorHandler;
11-import org.xml.sax.SAXException;
12-import org.xml.sax.SAXParseException;
13-
14-/**
15- * 自製エラーハンドラ。
16- * 例外を渡されれば即投げる。
17- */
18-public final class BotherHandler implements ErrorHandler{
19-
20- /**
21- * 唯一のシングルトン。
22- */
23- public static final ErrorHandler HANDLER = new BotherHandler();
24-
25- /**
26- * 隠しコンストラクタ。
27- */
28- private BotherHandler(){
29- super();
30- return;
31- }
32-
33- /**
34- * {@inheritDoc}
35- * @param exception {@inheritDoc}
36- * @throws SAXException {@inheritDoc}
37- */
38- @Override
39- public void error(SAXParseException exception) throws SAXException{
40- throw exception;
41- }
42-
43- /**
44- * {@inheritDoc}
45- * @param exception {@inheritDoc}
46- * @throws SAXException {@inheritDoc}
47- */
48- @Override
49- public void fatalError(SAXParseException exception) throws SAXException{
50- throw exception;
51- }
52-
53- /**
54- * {@inheritDoc}
55- * @param exception {@inheritDoc}
56- * @throws SAXException {@inheritDoc}
57- */
58- @Override
59- public void warning(SAXParseException exception) throws SAXException{
60- throw exception;
61- }
62-
63-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/DomNsUtils.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/DomNsUtils.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,291 +0,0 @@
1-/*
2- * XML DOM utilities with namespace
3- *
4- * License : The MIT License
5- * Copyright(c) 2011 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.text.MessageFormat;
11-import java.util.Iterator;
12-import javax.xml.bind.DatatypeConverter;
13-import org.w3c.dom.DOMException;
14-import org.w3c.dom.Element;
15-import org.w3c.dom.Node;
16-
17-/**
18- * DOMユーティリティ(名前空間対応)。
19- * <p>各種名前空間引数にnullが渡された場合、全ての名前空間にマッチする。
20- * <p>各種ローカル名引数にnullが渡された場合、全てのローカル名にマッチする。
21- * <p>ノードの持つ名前空間がnullの場合、全ての名前空間引数にマッチする。
22- */
23-public final class DomNsUtils {
24-
25- private static final String ERRMSG_NOELEM =
26- "Elem:[{0}] was not found in Elem:[{1}]";
27- private static final String ERRMSG_NOATTR =
28- "Attr:[{0}] was not found in Elem:[{1}]";
29- private static final String ERRMSG_INVATTR =
30- "Invalid attribute form Attr[{0}] Value[{1}]";
31-
32-
33- /**
34- * 隠しコンストラクタ。
35- */
36- private DomNsUtils(){
37- assert false;
38- throw new AssertionError();
39- }
40-
41-
42- /**
43- * 名前空間とローカル名が一致するノードか判定する。
44- * @param node ノード
45- * @param nsuri 名前空間URI
46- * @param localName ローカル名。
47- * @return ノードの名前空間およびローカル名が一致したらtrue
48- */
49- public static boolean hasNsLocalNameNode(Node node,
50- String nsuri,
51- String localName ){
52- String nodeLocalName = node.getLocalName();
53- String nodeNsUri = node.getNamespaceURI();
54-
55- if(localName != null){
56- if( ! localName.equals(nodeLocalName) ) return false;
57- }
58-
59- if(nsuri != null && nodeNsUri != null){
60- if( ! nsuri.equals(nodeNsUri) ) return false;
61- }
62-
63- return true;
64- }
65-
66- /**
67- * 名前空間とローカル名が一致する要素か判定する。
68- * @param node ノード
69- * @param nsuri 名前空間URI
70- * @param localName ローカル名。
71- * @return 名前空間およびローカル名が一致する要素であればtrue
72- */
73- public static boolean hasNsLocalNameElem(Node node,
74- String nsuri,
75- String localName ){
76- if(node.getNodeType() != Node.ELEMENT_NODE) return false;
77- if( ! hasNsLocalNameNode(node, nsuri, localName) ) return false;
78- return true;
79- }
80-
81- /**
82- * 親要素が指定された名前の子要素を持つか判定する。
83- * @param parent 親要素
84- * @param nsuri 名前空間URI
85- * @param localName ローカル名
86- * @return 指定名の子要素が存在すればtrue
87- */
88- public static boolean hasChild(Element parent,
89- String nsuri,
90- String localName ){
91- for(Node node = parent.getFirstChild();
92- node != null;
93- node = node.getNextSibling() ){
94-
95- if(hasNsLocalNameElem(node, nsuri, localName)){
96- return true;
97- }
98- }
99-
100- return false;
101- }
102-
103- /**
104- * 指定された名前空間とローカル名に合致する最初の直下子要素を返す。
105- * @param parent 親要素
106- * @param nsuri 名前空間URI
107- * @param localName ローカル名
108- * @return 最初の直下子要素。見つからなければnull。
109- */
110- public static Element pickFirstChild(Node parent,
111- String nsuri,
112- String localName ){
113- Node node = parent.getFirstChild();
114- while(node != null){
115- if(hasNsLocalNameElem(node, nsuri, localName)){
116- break;
117- }
118- node = node.getNextSibling();
119- }
120- return (Element) node;
121- }
122-
123- /**
124- * 指定された名前空間とローカル名に合致する最初の直下子要素を返す。
125- * <p>見つからなければ例外を投げる。
126- * @param parent 親要素
127- * @param nsuri 名前空間URI
128- * @param localName ローカル名
129- * @return 最初の直下子要素。
130- * @throws TogaXmlException 1つも見つからなかった
131- */
132- public static Element getFirstChild(Element parent,
133- String nsuri,
134- String localName )
135- throws TogaXmlException{
136- Element elem = pickFirstChild(parent, nsuri, localName);
137-
138- if(elem == null){
139- String message = MessageFormat.format(ERRMSG_NOELEM,
140- localName,
141- parent.getLocalName() );
142- throw new TogaXmlException(message);
143- }
144-
145- return elem;
146- }
147-
148- /**
149- * 指定された名前の子要素のforeachを返す。
150- * @param parent 親要素
151- * @param nsuri 名前空間URI
152- * @param localName 子要素名
153- * @return 子要素のforeach
154- */
155- public static Iterable<Element> getEachChild(final Element parent,
156- final String nsuri,
157- final String localName ){
158- Iterable<Element> result = new Iterable<Element>(){
159- @Override
160- public Iterator<Element> iterator(){
161- return new SiblingElemIterator(parent, nsuri, localName);
162- }
163- };
164- return result;
165- }
166-
167- /**
168- * 要素に属性が存在するか判定する。
169- * @param elem 要素
170- * @param nsuri 名前空間URI
171- * @param localName ローカル名
172- * @return 存在するならtrue
173- */
174- public static boolean hasAttrNS(Element elem,
175- String nsuri,
176- String localName ){
177- return elem.hasAttributeNS(nsuri, localName);
178- }
179-
180- /**
181- * 要素からxsd:string型属性値を読み取る。
182- * @param elem 要素
183- * @param nsuri 名前空間URI
184- * @param localName 属性名
185- * @return 文字列
186- * @throws TogaXmlException 属性値が見つからなかった。
187- */
188- public static String getStringAttrNS(Element elem,
189- String nsuri,
190- String localName )
191- throws TogaXmlException{
192- if( ! hasAttrNS(elem, nsuri, localName) ){
193- String message = MessageFormat.format(ERRMSG_NOATTR,
194- localName,
195- elem.getLocalName() );
196- throw new TogaXmlException(message);
197- }
198-
199- String result;
200- try{
201- result = elem.getAttributeNS(nsuri, localName);
202- }catch(DOMException e){
203- assert false;
204- throw new AssertionError(e);
205- }
206-
207- return result;
208- }
209-
210- /**
211- * 要素からxsd:boolean型属性値を読み取る。
212- * @param elem 要素
213- * @param nsuri 名前空間URI
214- * @param localName 属性名
215- * @return 真ならtrue
216- * @throws TogaXmlException 属性値が見つからなかった。
217- */
218- public static boolean getBooleanAttrNS(Element elem,
219- String nsuri,
220- String localName )
221- throws TogaXmlException{
222- String value = getStringAttrNS(elem, nsuri, localName);
223-
224- boolean result;
225- try{
226- result = DatatypeConverter.parseBoolean(value);
227- }catch(IllegalArgumentException e){
228- String message = MessageFormat.format(ERRMSG_INVATTR,
229- localName,
230- value );
231- throw new TogaXmlException(message, e);
232- }
233-
234- return result;
235- }
236-
237- /**
238- * 要素からxsd:integer型属性値を読み取る。
239- * @param elem 要素
240- * @param nsuri 名前空間URI
241- * @param localName 属性名
242- * @return int値
243- * @throws TogaXmlException 属性値が見つからなかった。
244- */
245- public static int getIntegerAttrNS(Element elem,
246- String nsuri,
247- String localName )
248- throws TogaXmlException{
249- String value = getStringAttrNS(elem, nsuri, localName);
250-
251- int result;
252- try{
253- result = DatatypeConverter.parseInt(value);
254- }catch(NumberFormatException e){
255- String message = MessageFormat.format(ERRMSG_INVATTR,
256- localName,
257- value );
258- throw new TogaXmlException(message, e);
259- }
260-
261- return result;
262- }
263-
264- /**
265- * 要素からxsd:float型属性値を読み取る。
266- * @param elem 要素
267- * @param nsuri 名前空間URI
268- * @param localName 属性名
269- * @return float値
270- * @throws TogaXmlException 属性値が見つからなかった。
271- */
272- public static float getFloatAttrNS(Element elem,
273- String nsuri,
274- String localName )
275- throws TogaXmlException{
276- String value = getStringAttrNS(elem, nsuri, localName);
277-
278- float result;
279- try{
280- result = DatatypeConverter.parseFloat(value);
281- }catch(NumberFormatException e){
282- String message = MessageFormat.format(ERRMSG_INVATTR,
283- localName,
284- value );
285- throw new TogaXmlException(message, e);
286- }
287-
288- return result;
289- }
290-
291-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/DomUtils.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/DomUtils.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,363 +0,0 @@
1-/*
2- * XML DOM utilities
3- *
4- * License : The MIT License
5- * Copyright(c) 2010 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.util.Iterator;
11-import java.util.LinkedList;
12-import java.util.List;
13-import java.util.NoSuchElementException;
14-import javax.xml.bind.DatatypeConverter;
15-import org.w3c.dom.Element;
16-import org.w3c.dom.Node;
17-
18-/**
19- * DOMユーティリティ。
20- */
21-public final class DomUtils {
22-
23- // 構文解析バグ回避。
24- private static final char BS_CHAR = (char) 0x005c;
25-
26- /**
27- * 隠しコンストラクタ。
28- */
29- private DomUtils(){
30- super();
31- assert false;
32- throw new AssertionError();
33- }
34-
35- /**
36- * 要素からxsd:string型属性値を読み取る。
37- * @param elem 要素
38- * @param attrName 属性名
39- * @return 文字列
40- * @throws TogaXmlException 属性値が見つからなかった。
41- */
42- public static String getStringAttr(Element elem, String attrName)
43- throws TogaXmlException{
44- if( ! elem.hasAttribute(attrName) ){
45- String message = "Attr:[" + attrName + "] "
46- + "was not found in "
47- + "Elem:[" + elem.getTagName()+"]";
48- throw new TogaXmlException(message);
49- }
50-
51- String result;
52- try{
53- result = elem.getAttribute(attrName);
54- }catch(IllegalArgumentException e){
55- String message = "Invalid attribute form [" + attrName + "]";
56- throw new TogaXmlException(message, e);
57- }
58-
59- return result;
60- }
61-
62- /**
63- * 要素からxsd:boolean型属性値を読み取る。
64- * @param elem 要素
65- * @param attrName 属性名
66- * @return 真ならtrue
67- * @throws TogaXmlException 属性値が見つからなかった。
68- */
69- public static boolean getBooleanAttr(Element elem, String attrName)
70- throws TogaXmlException{
71- String value = getStringAttr(elem, attrName);
72-
73- boolean result;
74- try{
75- result = DatatypeConverter.parseBoolean(value);
76- }catch(IllegalArgumentException e){
77- String message =
78- "Invalid boolean attribute form "
79- + "[" + attrName + "][" + value + "]";
80- throw new TogaXmlException(message, e);
81- }
82-
83- return result;
84- }
85-
86- /**
87- * 要素からxsd:integer型属性値を読み取る。
88- * @param elem 要素
89- * @param attrName 属性名
90- * @return int値
91- * @throws TogaXmlException 属性値が見つからなかった。
92- */
93- public static int getIntegerAttr(Element elem, String attrName)
94- throws TogaXmlException{
95- String value = getStringAttr(elem, attrName);
96-
97- int result;
98- try{
99- result = DatatypeConverter.parseInt(value);
100- }catch(IllegalArgumentException e){
101- String message =
102- "Invalid integer attribute form "
103- + "[" + attrName + "][" + value + "]";
104- throw new TogaXmlException(message, e);
105- }
106-
107- return result;
108- }
109-
110- /**
111- * 要素からxsd:float型属性値を読み取る。
112- * @param elem 要素
113- * @param attrName 属性名
114- * @return float値
115- * @throws TogaXmlException 属性値が見つからなかった。
116- */
117- public static float getFloatAttr(Element elem, String attrName)
118- throws TogaXmlException{
119- String value = getStringAttr(elem, attrName);
120-
121- float result;
122- try{
123- result = DatatypeConverter.parseFloat(value);
124- }catch(IllegalArgumentException e){
125- String message =
126- "Invalid float attribute form "
127- + "[" + attrName + "][" + value + "]";
128- throw new TogaXmlException(message, e);
129- }
130-
131- return result;
132- }
133-
134- /**
135- * 要素から日本語Windows用ファイル名を属性値として読み取る。
136- * 念のため文字U+00A5は文字U-005Cに変換される。
137- * @param elem 要素
138- * @param attrName 属性名
139- * @return ファイル名
140- * @throws TogaXmlException 属性値が見つからなかった。
141- */
142- public static String getSjisFileNameAttr(Element elem, String attrName)
143- throws TogaXmlException{
144- String result;
145- try{
146- result = getStringAttr(elem, attrName);
147- }catch(IllegalArgumentException e){
148- String message =
149- "Invalid winfile attribute form "
150- + "[" + attrName + "]";
151- throw new TogaXmlException(message, e);
152- }
153-
154- result = result.replace("" + '\u00a5', "" + BS_CHAR);
155-
156- return result;
157- }
158-
159- /**
160- * 指定された名前の子要素を1つだけ返す。
161- * @param parent 親要素
162- * @param tagName 子要素名
163- * @return 子要素
164- * @throws TogaXmlException 1つも見つからなかった
165- */
166- public static Element getChild(Element parent, String tagName)
167- throws TogaXmlException{
168- Element result = null;
169-
170- for(Node node = parent.getFirstChild();
171- node != null;
172- node = node.getNextSibling() ){
173-
174- if(node.getNodeType() != Node.ELEMENT_NODE) continue;
175- Element elem = (Element) node;
176-
177- String elemTagName = elem.getTagName();
178- if( tagName.equals(elemTagName) ){
179- result = elem;
180- break;
181- }
182- }
183-
184- if(result == null){
185- String message =
186- "Elem:[" + tagName + "] was not found in "
187- +"Elem:[" + parent.getTagName() + "]";
188- throw new TogaXmlException(message);
189- }
190-
191- return result;
192- }
193-
194- /**
195- * 親要素が指定された名前の子要素を持つか判定する。
196- * @param parent 親要素
197- * @param tagName 子要素名
198- * @return 指定名の子要素が存在すればtrue
199- */
200- public static boolean hasChild(Element parent, String tagName){
201- for(Node node = parent.getFirstChild();
202- node != null;
203- node = node.getNextSibling() ){
204-
205- if(node.getNodeType() != Node.ELEMENT_NODE) continue;
206- Element elem = (Element) node;
207-
208- String elemTagName = elem.getTagName();
209- if( tagName.equals(elemTagName) ) return true;
210- }
211-
212- return false;
213- }
214-
215- /**
216- * 指定された名前の子要素のリストを返す。
217- * @param parent 親要素
218- * @param childTag 子要素名
219- * @return 子要素のリスト
220- */
221- public static List<Element> getChildList(Element parent,
222- String childTag){
223- List<Element> result = new LinkedList<Element>();
224-
225- for(Node node = parent.getFirstChild();
226- node != null;
227- node = node.getNextSibling() ){
228-
229- if(node.getNodeType() != Node.ELEMENT_NODE) continue;
230- Element elem = (Element) node;
231-
232- String tagName = elem.getTagName();
233- if( ! childTag.equals(tagName) ) continue;
234-
235- result.add(elem);
236- }
237-
238- return result;
239- }
240-
241- /**
242- * 指定された名前の子要素の列挙子を返す。
243- * @param parent 親要素
244- * @param childTag 子要素名
245- * @return 子要素の列挙子
246- */
247- public static Iterator<Element> getChildIterator(Element parent,
248- String childTag){
249- Element firstElem;
250- try{
251- firstElem = getChild(parent, childTag);
252- }catch(TogaXmlException e){
253- firstElem = null;
254- }
255-
256- Iterator<Element> result = new ElemIterator(firstElem);
257-
258- return result;
259- }
260-
261- /**
262- * 指定された名前の子要素のforeachを返す。
263- * @param parent 親要素
264- * @param childTag 子要素名
265- * @return 子要素のforeach
266- */
267- public static Iterable<Element> getEachChild(Element parent,
268- String childTag){
269- final Iterator<Element> iterator = getChildIterator(parent, childTag);
270- Iterable<Element> result = new Iterable<Element>(){
271- @Override
272- public Iterator<Element> iterator(){
273- return iterator;
274- }
275- };
276- return result;
277- }
278-
279- /**
280- * 要素の次の要素を返す。
281- * @param elem 要素
282- * @return 次の要素。なければnull
283- */
284- public static Element nextElement(Element elem){
285- Node nextNode = elem;
286- for(;;){
287- nextNode = nextNode.getNextSibling();
288- if(nextNode == null) break;
289- if(nextNode.getNodeType() == Node.ELEMENT_NODE){
290- break;
291- }
292- }
293-
294- return (Element) nextNode;
295- }
296-
297- /**
298- * 同じ要素名を持つ次の要素を返す。
299- * @param elem 要素
300- * @return 次の要素。なければnull
301- */
302- public static Element nextNamedElement(Element elem){
303- String tagName = elem.getTagName();
304- Element nextElem = elem;
305- for(;;){
306- nextElem = nextElement(nextElem);
307- if(nextElem == null) break;
308- if(tagName.equals(nextElem.getTagName())) break;
309- }
310-
311- return nextElem;
312- }
313-
314- /**
315- * 同じ親要素と同じ要素名を持つ兄弟要素を列挙する列挙子。
316- */
317- private static final class ElemIterator implements Iterator<Element> {
318- private Element next;
319-
320- /**
321- * コンストラクタ。
322- * @param elem 最初の要素。nullを指定すれば空列挙子となる。
323- */
324- ElemIterator(Element elem){
325- super();
326- this.next = elem;
327- }
328-
329- /**
330- * {@inheritDoc}
331- * @return {@inheritDoc}
332- */
333- @Override
334- public boolean hasNext(){
335- if(this.next == null) return false;
336- return true;
337- }
338-
339- /**
340- * {@inheritDoc}
341- * @return {@inheritDoc}
342- * @throws NoSuchElementException {@inheritDoc}
343- */
344- @Override
345- public Element next() throws NoSuchElementException{
346- if(this.next == null) throw new NoSuchElementException();
347- Element result = this.next;
348- this.next = nextNamedElement(this.next);
349- return result;
350- }
351-
352- /**
353- * {@inheritDoc}
354- * ※ 未サポート。
355- */
356- @Override
357- public void remove(){
358- throw new UnsupportedOperationException();
359- }
360-
361- }
362-
363-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/LocalXmlResource.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/LocalXmlResource.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
1-/*
2- * xml local resource map
3- *
4- * License : The MIT License
5- * Copyright(c) 2013 olyutorskii
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.net.URI;
11-
12-/**
13- * 代用ローカルリソースの管理を行う。
14- * <p>ネットワークを介したグローバルなリソースと、
15- * アプリ上のローカルな代用リソースとを対応付ける。
16- */
17-public interface LocalXmlResource {
18-
19- /**
20- * オリジナル版XMLリソースのURIを返す。
21- * @return オリジナル版リソースのURL。
22- */
23- URI getOriginalResource();
24-
25- /**
26- * ローカル版XMLリソースのURIを返す。
27- * @return ローカル版リソースのURL。
28- */
29- URI getLocalResource();
30-
31-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/ProxyXmlExporter.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/ProxyXmlExporter.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
1-/*
2- * proxy xml exporter
3- *
4- * License : The MIT License
5- * Copyright(c) 2013 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.io.IOException;
11-
12-/**
13- * 委譲型XMLエクスポータ。
14- */
15-public class ProxyXmlExporter extends AbstractXmlExporter{
16-
17- private final XmlExporter delegate;
18-
19-
20- /**
21- * コンストラクタ。
22- * @param delegate 委譲先
23- */
24- public ProxyXmlExporter(XmlExporter delegate){
25- super();
26- this.delegate = delegate;
27- return;
28- }
29-
30-
31- /**
32- * {@inheritDoc}
33- * @param ch {@inheritDoc}
34- * @return {@inheritDoc}
35- * @throws IOException {@inheritDoc}
36- */
37- @Override
38- public Appendable append(char ch) throws IOException{
39- return this.delegate.append(ch);
40- }
41-
42- /**
43- * {@inheritDoc}
44- * @param seq {@inheritDoc}
45- * @return {@inheritDoc}
46- * @throws IOException {@inheritDoc}
47- */
48- @Override
49- public Appendable append(CharSequence seq) throws IOException{
50- return this.delegate.append(seq);
51- }
52-
53- /**
54- * {@inheritDoc}
55- * @param seq {@inheritDoc}
56- * @param start {@inheritDoc}
57- * @param end {@inheritDoc}
58- * @return {@inheritDoc}
59- * @throws IOException {@inheritDoc}
60- */
61- @Override
62- public Appendable append(CharSequence seq, int start, int end)
63- throws IOException{
64- return this.delegate.append(seq, start, end);
65- }
66-
67- /**
68- * {@inheritDoc}
69- * @throws IOException {@inheritDoc}
70- */
71- @Override
72- public void flush() throws IOException{
73- this.delegate.flush();
74- return;
75- }
76-
77- /**
78- * {@inheritDoc}
79- * @throws IOException {@inheritDoc}
80- */
81- @Override
82- public void close() throws IOException{
83- this.delegate.close();
84- return;
85- }
86-
87- /**
88- * {@inheritDoc}
89- * @param ch {@inheritDoc}
90- * @return {@inheritDoc}
91- * @throws IOException {@inheritDoc}
92- */
93- @Override
94- public XmlExporter putRawCh(char ch) throws IOException{
95- return this.delegate.putRawCh(ch);
96- }
97-
98- /**
99- * {@inheritDoc}
100- * @param seq {@inheritDoc}
101- * @return {@inheritDoc}
102- * @throws IOException {@inheritDoc}
103- */
104- @Override
105- public XmlExporter putRawText(CharSequence seq) throws IOException{
106- return this.delegate.putRawText(seq);
107- }
108-
109- /**
110- * {@inheritDoc}
111- * @return {@inheritDoc}
112- */
113- @Override
114- public boolean isBasicLatinOnlyOut(){
115- return this.delegate.isBasicLatinOnlyOut();
116- }
117-
118- /**
119- * {@inheritDoc}
120- * @param bool {@inheritDoc}
121- */
122- @Override
123- public void setBasicLatinOnlyOut(boolean bool){
124- this.delegate.setBasicLatinOnlyOut(bool);
125- return;
126- }
127-
128- /**
129- * {@inheritDoc}
130- * @return {@inheritDoc}
131- */
132- @Override
133- public String getNewLine(){
134- return this.delegate.getNewLine();
135- }
136-
137- /**
138- * {@inheritDoc}
139- * @param newLine {@inheritDoc}
140- * @throws NullPointerException {@inheritDoc}
141- */
142- @Override
143- public void setNewLine(String newLine) throws NullPointerException{
144- this.delegate.setNewLine(newLine);
145- return;
146- }
147-
148- /**
149- * {@inheritDoc}
150- * @return {@inheritDoc}
151- */
152- @Override
153- public String getIndentUnit(){
154- return this.delegate.getIndentUnit();
155- }
156-
157- /**
158- * {@inheritDoc}
159- * @param indUnit {@inheritDoc}
160- * @throws NullPointerException {@inheritDoc}
161- */
162- @Override
163- public void setIndentUnit(String indUnit) throws NullPointerException{
164- this.delegate.setIndentUnit(indUnit);
165- return;
166- }
167-
168- /**
169- * {@inheritDoc}
170- */
171- @Override
172- public void pushNest(){
173- this.delegate.pushNest();
174- return;
175- }
176-
177- /**
178- * {@inheritDoc}
179- */
180- @Override
181- public void popNest(){
182- this.delegate.popNest();
183- return;
184- }
185-
186- /**
187- * {@inheritDoc}
188- * @return {@inheritDoc}
189- */
190- @Override
191- public int getIndentLevel(){
192- return this.delegate.getIndentLevel();
193- }
194-
195-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/SchemaUtil.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/SchemaUtil.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
1-/*
2- * xml schema utility
3- *
4- * License : The MIT License
5- * Copyright(c) 2013 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.io.BufferedInputStream;
11-import java.io.IOException;
12-import java.io.InputStream;
13-import java.net.MalformedURLException;
14-import java.net.URI;
15-import java.net.URL;
16-import java.util.ArrayList;
17-import java.util.List;
18-import javax.xml.XMLConstants;
19-import javax.xml.transform.Source;
20-import javax.xml.transform.stream.StreamSource;
21-import javax.xml.validation.Schema;
22-import javax.xml.validation.SchemaFactory;
23-import org.w3c.dom.ls.LSResourceResolver;
24-import org.xml.sax.SAXException;
25-
26-/**
27- * XMLスキーマの各種ビルダ。
28- */
29-public final class SchemaUtil {
30-
31- /**
32- * 隠しコンストラクタ。
33- */
34- private SchemaUtil(){
35- assert false;
36- throw new AssertionError();
37- }
38-
39-
40- /**
41- * XML Schema 用のスキーマファクトリを返す。
42- * @return スキーマファクトリ
43- */
44- public static SchemaFactory newSchemaFactory(){
45- SchemaFactory result = newSchemaFactory(null);
46- return result;
47- }
48-
49- /**
50- * XML Schema 用のスキーマファクトリを返す。
51- * @param resolver カスタムリゾルバ。nullも可。
52- * @return スキーマファクトリ
53- */
54- public static SchemaFactory newSchemaFactory(
55- LSResourceResolver resolver ){
56- SchemaFactory schemaFactory =
57- SchemaFactory.newInstance(
58- XMLConstants.W3C_XML_SCHEMA_NS_URI
59- );
60-
61-// schemaFactory.setFeature(name, value);
62-// schemaFactory.setProperty(name, object);
63-
64- schemaFactory.setErrorHandler(BotherHandler.HANDLER);
65- schemaFactory.setResourceResolver(resolver);
66-
67- return schemaFactory;
68- }
69-
70- /**
71- * ローカルリソースをSourceに変換する。
72- * @param resource ローカルリソース
73- * @return XML Source
74- * @throws MalformedURLException 不正なURI
75- * @throws IOException オープンエラー
76- */
77- private static Source toLocalSource(LocalXmlResource resource)
78- throws MalformedURLException, IOException{
79- URI localUri = resource.getLocalResource();
80- URL localUrl = localUri.toURL();
81-
82- InputStream is = localUrl.openStream();
83- is = new BufferedInputStream(is);
84-
85- Source result = new StreamSource(is);
86- return result;
87- }
88-
89- /**
90- * ローカルリソース群をSource群に変換する。
91- * @param resArray ローカルリソースURI並び
92- * @return XML Source並び
93- * @throws MalformedURLException 不正なURI
94- * @throws IOException オープンエラー
95- */
96- private static Source[] toLocalSourceArray(LocalXmlResource[] resArray)
97- throws MalformedURLException, IOException{
98- List<Source> sourceList = new ArrayList<Source>(resArray.length);
99-
100- for(LocalXmlResource resource : resArray){
101- Source localSource = toLocalSource(resource);
102- sourceList.add(localSource);
103- }
104-
105- Source[] result = new Source[sourceList.size()];
106- result = sourceList.toArray(result);
107- return result;
108- }
109-
110- /**
111- * ローカルスキーマをロードする。
112- * <p>任意のリゾルバを指定可能
113- * @param resolver リゾルバ
114- * @param resArray ローカルスキーマ情報並び
115- * @return スキーマ
116- */
117- public static Schema newSchema(XmlResourceResolver resolver,
118- LocalXmlResource... resArray ){
119- for(LocalXmlResource resource : resArray){
120- resolver.putRedirected(resource);
121- }
122-
123- Source[] sources;
124- try{
125- sources = toLocalSourceArray(resArray);
126- }catch(IOException e){ // ビルド障害
127- assert false;
128- throw new AssertionError(e);
129- }
130-
131- SchemaFactory schemaFactory = newSchemaFactory(resolver);
132-
133- Schema result;
134- try{
135- if(sources.length <= 0){
136- // ドキュメント埋め込みスキーマURLにリゾルバ経由でアクセス
137- result = schemaFactory.newSchema();
138- }else{
139- result = schemaFactory.newSchema(sources);
140- }
141- }catch(SAXException e){ // Build error
142- assert false;
143- throw new AssertionError(e);
144- }
145-
146- // TODO: Sourceを閉めるのは誰の責務?
147-
148- return result;
149- }
150-
151-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/SiblingElemIterator.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/SiblingElemIterator.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
1-/*
2- * sibling element iterator on DOM tree
3- *
4- * License : The MIT License
5- * Copyright(c) 2011 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.util.Iterator;
11-import java.util.NoSuchElementException;
12-import org.w3c.dom.Element;
13-import org.w3c.dom.Node;
14-
15-/**
16- * 兄弟要素間用Iterator。
17- * <p>同じ親と名前空間とローカル名を持つ要素同士を「兄弟要素」とする。
18- * <p>ノードの持つ名前空間がnullの場合、全ての名前空間引数にマッチする。
19- * <p>削除操作は未サポート。
20- */
21-public class SiblingElemIterator implements Iterator<Element> {
22-
23- private Element next;
24- private final String nsuri;
25- private final String localName;
26-
27-
28- /**
29- * コンストラクタ。
30- * @param first 最初の兄弟要素。nullだと一度もiterateしない。
31- */
32- public SiblingElemIterator(Element first){
33- super();
34-
35- this.next = first;
36-
37- if(this.next == null){
38- this.nsuri = null;
39- this.localName = null;
40- }else{
41- this.nsuri = this.next.getNamespaceURI();
42- this.localName = this.next.getLocalName();
43- }
44-
45- return;
46- }
47-
48- /**
49- * コンストラクタ。
50- * <p>名前空間引数にnullが渡された場合、全ての名前空間にマッチする。
51- * <p>ローカル名引数にnullが渡された場合、全てのローカル名にマッチする。
52- * @param parent 親要素
53- * @param nsuri 子要素の名前空間URI
54- * @param localName 子要素のローカル名
55- */
56- public SiblingElemIterator(Element parent,
57- String nsuri,
58- String localName ){
59- super();
60-
61- this.next = DomNsUtils.pickFirstChild(parent, nsuri, localName);
62-
63- if(this.next == null){
64- this.nsuri = null;
65- this.localName = null;
66- }else{
67- this.nsuri = nsuri;
68- this.localName = localName;
69- }
70-
71- return;
72- }
73-
74-
75- /**
76- * {@inheritDoc}
77- * @return {@inheritDoc}
78- */
79- @Override
80- public boolean hasNext(){
81- if(this.next != null) return true;
82- return false;
83- }
84-
85- /**
86- * {@inheritDoc}
87- * @return {@inheritDoc}
88- * @throws NoSuchElementException {@inheritDoc}
89- */
90- @Override
91- public Element next() throws NoSuchElementException {
92- if(this.next == null) throw new NoSuchElementException();
93-
94- Element result = this.next;
95-
96- Node sibNode = result;
97- do{
98- sibNode = sibNode.getNextSibling();
99- if(sibNode == null) break;
100- }while( ! matchElemName(sibNode) );
101- this.next = (Element) sibNode;
102-
103- return result;
104- }
105-
106- /**
107- * 兄弟要素にふさわしい名前を持つか判定する。
108- * @param node 判定対象
109- * @return 兄弟にふさわしい名前を持つならtrue
110- */
111- private boolean matchElemName(Node node){
112- return DomNsUtils.hasNsLocalNameElem(node,
113- this.nsuri, this.localName );
114- }
115-
116- /**
117- * {@inheritDoc}
118- * ※削除不可。
119- * @throws UnsupportedOperationException 削除を試みたので失敗した
120- */
121- @Override
122- public void remove() throws UnsupportedOperationException {
123- throw new UnsupportedOperationException();
124- }
125-
126-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/TogaXmlException.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/TogaXmlException.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
1-/*
2- * exception about xml
3- *
4- * License : The MIT License
5- * Copyright(c) 2010 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-/**
11- * 意図しないXML文書を検出した際の例外。
12- */
13-@SuppressWarnings("serial")
14-public class TogaXmlException extends Exception{
15-
16- /**
17- * コンストラクタ。
18- */
19- public TogaXmlException(){
20- super();
21- return;
22- }
23-
24- /**
25- * コンストラクタ。
26- * @param message メッセージ
27- */
28- public TogaXmlException(String message){
29- super(message);
30- return;
31- }
32-
33- /**
34- * コンストラクタ。
35- * @param message メッセージ
36- * @param cause 原因の例外
37- */
38- public TogaXmlException(String message, Throwable cause){
39- super(message, cause);
40- return;
41- }
42-
43- /**
44- * コンストラクタ。
45- * @param cause 原因の例外
46- */
47- public TogaXmlException(Throwable cause){
48- super(cause);
49- return;
50- }
51-
52-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/XmlExporter.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/XmlExporter.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,318 +0,0 @@
1-/*
2- * xml exporter
3- *
4- * License : The MIT License
5- * Copyright(c) 2013 MikuToga Partners
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.io.Closeable;
11-import java.io.Flushable;
12-import java.io.IOException;
13-
14-/**
15- * XMLエクスポータ基本機能のセット。
16- */
17-public interface XmlExporter extends Appendable, Flushable, Closeable{
18-
19- /**
20- * 1文字を生出力する。
21- * @param ch 文字
22- * @return this本体
23- * @throws IOException 出力エラー
24- */
25- XmlExporter putRawCh(char ch) throws IOException;
26-
27- /**
28- * 文字列を生出力する。
29- * @param seq 文字列
30- * @return this本体
31- * @throws IOException 出力エラー
32- */
33- XmlExporter putRawText(CharSequence seq) throws IOException;
34-
35- /**
36- * 空白を出力する。
37- * @return this本体
38- * @throws IOException 出力エラー
39- */
40- XmlExporter sp() throws IOException;
41-
42- /**
43- * 空白を指定回数出力する。
44- * @param count 空白回数。0以下の場合は何も出力しない。
45- * @return this本体
46- * @throws IOException 出力エラー
47- */
48- XmlExporter sp(int count) throws IOException;
49-
50- /**
51- * 改行文字列を返す。
52- * @return 改行文字列
53- */
54- String getNewLine();
55-
56- /**
57- * 改行文字列を設定する。
58- * @param newLine 改行文字列
59- * @throws NullPointerException 引数がnull
60- */
61- void setNewLine(String newLine) throws NullPointerException;
62-
63- /**
64- * 改行を出力する。
65- * @return this本体
66- * @throws IOException 出力エラー
67- */
68- XmlExporter ln() throws IOException;
69-
70- /**
71- * 改行を指定回数出力する。
72- * @param count 改行回数。0以下の場合は何も出力しない。
73- * @return this本体
74- * @throws IOException 出力エラー
75- */
76- XmlExporter ln(int count) throws IOException;
77-
78- /**
79- * インデント単位文字列を返す。
80- * @return インデント単位文字列
81- */
82- String getIndentUnit();
83-
84- /**
85- * インデント単位文字列を設定する。
86- * <p>デフォルトでは空白2個。
87- * @param indUnit インデント単位文字列。
88- * @throws NullPointerException 引数がnull
89- */
90- void setIndentUnit(String indUnit) throws NullPointerException;
91-
92- /**
93- * インデントレベルを一段下げる。
94- */
95- void pushNest();
96-
97- /**
98- * インデントレベルを一段上げる。
99- * インデントレベル0の状態をさらに上げようとした場合、何も起こらない。
100- */
101- void popNest();
102-
103- /**
104- * インデントレベルを返す。
105- * <p>深さ1の場合1を返す。
106- * @return インデントレベル
107- */
108- int getIndentLevel();
109-
110- /**
111- * インデントを出力する。
112- * インデント単位文字列をネストレベル回数分出力する。
113- * @return this本体
114- * @throws IOException 出力エラー
115- */
116- XmlExporter ind() throws IOException;
117-
118- /**
119- * BasicLatin文字だけを出力する状態か判定する。
120- * <p>コメント部中身は対象外。
121- * @return BasicLatin文字だけで出力するならtrue
122- */
123- boolean isBasicLatinOnlyOut();
124-
125- /**
126- * BasicLatin文字だけで出力するか設定する。
127- * <p>BasicLatin以外の文字(≒日本語)を、そのまま出力するか、
128- * 文字参照で出力するか、の設定が可能。
129- * <p>コメント部中身は対象外。
130- * @param bool BasicLatin文字だけで出力するならtrue
131- */
132- void setBasicLatinOnlyOut(boolean bool);
133-
134- /**
135- * 指定された文字を16進2桁の文字参照形式で出力する。
136- * <p>「A」は「&amp;#x41;」になる。
137- * <p>2桁で出力できない場合(>0x00ff)は4桁で出力する。
138- * @param ch 文字
139- * @return this本体
140- * @throws IOException 出力エラー
141- * @see <a href="http://www.w3.org/TR/xml11/#NT-CharRef">
142- * W3C XML1.1 Character Reference
143- * </a>
144- */
145- XmlExporter putCharRef2Hex(char ch) throws IOException;
146-
147- /**
148- * 指定された文字を16進4桁の文字参照形式で出力する。
149- * <p>「亜」は「&amp;#x4E9C;」になる。
150- * <p>UCS4に伴うサロゲートペアは未サポート
151- * @param ch 文字
152- * @return this本体
153- * @throws IOException 出力エラー
154- * @see <a href="http://www.w3.org/TR/xml11/#NT-CharRef">
155- * W3C XML1.1 Character Reference
156- * </a>
157- */
158- XmlExporter putCharRef4Hex(char ch) throws IOException;
159-
160- /**
161- * 要素の中身および属性値中身を出力する。
162- * <p>XMLの構文規則を守る上で必要な各種エスケープ処理が行われる。
163- * @param ch 文字
164- * @return this本体
165- * @throws IOException 出力エラー
166- */
167- XmlExporter putCh(char ch) throws IOException;
168-
169- /**
170- * 要素の中身および属性値中身を出力する。
171- * <p>必要に応じてXML定義済み実体文字が割り振られた文字、
172- * コントロールコード、および非BasicLatin文字がエスケープされる。
173- * <p>半角円通貨記号U+00A5はバックスラッシュU+005Cに置換される。
174- * <p>連続するスペースU+0020の2文字目以降は文字参照化される。
175- * <p>全角スペースその他空白文字は無条件に文字参照化される。
176- * @param content 内容
177- * @return this本体
178- * @throws IOException 出力エラー
179- */
180- XmlExporter putContent(CharSequence content) throws IOException;
181-
182- /**
183- * コメントの内容を出力する。
184- * <p>コメント中の'\n'記号出現に伴い、
185- * あらかじめ指定された改行文字が出力される。
186- * <p>コメント中の'\n'以外のコントロールコードは
187- * Control Pictures(U+2400〜)で代替される。
188- * <p>それ以外の非BasicLatin文字はそのまま出力される。
189- * <p>連続するハイフン(-)記号間には強制的にスペースが挿入される。
190- * @param comment コメント内容
191- * @return this本体
192- * @throws IOException 出力エラー
193- * <a href="http://www.unicode.org/charts/PDF/U2400.pdf">
194- * Unicode 6.2 Controll Pictures
195- * </a>
196- */
197- XmlExporter putCommentContent(CharSequence comment) throws IOException;
198-
199- /**
200- * 1行コメントを出力する。
201- * コメント内部の頭及び末尾に空白が1つ挿入される。
202- * @param comment コメント内容
203- * @return this本体
204- * @throws IOException 出力エラー
205- */
206- XmlExporter putLineComment(CharSequence comment) throws IOException;
207-
208- /**
209- * ブロックコメントを出力する。
210- * <p>コメント内部の頭の前に改行が出力される。
211- * <p>コメント内部の末尾が改行でない場合、改行が挿入される。
212- * <p>ブロックコメント末尾は改行で終わる。
213- * <p>インデント設定は無視される。
214- * @param comment コメント内容
215- * @return this本体
216- * @throws IOException 出力エラー
217- */
218- XmlExporter putBlockComment(CharSequence comment) throws IOException;
219-
220- /**
221- * 開始タグ開き表記を出力する。
222- * @param tagName タグ名
223- * @return this本体
224- * @throws IOException 出力エラー
225- */
226- XmlExporter putOpenSTag(CharSequence tagName) throws IOException;
227-
228- /**
229- * 開始タグ閉じ表記を出力する。
230- * @return this本体
231- * @throws IOException 出力エラー
232- */
233- XmlExporter putCloseSTag() throws IOException;
234-
235- /**
236- * 属性の無いシンプルな開始タグ表記を出力する。
237- * @param tagName タグ名
238- * @return this本体
239- * @throws IOException 出力エラー
240- */
241- XmlExporter putSimpleSTag(CharSequence tagName) throws IOException;
242-
243- /**
244- * 終了タグ表記を出力する。
245- * @param tagName タグ名
246- * @return this本体
247- * @throws IOException 出力エラー
248- */
249- XmlExporter putETag(CharSequence tagName) throws IOException;
250-
251- /**
252- * 属性の無い単出タグ表記を出力する。
253- * @param tagName タグ名
254- * @return this本体
255- * @throws IOException 出力エラー
256- */
257- XmlExporter putSimpleEmpty(CharSequence tagName) throws IOException;
258-
259- /**
260- * 単出タグ閉じ表記を出力する。
261- * @return this本体
262- * @throws IOException 出力エラー
263- */
264- XmlExporter putCloseEmpty() throws IOException;
265-
266- /**
267- * xsd:int値をXMLスキーマ準拠の形式で出力する。
268- * @param iVal int値
269- * @return this本体
270- * @throws IOException 出力エラー
271- * @see <a href="http://www.w3.org/TR/xmlschema11-2/#int">
272- * XML Schema 1.1 Datatypes int
273- * </a>
274- */
275- XmlExporter putXsdInt(int iVal) throws IOException;
276-
277- /**
278- * xsd:float値をXMLスキーマ準拠の形式で出力する。
279- * @param fVal float値
280- * @return this本体
281- * @throws IOException 出力エラー
282- * @see <a href="http://www.w3.org/TR/xmlschema11-2/#sec-lex-float">
283- * XML Schema 1.1 Datatypes float Lexical Mapping
284- * </a>
285- */
286- XmlExporter putXsdFloat(float fVal) throws IOException;
287-
288- /**
289- * int型属性値を出力する。
290- * @param attrName 属性名
291- * @param iVal int値
292- * @return this本体
293- * @throws IOException 出力エラー
294- */
295- XmlExporter putIntAttr(CharSequence attrName, int iVal)
296- throws IOException;
297-
298- /**
299- * float型属性値を出力する。
300- * @param attrName 属性名
301- * @param fVal float値
302- * @return this本体
303- * @throws IOException 出力エラー
304- */
305- XmlExporter putFloatAttr(CharSequence attrName, float fVal)
306- throws IOException;
307-
308- /**
309- * 属性値を出力する。
310- * @param attrName 属性名
311- * @param content 属性内容
312- * @return this本体
313- * @throws IOException 出力エラー
314- */
315- XmlExporter putAttr(CharSequence attrName, CharSequence content)
316- throws IOException;
317-
318-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/XmlResourceResolver.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/XmlResourceResolver.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,472 +0,0 @@
1-/*
2- * xml resource resolver
3- *
4- * License : The MIT License
5- * Copyright(c) 2009 olyutorskii
6- */
7-
8-package jp.sourceforge.mikutoga.xml;
9-
10-import java.io.IOException;
11-import java.io.InputStream;
12-import java.io.Reader;
13-import java.net.URI;
14-import java.net.URISyntaxException;
15-import java.net.URL;
16-import java.util.Collections;
17-import java.util.HashMap;
18-import java.util.Map;
19-import org.w3c.dom.ls.LSInput;
20-import org.w3c.dom.ls.LSResourceResolver;
21-import org.xml.sax.EntityResolver;
22-import org.xml.sax.InputSource;
23-import org.xml.sax.SAXException;
24-
25-/**
26- * URL変換マップに従い、XML文書からの外部参照をリダイレクトする。
27- * 相対URIはこのクラスをベースに解決される。
28- * 主な用途は外部スキーマのリソース化など。
29- */
30-public class XmlResourceResolver
31- implements LSResourceResolver, EntityResolver {
32-
33- /** XML Schema. */
34- public static final String SCHEMA_XML =
35- "http://www.w3.org/2001/xml.xsd";
36-
37- /** XSD名前空間。 */
38- public static final String NS_XSD =
39- "http://www.w3.org/2001/XMLSchema-instance";
40-
41- private static final String LOCAL_SCHEMA_XML =
42- "resources/xmlspace.xsd";
43-
44- private static final URI EMPTY_URI = URI.create("");
45-
46- private static final Class<?> THISCLASS = XmlResourceResolver.class;
47-
48-
49- private final Map<URI, URI> uriMap;
50-
51-
52- /**
53- * コンストラクタ。
54- */
55- public XmlResourceResolver(){
56- super();
57-
58- assert this.getClass().equals(THISCLASS);
59-
60- Map<URI, URI> map;
61- map = new HashMap<URI, URI>();
62- map = Collections.synchronizedMap(map);
63- this.uriMap = map;
64-
65- URL redirectRes = THISCLASS.getResource(LOCAL_SCHEMA_XML);
66- String redirectResName = redirectRes.toString();
67-
68- URI originalURI = URI.create(SCHEMA_XML);
69- URI redirectURI = URI.create(redirectResName);
70-
71- putRedirectedImpl(originalURI, redirectURI);
72-
73- return;
74- }
75-
76-
77- /**
78- * 絶対URIと相対URIを合成したURIを返す。
79- * 正規化も行われる。
80- * @param base 絶対URIでなければならない。nullでもよい。
81- * @param relative 絶対URIでもよいがその場合baseは無視される。null可。
82- * @return 合成結果のURLオブジェクト。必ず絶対URIになる。
83- * @throws java.net.URISyntaxException URIとして変。
84- * @throws java.lang.IllegalArgumentException 絶対URIが生成できない。
85- */
86- protected static URI buildBaseRelativeURI(String base, String relative)
87- throws URISyntaxException,
88- IllegalArgumentException {
89- URI baseURI;
90- if(base != null){
91- baseURI = new URI(base);
92- if( ! baseURI.isAbsolute() ){
93- throw new IllegalArgumentException();
94- }
95- }else{
96- baseURI = null;
97- }
98-
99- URI relativeURI;
100- if(relative != null){
101- relativeURI = new URI(relative);
102- }else{
103- relativeURI = EMPTY_URI;
104- }
105-
106- URI resultURI;
107- if(baseURI == null || relativeURI.isAbsolute()){
108- resultURI = relativeURI;
109- }else{
110- resultURI = baseURI.resolve(relativeURI);
111- }
112-
113- if( ! resultURI.isAbsolute() ){
114- throw new IllegalArgumentException();
115- }
116-
117- resultURI = resultURI.normalize();
118-
119- return resultURI;
120- }
121-
122- /**
123- * LSInput実装を生成する。
124- * @return LSInput実装
125- */
126- public static LSInput createLSInput(){
127- LSInput input = new LSInputImpl();
128- return input;
129- }
130-
131-
132- /**
133- * オリジナルURIとリダイレクト先のURIを登録する。
134- * オリジナルURIへのアクセスはリダイレクトされる。
135- * @param original オリジナルURI
136- * @param redirect リダイレクトURI
137- */
138- private void putRedirectedImpl(URI original, URI redirect){
139- URI oridinalNorm = original.normalize();
140- URI redirectNorm = redirect.normalize();
141-
142- this.uriMap.put(oridinalNorm, redirectNorm);
143-
144- return;
145- }
146-
147- /**
148- * オリジナルURIとリダイレクト先のURIを登録する。
149- * オリジナルURIへのアクセスはリダイレクトされる。
150- * @param original オリジナルURI
151- * @param redirect リダイレクトURI
152- */
153- public void putRedirected(URI original, URI redirect){
154- putRedirectedImpl(original, redirect);
155- return;
156- }
157-
158- /**
159- * ローカル版リソース参照解決を登録する。
160- * @param lsc ローカル版リソース参照解決
161- */
162- public void putRedirected(LocalXmlResource lsc){
163- URI original = lsc.getOriginalResource();
164- if(original == null) return;
165-
166- URI local = lsc.getLocalResource();
167-
168- putRedirected(original, local);
169-
170- return;
171- }
172-
173- /**
174- * 別リゾルバの登録内容を追加登録する。
175- * @param other 別リゾルバ
176- */
177- public void putRedirected(XmlResourceResolver other){
178- this.uriMap.putAll(other.uriMap);
179- return;
180- }
181-
182- /**
183- * 登録済みリダイレクト先URIを返す。
184- * @param original オリジナルURI
185- * @return リダイレクト先URI。未登録の場合はnull
186- */
187- public URI getRedirected(URI original){
188- URI keyURI = original.normalize();
189- URI resourceURI = this.uriMap.get(keyURI);
190- return resourceURI;
191- }
192-
193- /**
194- * 登録済みリダイレクト先URIを返す。
195- * @param original オリジナルURI
196- * @return リダイレクト先URI。未登録の場合はオリジナルを返す
197- */
198- public URI resolveRedirected(URI original){
199- URI result = getRedirected(original);
200- if(result == null) result = original;
201- return result;
202- }
203-
204- /**
205- * 登録済みリダイレクト先リソースの入力ストリームを得る。
206- * @param originalURI オリジナルURI
207- * @return 入力ストリーム。リダイレクト先が未登録の場合はnull
208- * @throws java.io.IOException 入出力エラー。
209- * もしくはリソースが見つからない。
210- */
211- private InputStream getXMLResourceAsStream(URI originalURI)
212- throws IOException{
213- URI resourceURI = getRedirected(originalURI);
214- if(resourceURI == null) return null;
215-
216- URL resourceURL = resourceURI.toURL();
217- InputStream is = resourceURL.openStream();
218-
219- return is;
220- }
221-
222- /**
223- * {@inheritDoc}
224- * URL変換したあとの入力ソースを返す。
225- * @param type {@inheritDoc}
226- * @param namespaceURI {@inheritDoc}
227- * @param publicId {@inheritDoc}
228- * @param systemId {@inheritDoc}
229- * @param baseURI {@inheritDoc}
230- * @return {@inheritDoc}
231- */
232- @Override
233- public LSInput resolveResource(String type,
234- String namespaceURI,
235- String publicId,
236- String systemId,
237- String baseURI ){
238- if(systemId == null) return null;
239-
240- URI originalURI;
241- try{
242- originalURI = buildBaseRelativeURI(baseURI, systemId);
243- }catch(URISyntaxException e){
244- return null;
245- }
246-
247- InputStream is;
248- try{
249- is = getXMLResourceAsStream(originalURI);
250- }catch(IOException e){
251- return null;
252- }
253- if(is == null) return null;
254-
255- LSInput input = createLSInput();
256- input.setBaseURI(baseURI);
257- input.setPublicId(publicId);
258- input.setSystemId(systemId);
259- input.setByteStream(is);
260-
261- return input;
262- }
263-
264- /**
265- * {@inheritDoc}
266- * URL変換したあとの入力ソースを返す。
267- * @param publicId {@inheritDoc}
268- * @param systemId {@inheritDoc}
269- * @return {@inheritDoc}
270- * @throws org.xml.sax.SAXException {@inheritDoc}
271- * @throws java.io.IOException {@inheritDoc}
272- */
273- @Override
274- public InputSource resolveEntity(String publicId, String systemId)
275- throws SAXException, IOException{
276- if(systemId == null) return null;
277-
278- URI originalUri;
279- try{
280- originalUri = new URI(systemId);
281- }catch(URISyntaxException e){
282- return null;
283- }
284-
285- InputStream is = getXMLResourceAsStream(originalUri);
286- if(is == null) return null;
287-
288- InputSource source = new InputSource(is);
289- source.setPublicId(publicId);
290- source.setSystemId(systemId);
291-
292- return source;
293- }
294-
295- /**
296- * JRE1.5用LSInput実装。
297- * JRE1.6なら
298- * org.w3c.dom.ls.DOMImplementationLS#createLSInput()
299- * で生成可能かも。
300- */
301- private static final class LSInputImpl implements LSInput {
302-
303- private String baseURI = null;
304- private InputStream byteStream = null;
305- private boolean certifiedText = false;
306- private Reader characterStream = null;
307- private String encoding = null;
308- private String publicId = null;
309- private String stringData = null;
310- private String systemId = null;
311-
312- /**
313- * コンストラクタ。
314- */
315- LSInputImpl(){
316- super();
317- return;
318- }
319-
320- /**
321- * {@inheritDoc}
322- * @return {@inheritDoc}
323- */
324- @Override
325- public String getBaseURI(){
326- return this.baseURI;
327- }
328-
329- /**
330- * {@inheritDoc}
331- * @param baseURI {@inheritDoc}
332- */
333- @Override
334- public void setBaseURI(String baseURI){
335- this.baseURI = baseURI;
336- return;
337- }
338-
339- /**
340- * {@inheritDoc}
341- * @return {@inheritDoc}
342- */
343- @Override
344- public InputStream getByteStream(){
345- return this.byteStream;
346- }
347-
348- /**
349- * {@inheritDoc}
350- * @param byteStream {@inheritDoc}
351- */
352- @Override
353- public void setByteStream(InputStream byteStream){
354- this.byteStream = byteStream;
355- }
356-
357- /**
358- * {@inheritDoc}
359- * @return {@inheritDoc}
360- */
361- @Override
362- public boolean getCertifiedText(){
363- return this.certifiedText;
364- }
365-
366- /**
367- * {@inheritDoc}
368- * @param certifiedText {@inheritDoc}
369- */
370- @Override
371- public void setCertifiedText(boolean certifiedText){
372- this.certifiedText = certifiedText;
373- return;
374- }
375-
376- /**
377- * {@inheritDoc}
378- * @return {@inheritDoc}
379- */
380- @Override
381- public Reader getCharacterStream(){
382- return this.characterStream;
383- }
384-
385- /**
386- * {@inheritDoc}
387- * @param characterStream {@inheritDoc}
388- */
389- @Override
390- public void setCharacterStream(Reader characterStream){
391- this.characterStream = characterStream;
392- }
393-
394- /**
395- * {@inheritDoc}
396- * @return {@inheritDoc}
397- */
398- @Override
399- public String getEncoding(){
400- return this.encoding;
401- }
402-
403- /**
404- * {@inheritDoc}
405- * @param encoding {@inheritDoc}
406- */
407- @Override
408- public void setEncoding(String encoding){
409- this.encoding = encoding;
410- return;
411- }
412-
413- /**
414- * {@inheritDoc}
415- * @return {@inheritDoc}
416- */
417- @Override
418- public String getPublicId(){
419- return this.publicId;
420- }
421-
422- /**
423- * {@inheritDoc}
424- * @param publicId {@inheritDoc}
425- */
426- @Override
427- public void setPublicId(String publicId){
428- this.publicId = publicId;
429- return;
430- }
431-
432- /**
433- * {@inheritDoc}
434- * @return {@inheritDoc}
435- */
436- @Override
437- public String getStringData(){
438- return this.stringData;
439- }
440-
441- /**
442- * {@inheritDoc}
443- * @param stringData {@inheritDoc}
444- */
445- @Override
446- public void setStringData(String stringData){
447- this.stringData = stringData;
448- return;
449- }
450-
451- /**
452- * {@inheritDoc}
453- * @return {@inheritDoc}
454- */
455- @Override
456- public String getSystemId(){
457- return this.systemId;
458- }
459-
460- /**
461- * {@inheritDoc}
462- * @param systemId {@inheritDoc}
463- */
464- @Override
465- public void setSystemId(String systemId){
466- this.systemId = systemId;
467- return;
468- }
469-
470- }
471-
472-}
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/java/jp/sourceforge/mikutoga/xml/package-info.java
--- a/src/main/java/jp/sourceforge/mikutoga/xml/package-info.java Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
1-/*
2- * package information for Javadoc
3- *
4- * License : The MIT License
5- * Copyright(c) 2010 MikuToga Partners
6- */
7-
8-/**
9- * MikuToga XML共通ライブラリ。
10- */
11-
12-package jp.sourceforge.mikutoga.xml;
13-
14-/* EOF */
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/resources/jp/sfjp/mikutoga/xml/resources/xmlspace.xsd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/jp/sfjp/mikutoga/xml/resources/xmlspace.xsd Sat Jun 08 13:30:16 2013 +0900
@@ -0,0 +1,37 @@
1+<?xml version="1.0" encoding="UTF-8" ?>
2+
3+<xsd:schema
4+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
5+ targetNamespace="http://www.w3.org/XML/1998/namespace"
6+>
7+
8+ <xsd:annotation>
9+ <xsd:documentation>
10+ Only for using "xml:space" in XML schema definition.
11+ See
12+ http://www.w3.org/2001/xml.xsd
13+ http://www.w3.org/2009/01/xml.xsd
14+ </xsd:documentation>
15+ </xsd:annotation>
16+
17+ <xsd:attribute name="space">
18+
19+ <xsd:annotation>
20+ <xsd:documentation>
21+ about xml:space attribute
22+ </xsd:documentation>
23+ </xsd:annotation>
24+
25+ <xsd:simpleType>
26+ <xsd:restriction base="xsd:NCName">
27+ <xsd:enumeration value="default"/>
28+ <xsd:enumeration value="preserve"/>
29+ </xsd:restriction>
30+ </xsd:simpleType>
31+
32+ </xsd:attribute>
33+
34+</xsd:schema>
35+
36+
37+<!-- EOF -->
diff -r 35f967fe1b71 -r ec69393f6ebc src/main/resources/jp/sourceforge/mikutoga/xml/resources/xmlspace.xsd
--- a/src/main/resources/jp/sourceforge/mikutoga/xml/resources/xmlspace.xsd Tue May 21 23:10:18 2013 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
1-<?xml version="1.0" encoding="UTF-8" ?>
2-
3-<xsd:schema
4- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
5- targetNamespace="http://www.w3.org/XML/1998/namespace"
6->
7-
8- <xsd:annotation>
9- <xsd:documentation>
10- Only for using "xml:space" in XML schema definition.
11- See
12- http://www.w3.org/2001/xml.xsd
13- http://www.w3.org/2009/01/xml.xsd
14- </xsd:documentation>
15- </xsd:annotation>
16-
17- <xsd:attribute name="space">
18-
19- <xsd:annotation>
20- <xsd:documentation>
21- about xml:space attribute
22- </xsd:documentation>
23- </xsd:annotation>
24-
25- <xsd:simpleType>
26- <xsd:restriction base="xsd:NCName">
27- <xsd:enumeration value="default"/>
28- <xsd:enumeration value="preserve"/>
29- </xsd:restriction>
30- </xsd:simpleType>
31-
32- </xsd:attribute>
33-
34-</xsd:schema>
35-
36-
37-<!-- EOF -->
diff -r 35f967fe1b71 -r ec69393f6ebc src/test/java/sample/vmd/DummyHandler.java
--- a/src/test/java/sample/vmd/DummyHandler.java Tue May 21 23:10:18 2013 +0900
+++ b/src/test/java/sample/vmd/DummyHandler.java Sat Jun 08 13:30:16 2013 +0900
@@ -218,6 +218,20 @@
218218 return;
219219 }
220220
221+ @Override
222+ public void vmdModelSight(boolean show, int keyFrameNo){
223+ println("modelSight : frame#=" + keyFrameNo + " show=" + show);
224+ return;
225+ }
226+
227+ @Override
228+ public void vmdIkSwitch(String boneName,
229+ boolean validIk,
230+ int keyFrameNo ){
231+ println("IKSwitch : frame#=" + keyFrameNo + " bone=" + boneName + " valid=" + validIk);
232+ return;
233+ }
234+
221235 private void println(String msg){
222236 System.out.println(msg);
223237 return;
diff -r 35f967fe1b71 -r ec69393f6ebc src/test/java/sample/vmd/DummyMain.java
--- a/src/test/java/sample/vmd/DummyMain.java Tue May 21 23:10:18 2013 +0900
+++ b/src/test/java/sample/vmd/DummyMain.java Sat Jun 08 13:30:16 2013 +0900
@@ -27,8 +27,8 @@
2727 private static final DummyHandler handler = new DummyHandler();
2828
2929 static{
30-// VMDFILE = "D:\\Test\\test.vmd";
31- VMDFILE = "D:\\Test\\camera.vmd";
30+ VMDFILE = "D:\\Test\\test.vmd";
31+// VMDFILE = "D:\\Test\\camera.vmd";
3232 }
3333
3434 private static InputStream buildSource(String fname){
@@ -52,6 +52,7 @@
5252 parser.setBasicHandler(handler);
5353 parser.setLightingHandler(handler);
5454 parser.setCameraHandler(handler);
55+ parser.setBoolHandler(handler);
5556
5657 return;
5758 }
@@ -66,7 +67,6 @@
6667 VmdParser parser = new VmdParser(source);
6768
6869 setupHandler(parser);
69- parser.setIgnoreName(true);
7070 parser.setRedundantCheck(false);
7171
7272 try{
Show on old repository browser