ボンジュール・マドモアゼル

本サイトの情報は自己責任にてご利用下さい。

[正誤表] Java GUIプログラミング Java SE6対応 Vol.I 初版第3刷 正誤表

 
以下、「Java GUIプログラミング Java SE6対応 Vol.I 初版第3刷」にて見つかった誤記です。

全般
本書の全てのサンプルコードが GUI の起動を main スレッドで行っているが、
これは、スレッド安全上危険なやり方である。
正しくは、以下のように invokeLater() メソッドによって起動する。
    public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowFrame();
}
});
}
private static void createAndShowFrame() {
JFrame frame = new JFrame("JFrame02");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
Swingの起動方法については以下の記事が参考になる。特に Java Tutorials の次の記述に注意。
Why does not the initial thread simply create the GUI itself? Because almost all code that creates or interacts with Swing components must run on the event dispatch thread.
なぜ、最初のスレッドが単純にGUI自体を作成しないのか、それは、Swingコンポーネントを作成するか、相互作用するほぼすべてのコードは、イベントディスパッチスレッド上で実行する必要があるためです。


Q4.3 SwingのGUIを起動する正しいやり方は?
http://homepage1.nifty.com/algafield/JavaGUIFaq19j.html#four3

The Java Tutorials — Creating a GUI With JFC/Swing > Concurrency in Swing > Initial Threads > Initial Threads
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html

Java Tutorials Code Sample — HelloWorldSwing.java
http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/start/HelloWorldSwingProject/src/start/HelloWorldSwing.java

p.2
したがって、サンプルプログラムJFrame01.javaのクラスは、JFrameを継承していることになる。
→サンプルプログラムの JFrame01 クラスは何も継承していない。

p.16
シャットダウンフックは、後から登録したものから先に呼び出される。
→ シャットダウンフックの呼び出し順序は規定されていない。登録したものは何らかの順序で並行して実行される。
Runtime クラスの addShutdownHook メソッドについて Javadoc には次のように書かれている。

When the virtual machine begins its shutdown sequence it will start all
registered shutdown hooks in some unspecified order and let them run concurrently.
仮想マシンがシャットダウンシーケンスを開始すると、すべての登録済みシャットダウンフックを、
指定されていない順序で起動し並行して実行します。

p.18

■シャットダウンフックを指定したときには、このような順序で呼び出される
→ 呼び出し順序は規定されていない。さらに登録したものは並行して実行されるため、
呼び出し順序と出力結果の順序は必ずしも一致しない。

p.28
contentPane.setToolTipText("ContentPane は Swing コンポーネントです");
→ サンプルコードとして書式スタイルが設定されていない、行の下に水平線がない。

p.34
レイアウトマネージャーに関しては、別巻で詳しく取り上げる。
→ 具体的にどの巻か? vol. の目次にはそれらしいのが見当たらない。

p.54
誤:label1の東側とlabel1の西側が向き合うので、Label1の右側にLabel2が位置することになる。
正:label1の東側とlabel2の西側が向き合うので、Label1の右側にLabel2が位置することになる。
※label1の西側 → label2の西側

p.66
ImageLabel02.java
    public int getIconWidth() {

return this.width;
}
public int getIconHeight() {
return this.height;
}
→ 動作はするが、width, height は静的変数なので
this.width を width または DrawIcon.width にするか、
もしくは、width をインスタンス変数にするべき。
height についても同様。

p.67
誤:この例では、アイコンは幅・高さともに32ピクセルで、赤く塗りつぶした円が描画される。
正:この例では、アイコンは幅・高さともに100ピクセルで、緑色で塗りつぶした円が描画される。
※ 32ピクセル→100ピクセル、赤く→緑色

p.90
MenuTest05.java
    //System.out.println( e );
→ 下から7行目の行が余計。
//System.out.println( e ); //イベント内容を出力する
などのコメントを付加するか、この行を削除した方が良い。

p.96
ImageButton02.java
    public TestIcon() {

誤) color = Color.red;
正) color = Color.white;
}
p.96
ImageButton02.java
    public int getIconWidth() {

return this.width;
}
public int getIconHeight() {
return this.height;
}
→ 動作はするが、width, height は静的変数なので
this.width を width または DrawIcon.width にするか、
もしくは、width をインスタンス変数にするべき。
height についても同様。

p.127
誤:<br>タグは単なる改行にだけでなく、パラグラフ指定の意味もある。
正:<p>タグは単なる改行だけでなく、パラグラフ指定の意味もある。
※<br> → <p>,
改行にだけでなく → 改行だけでなく

p.131
Html10.java
frame.setDefaultCloseOperation(3); // EXIT_ON_CLOSE
次のように修正するべき。
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
以下のページについても同様。
p.133 Html10A.java
p.137 Html11.java
p.141 Html12.java
p.144 Html13.java
p.146 Html14.java
p.149 Html15.java
p.153 Html16.java
p.156 Html16A.java
p.160 Html17.java
p.162 Html18.java

p.154
■JTabbedPane でHTML指定
→ 掲載された図には JLabelオブジェクト month が表示されていない。
アプリケーション起動後、いずれかのタブを選択し、
month を表示させてから、ハードコピーを取ると以下のようになる。
Html16 表示結果差し替え版

p.158
■タブが表示される位置を変えられる
→ 掲載された図には JLabelオブジェクト month が表示されていない。
アプリケーション起動後、いずれかのタブを選択し、
month を表示させてから、ハードコピーを取ると以下のようになる。
Html16A 表示結果差し替え版

p.177
誤:ラジオボタンは、Contentpaneに追加するだけでなく、ButtonGroupにも追加する。
正:ラジオボタンは、ContentPaneに追加するだけでなく、ButtonGroupにも追加する。
※ Contentpane → ContentPane

p.216
    if (label == 'C') {

field.setText("");
(追加) arg = "";
opeCode = '+';
arg1 = 0;
lastTimeNum = false;
System.out.println("arg1:" + arg1);
return;
}
※ 元のコードには以下のようなバグがある。
【バグ内容】電卓の C ボタンを押した際、バッファ arg をクリアしていないため、
C ボタンでテキストフィールド上の数字をクリアしても、
再び数字を打ち始めると、それまで打った内容が復活してしまう。

p.282
誤:メッセージボックスはshowMessage Dialog()メソッドを使って生成する。
正:メッセージボックスはshowMessageDialog()メソッドを使って生成する。
※ showMessage Dialog() → showMessageDialog()

p.283
→ この章のほかの図とは違い「■最も単純なメッセージボックス」のハードコピーだけ、
メッセージボックスのみが含まれ、メインウィンドウが含まれていない。

p.284
第1引数の説明の4行目の「代引き数」は、「第1引数」の誤記であると思われる。

p.308
[取消し] ボタンが押された場合には、nullが返される。
→ この文は、「6-7 JOptionPaneの中にコンポーネントを置く」の1行目の文となっているが、
「6-6 コンボボックスを持つダイアログボックス〜」の最後の1文であるべき。

p.309
DialogTest07.java の実行結果が「■JOptionPaneには、さまざまなコンポーネントを置ける」の図と一致しない。
図を修正するか、DialogTest07.java を以下のように修正する必要がある。
サンプルコードを以下のように修正する場合には、p.310 のコード解説にあるコードも修正が必要となる。
        public void actionPerformed(ActionEvent e) {


String[] choice = { "One", "Two", "Three" };
JList li = new JList(choice);

(追加) JRadioButton rb = new JRadioButton("ラジオボタン", true);
(追加) JCheckBox cb = new JCheckBox("チェックボックス", true);

(修正) Object[] option = {li, rb, cb};
int ans = JOptionPane.showConfirmDialog(pane, option,
"JOptionの中でJListが使える",
JOptionPane.OK_CANCEL_OPTION);
System.out.println(li.getSelectedValue());
(追加) System.out.println(rb.isSelected());
(追加) System.out.println(cb.isSelected());
}
p.319
誤:String[] extensions = { "gif", "jpg" };
正:String[] extensions = { ".gif", ".jpg" };

※ 訂正後のコードは、gif, jpg の前にドットを付加。
元のコードでは、「jjjjpg」のようなファイル名で
拡張子のないファイルも表示されてしまう。

p.321
誤:String[] extensions = { "gif", "jpg" };
正:String[] extensions = { ".gif", ".jpg" };
※ 訂正後のコードは、gif, jpg の前にドットを付加。

p.324-p.325
JListTest01.java の実行結果が「■JListの最も基本的な例」の図と一致しない。
図、または、サンプルコードを修正するか、その両方を修正する必要がある。
図に合わせサンプルコードのみを修正する場合、コードの修正内容は以下のとおり。

String[] choice = { "Lisp", "C++", "Smalltalk", "Java" };

String[] choice = { "1111", "2222", "3333", "4444", "5555", "6666", "7777", "8888" };

サンプルコードを修正する場合には、p.325 のコード解説に再掲されたコードも修正が必要となる。

p.338
String[] choice = { "1111", "2222", "3333", "4444", "5555" };
をコンストラクタ内のローカル変数ではなく、JListTest03A のインスタンス変数として定義すべき。
そうしないと、同ページ内にある次のコメント行を有効にした場合、コンパイルエラーが発生する。
それか、このコメント行を削除すべき。
// String select = choice[selectNo];

p.347
JListTest03.java で使われている getValueIsAdjusting()メソッドの説明がない。
→ getValueIsAdjusting() は、p.340 の「●getValueIsAdjusting()〜選択状態が確定したか」で
説明されているが、初出のここで説明するべき。

p.354
誤:String[] choice = { "Java", "C", "C++", "SmallTalk", "Lisp", "Prolog", "Pascal" };
正:String[] choice = { "Java", "C", "C++", "Smalltalk", "Lisp", "Prolog", "Pascal" };
※ Smalltalk の t は小文字。

p.356, p.358 にも同様の訂正が必要。
それに加えて以下のハードコピーも訂正が必要。
(p.356) ■ListModelを使っていると、項目名を変更できる
(p.360) ■変更・追加・削除ができるようにする

p.357
誤:[Java, C, C++, SmallTalk, Lisp, Prolog, Pascal]
正:[Java, C, C++, Smalltalk, Lisp, Prolog, Pascal]

p.357
「●JListからDefaultListModelを取り出す」のコード解説に再掲されるサンプルコード

JList list = (JList) e.getSource();
System.out.println(list.getModel());

→ System.out.println(list.getModel()); は、
 「●DefaultListModelの内容をダンプする」で解説済み。
 次のコードの方が解説内容に合致する。

DefaultListModel model = (DefaultListModel) list.getModel();

p.360
誤:int ans = JOptionPane.showOptionDialog( frame, obj, "Edit List",
正:int ans = JOptionPane.showOptionDialog( frame, obj, "リスト内容の変更",

p.360
誤:ダイアログボックスに複数のボタンを置くのに、JOptionPane.showOption Dialog()を使う。
正:ダイアログボックスに複数のボタンを置くのに、JOptionPane.showOptionDialog()を使う。
※ showOption Dialog() → showOptionDialog()

p.365
最後の一文
誤:やはり、不透明表示を指示する必要がある。
正:不透明表示を無効にする必要がある。

p.369
誤:それを行うには、独自のList SelectionModel
正:それを行うには、独自のListSelectionModel

p.370
誤:Shiftキーを押さずに、ただ単に項目を連続敵に
正:Shiftキーを押さずに、ただ単に項目を連続的に
※連続敵 → 連続的

p.371
1行目
誤:コンポーネント内の各項目をどのように表示するかを
正:コンポーネント内の各項目をどのように選択するかを
※どのように表示するか → どのように選択するか

p.392
PrimeNumbersTask クラスを以下のように修正するべき。
PrimeNumbersTask のコンストラクタは
JTextArea の引数を取っているので、
それをインスタンス変数に保存するべき。
あるいは、コンストラクタの引数から textArea を削除するか。
    class PrimeNumbersTask extends SwingWorker<List<Integer>, Integer> {

int current = 1;
int numbersToFind = 1;
(追加) JTextArea textArea = null;
public PrimeNumbersTask(JTextArea textArea, int n) {
numbersToFind = n;
(追加) this.textArea = textArea;
}
...
p.392
2は素数だから IsPrimeにおいて n が2の場合 false を返すのは間違い。
    private boolean IsPrime(int n) {

int i = 0;
if (n < 2) return true;
(誤) else if (n == 2) return false;
(正) else if (n == 2) return true;
if (n % 2 == 0) return false;
for (i = 3; i * i <= n; i += 2)
if (n % i == 0) return false;
return true;
}
p.392, p.395
Java の慣習に従い、以下3箇所の IsPrimeメソッド名を isPrime に直すべき。
(p.392) private boolean IsPrime(int n) {
(p.392) b = isPrime(++current);
(p.395) private boolean IsPrime(int n) {

以上

[Web開発] Java における各種 XML シリアライザの出力結果

 
http://monado.dtiblog.com/blog-entry-175.html の続き。

検証内容
子要素として、接頭辞が未指定で作成された rect 要素を持つルート要素 svg:svg を作成し、
以下の各シリアライザでそれぞれどのようにシリアライズされるかを確認する。


また、シリアライザによって DOM ツリーが変更されることを見るため、
要素 svg:svg を都度、再生成し、シリアライズされた XML 文字列の前後に要素 svg:svg のDOMツリーを印刷する。

注意事項
Xerces の XMLSerializer は Javadocで以下のように書かれてる通り既に非推奨になっている。
Deprecated. This class was deprecated in Xerces 2.9.0. It is recommended that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation API for XML (TrAX) for serializing XML.
推奨されていません。このクラスは、Xercesは2.9.0で非推奨になりました。新しいアプリケーションでは、XMLをシリアル化するために XMLDOM Level 3LSSerializer または JAXPTransformation API(TrAX) を使用することをお勧めします。


検証用コード

import java.io.ByteArrayOutputStream;

import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xml.serializer.OutputPropertiesFactory;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;

public class NSTest {

static final String SVG_NS = "http://www.w3.org/2000/svg";

public static abstract class TestTemplate {

private String title;

public TestTemplate(String title) {
this.title = title;
}

abstract public String serialize(Element element) throws Exception;

public void runTest() throws Exception {
printTitle();

Element element = createTestElement();
printNode(element, 0);

System.out.println(serialize(element));

System.out.println();
printNode(element, 0);
}

public void printTitle() {
System.out.println(repeat("#", 80));
System.out.println("\t\t" + title);
System.out.println(repeat("#", 80));
System.out.println();
}

public Element createTestElement() throws Exception {

DocumentBuilderFactory dbfactory = DocumentBuilderFactory
.newInstance();
dbfactory.setNamespaceAware(true);
DocumentBuilder builder = dbfactory.newDocumentBuilder();
Document doc = builder.newDocument();

// 要素rootを作成する.
Element root = doc.createElementNS(SVG_NS, "svg:svg");
// 要素 el1 は名前空間プレフィックスを指定せずに作成する.
Element el1 = doc.createElementNS(SVG_NS, "rect");
root.appendChild(el1);

return root;
}
}

public static void main(String[] argv) throws Exception {

/**********************************************************************/
// JAXP Transformer クラスを使ったシリアライズ.
/**********************************************************************/
(new TestTemplate("JAXP's Transformer") {

public String serialize(Element element) throws Exception {

TransformerFactory tff = TransformerFactory.newInstance();
Transformer transformer = tff.newTransformer();

// XML宣言の省略を指示する.
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
// インデント出力を指示する。
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// インデント幅を設定する。
transformer.setOutputProperty(
OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "4");

// シリアライズする DOM オブジェクト
DOMSource src = new DOMSource(element);

// シリアライズした結果を出力する先
StringWriter writer = new StringWriter();
StreamResult output = new StreamResult(writer);

// シリアライズ
transformer.transform(src, output);

writer.flush();
writer.close();
return writer.toString();
}
}).runTest();

/**********************************************************************/
// DOM Level 3 Load and Save API を使ったシリアライズ.
/**********************************************************************/
(new TestTemplate("DOM Level 3 Load and Save API") {

public String serialize(Element element) throws Exception {

DOMImplementationRegistry reg = DOMImplementationRegistry.newInstance();
DOMImplementationLS impLS = (DOMImplementationLS) reg.getDOMImplementation("LS");

if (impLS == null) {
System.err.println("DOM3 Load and Save feature is not supported.");
return "";
}

// LSSerializer クラスのインスタンス取得
LSSerializer lsserializer = impLS.createLSSerializer();

DOMConfiguration conf = lsserializer.getDomConfig();
// XML宣言の省略を指示する。
conf.setParameter("xml-declaration", false);
// インデント出力を指示する。
conf.setParameter("format-pretty-print", true);

// (参考) DOMConfiguration のプロパティについては次を参照。
// http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-LSSerializer-config

// LSOutput クラスのインスタンスを作成し, 出力先設定
LSOutput lsoutput = impLS.createLSOutput();
lsoutput.setEncoding("UTF-8");

ByteArrayOutputStream os = new ByteArrayOutputStream();
lsoutput.setByteStream(os);

// シリアライズ
lsserializer.write(element, lsoutput);

os.flush();
os.close();
return os.toString("UTF-8");
}
}).runTest();

/**********************************************************************/
// Xerces の XMLSerializer によるシリアライズ.
/**********************************************************************/
(new TestTemplate("DOM Level 3 Load and Save API") {

public String serialize(Element element) throws Exception {

OutputFormat format = new OutputFormat();
// XML宣言の省略を指示する。
format.setOmitXMLDeclaration(true);
// インデント出力を指示する。
format.setIndenting(true);
// インデント幅を設定する。
format.setIndent(4);

StringWriter writer = new StringWriter();
XMLSerializer serializer = new XMLSerializer(writer, format);

// シリアライズ
serializer.serialize(element);

writer.flush();
writer.close();
return writer.toString();
}
}).runTest();
}

private static void printNode(Node nd, int depth) {
String indent = repeat("\t", depth);

StringBuilder sb = new StringBuilder();
sb.append(indent + "getNodeType():\t\t" + nodeTypeNames[nd.getNodeType()] + "\n");
sb.append(indent + "getNodeName():\t\t" + nd.getNodeName() + "\n");
sb.append(indent + "getPrefix():\t\t" + nd.getPrefix() + "\n");
sb.append(indent + "getLocalName():\t\t" + nd.getLocalName() + "\n");
sb.append(indent + "getNamespaceURI():\t" + nd.getNamespaceURI() + "\n");

switch (nd.getNodeType()) {
case Node.TEXT_NODE:
case Node.ATTRIBUTE_NODE:
sb.append(indent + "getNodeValue():\t\t" + nd.getNodeValue() + "\n");
}

if (nd.getNodeType() == Node.ELEMENT_NODE) {
sb.append(indent + "getTagName():\t\t" + ((Element) nd).getTagName() + "\n");
}

System.out.println(sb.toString());

NamedNodeMap nmap = nd.getAttributes();
if (nmap != null) {
for (int i = 0; i < nmap.getLength(); i++) {
printNode(nmap.item(i), depth + 1);
}
}

NodeList nlist = nd.getChildNodes();
for (int i = 0; i < nlist.getLength(); i++) {
printNode(nlist.item(i), depth + 1);

}
}

private static String repeat(String str, int count) {
return new String(new char[count]).replace("\0", str);
}

// nodeType 数値から名前(文字列)へのマッピング
static String[] nodeTypeNames = { "",
"ELEMENT_NODE", "ATTRIBUTE_NODE", "TEXT_NODE",
"CDATA_SECTION_NODE", "ENTITY_REFERENCE_NODE",
"ENTITY_NODE", "PROCESSING_INSTRUCTION_NODE",
"COMMENT_NODE", "DOCUMENT_NODE", "DOCUMENT_TYPE_NODE",
"DOCUMENT_FRAGMENT_NODE", "NOTATION_NODE" };
}


出力結果
強調表示部がシリアライズされたXML文字列。
DOM Level 3 Load and Save API では、要素に名前空間宣言が属性に追加され、
シリアライズ前後で、DOMツリーが変わっている。
################################################################################

JAXP's Transformer
################################################################################

getNodeType(): ELEMENT_NODE
getNodeName(): svg:svg
getPrefix(): svg
getLocalName(): svg
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): svg:svg

getNodeType(): ELEMENT_NODE
getNodeName(): rect
getPrefix(): null
getLocalName(): rect
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): rect

<svg:svg xmlns:svg="http://www.w3.org/2000/svg">
<rect xmlns="http://www.w3.org/2000/svg"/>
</svg:svg>



getNodeType(): ELEMENT_NODE
getNodeName(): svg:svg
getPrefix(): svg
getLocalName(): svg
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): svg:svg

getNodeType(): ELEMENT_NODE
getNodeName(): rect
getPrefix(): null
getLocalName(): rect
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): rect

################################################################################
DOM Level 3 Load and Save API
################################################################################

getNodeType(): ELEMENT_NODE
getNodeName(): svg:svg
getPrefix(): svg
getLocalName(): svg
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): svg:svg

getNodeType(): ELEMENT_NODE
getNodeName(): rect
getPrefix(): null
getLocalName(): rect
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): rect

<svg:svg xmlns:svg="http://www.w3.org/2000/svg">
<rect xmlns="http://www.w3.org/2000/svg"/>
</svg:svg>



getNodeType(): ELEMENT_NODE
getNodeName(): svg:svg
getPrefix(): svg
getLocalName(): svg
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): svg:svg

getNodeType(): ATTRIBUTE_NODE
getNodeName(): xmlns:svg
getPrefix(): xmlns
getLocalName(): svg
getNamespaceURI(): http://www.w3.org/2000/xmlns/
getNodeValue(): http://www.w3.org/2000/svg

getNodeType(): TEXT_NODE
getNodeName(): #text
getPrefix(): null
getLocalName(): null
getNamespaceURI(): null
getNodeValue(): http://www.w3.org/2000/svg

getNodeType(): ELEMENT_NODE
getNodeName(): rect
getPrefix(): null
getLocalName(): rect
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): rect

getNodeType(): ATTRIBUTE_NODE
getNodeName(): xmlns
getPrefix(): null
getLocalName(): xmlns
getNamespaceURI(): http://www.w3.org/2000/xmlns/
getNodeValue(): http://www.w3.org/2000/svg

getNodeType(): TEXT_NODE
getNodeName(): #text
getPrefix(): null
getLocalName(): null
getNamespaceURI(): null
getNodeValue(): http://www.w3.org/2000/svg

################################################################################
DOM Level 3 Load and Save API
################################################################################

getNodeType(): ELEMENT_NODE
getNodeName(): svg:svg
getPrefix(): svg
getLocalName(): svg
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): svg:svg

getNodeType(): ELEMENT_NODE
getNodeName(): rect
getPrefix(): null
getLocalName(): rect
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): rect

<svg:svg>
<rect/>
</svg:svg>



getNodeType(): ELEMENT_NODE
getNodeName(): svg:svg
getPrefix(): svg
getLocalName(): svg
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): svg:svg

getNodeType(): ELEMENT_NODE
getNodeName(): rect
getPrefix(): null
getLocalName(): rect
getNamespaceURI(): http://www.w3.org/2000/svg
getTagName(): rect

[Web開発] テストコード その2

 
以下、シリアライザでプレフィックスを調整しているのが確認できる JavaScript 用のテストコード。
テスト内容については http://monado.dtiblog.com/blog-entry-175.html を参照。
<!DOCTYPE html> <!-- IE9 でも表示できるようドキュメントタイプは HTML5 とする -->

<html>
<head>
<title>Test2</title>
<style>
table {
border-collapse:collapse;
}
td {
vertical-align: top;
border-bottom: 1px solid gray;
border-top: 1px solid gray;
padding: 0px;
}
.prop {
color: red;
font-family: 'Times New Roman';
}
.val {
vertical-align: middle;
font-family: 'Courier New', monospace;
}
div {
padding-top: 20px;
padding-bottom: 10px;
font-size: 150%;
font-family: 'Times New Roman';
font-weight: bold;
}
</style>
</head>
<body>
<script>
var SVG_NS = 'http://www.w3.org/2000/svg';

function print_props(obj) {
var props = ['nodeName', 'namespaceURI', 'tagName', 'prefix', 'localName'];
for (var i = 0; i < props.length; i++ ) {
document.write('<tr><td class="prop">');
document.write(props[i]);
document.write('&nbsp;&nbsp;&nbsp;&nbsp;</td><td class="val">');
document.write(obj[props[i]]);
document.write('</td></tr>');
}
}

function print_elem(el) {
document.write('<table><tbody>');
print_props(el);
print_attrs(el);
document.write('</tbody></table>');
}

function print_attrs(el) {
for(var i = 0 ; i < el.attributes.length; i++) {
var attr = el.attributes[i];
document.write('<tr><td class="prop">attributes[' + i + ']:</td>');
document.write('<td>');
document.write('<table><tbody>');
print_props(attr);
document.write('</tbody></table>');
document.write('</td><tr>');
}
}


var root = document.createElementNS(SVG_NS, 'svg:svg');
// rect要素は接頭辞を省略して作成する.
var el1 = document.createElementNS(SVG_NS, 'rect');
root.appendChild(el1);

text = (new XMLSerializer()).serializeToString(root);
text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

document.write('<div><i>svg</i> node detail</div>');
print_elem(root);

document.write('<div><i>rect</i> node detail</div>');
print_elem(el1);

document.write('<div>result of serializeToString() method.</div>');
document.write('<span class="val">');
document.write(text);
document.write('</span>');

</script>
</body>
</html>

Firefoxでの実行結果
以下を見ると rect ノードオブジェクトの prefix が null であるにも関わらず、
シリアライズされた文字列に svg:rect と接頭辞が追加されていることがわかる。
Firefoxでの実行結果

次は、名前空間宣言を明示的に追加し、接頭辞もすべて指定するサンプルコードと実行結果。強調表示部が上のコードに追加した箇所。
<!DOCTYPE html> <!-- IE9 でも表示できるようドキュメントタイプは HTML5 とする -->

<html>
<head>
<title>Test3</title>
<style>
table {
border-collapse:collapse;
}
td {
vertical-align: top;
border-bottom: 1px solid gray;
border-top: 1px solid gray;
padding: 0px;
}
.prop {
color: red;
font-family: 'Times New Roman';
}
.val {
vertical-align: middle;
font-family: 'Courier New', monospace;
}
div {
padding-top: 20px;
padding-bottom: 10px;
font-size: 150%;
font-family: 'Times New Roman';
font-weight: bold;
}
</style>
</head>
<body>
<script>
var XMLNS_NS = 'http://www.w3.org/2000/xmlns/';
var SVG_NS = 'http://www.w3.org/2000/svg';

function print_props(obj) {
var props = ['nodeName', 'namespaceURI', 'tagName', 'prefix', 'localName'];
for (var i = 0; i < props.length; i++ ) {
document.write('<tr><td class="prop">');
document.write(props[i]);
document.write('&nbsp;&nbsp;&nbsp;&nbsp;</td><td class="val">');
document.write(obj[props[i]]);
document.write('</td></tr>');
}
}

function print_elem(el) {
document.write('<table><tbody>');
print_props(el);
print_attrs(el);
document.write('</tbody></table>');
}

function print_attrs(el) {
for(var i = 0 ; i < el.attributes.length; i++) {
var attr = el.attributes[i];
document.write('<tr><td class="prop">attributes[' + i + ']:</td>');
document.write('<td>');
document.write('<table><tbody>');
print_props(attr);
document.write('</tbody></table>');
document.write('</td><tr>');
}
}


var root = document.createElementNS(SVG_NS, 'svg:svg');
var el1 = document.createElementNS(SVG_NS, 'svg:rect');
root.appendChild(el1);
root.setAttributeNS(XMLNS_NS, 'xmlns:svg', SVG_NS);

text = (new XMLSerializer()).serializeToString(root);
text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

document.write('<div><i>svg</i> node detail</div>');
print_elem(root);

document.write('<div><i>rect</i> node detail</div>');
print_elem(el1);

document.write('<div>result of serializeToString() method.</div>');
document.write('<span class="val">');
document.write(text);
document.write('</span>');

</script>
</body>
</html>

Firefoxでの実行結果
Firefoxでの実行結果2

[Web開発] createElementNS 修飾名(qualified name) プレフィックス 接頭辞を省略したらどうなるか。

 
createElementNS の呼び出しで、修飾名(qualified name)の名前空間プレフィックスを省略した場合、どうなるかを検証した。
出力結果は、実装(おそらくはシリアライザの実装)によってまちまち。

Javaでの検証
検証環境のバージョンは以下のとおり。
Java : 1.7.0_02
Xerces : 2.11.0

以下のテストコードは簡易版。
JAXP の Transformer や DOM Level 3 Load and Save API のシリアライザを含めたより詳細な検証は、http://monado.dtiblog.com/blog-entry-177.htmlで実施。

NSTest.java
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class NSTest {

    static final String SVG_NS = "http://www.w3.org/2000/svg";

    public static void main(String[] argv) throws Exception {
        DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
        dbfactory.setNamespaceAware(true);
        DocumentBuilder builder = dbfactory.newDocumentBuilder();
        Document doc = builder.newDocument();

        // 要素rootを作成する
        Element root = doc.createElementNS(SVG_NS, "svg:svg");
        // 要素 el1 は名前空間プレフィックスを指定せずに作成する
        Element el1 = doc.createElementNS(SVG_NS, "rect");
        root.appendChild(el1);

        // 要素をシリアライズする
        OutputFormat format = new OutputFormat();
        format.setOmitXMLDeclaration(true);
        format.setIndenting(true);
        XMLSerializer serializer = new XMLSerializer(System.out, format);
        serializer.serialize(root);
    }
}


NSTest.java の実行結果
<svg:svg>
    <rect/>
</svg:svg>


JavaScript での検証
Internet Explorer では、createElementNS がバージョン 9 から利用可能であり、
InternetExplorer9 で createElementNS を使うために文書タイプをHTML5としている。
なお、http://monado.dtiblog.com/blog-entry-176.html にあるテストコードを使用すると、シリアライザがタグ名のプレフィックスを調整しているのが確認できる。
以下のコードは、簡単にするためそれをしていない。

<!DOCTYPE html> <!-- IE9 でも表示できるようドキュメントタイプは HTML5 とする -->
<html>
<head>
<title>Test1</title>
</head>
<body>
  <script>
    var SVG_NS = 'http://www.w3.org/2000/svg';
    var root = document.createElementNS(SVG_NS, 'svg:svg');
    // rect要素は接頭辞を省略して作成する.
    var el1 = document.createElementNS(SVG_NS, 'rect');
    root.appendChild(el1);

    text = (new XMLSerializer()).serializeToString(root);
    text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    document.write(text);

  </script>
</body>
</html>

各ブラウザの実行結果は以下の通り。

Internet Explorer 9.0.8112.16421
<svg:svg xmlns:svg="http://www.w3.org/2000/svg"><rect xmlns="http://www.w3.org/2000/svg" /></svg:svg>

Firefox 9.0.1
<svg:svg xmlns:svg="http://www.w3.org/2000/svg"><svg:rect/></svg:svg>
Firefox では、rect要素の省略された接頭辞が nsXMLContentSerializer::ConfirmPrefix メンバ関数によって算出される。これは、Firefox のソースコード nsXMLContentSerializer.cpp で確認できる。

Google Chrome 16.0.912.77
<svg:svg><rect></rect></svg:svg>


補足
下記のコードを書いてみたが Google Chrome では期待通りに動作しなかった。
調べたところ、Chrome のレンダリングエンジン Webkit では、 XMLSerializerserializeToString が正しく実装されていないようだ。
不具合については次のリンクを参照。

xmlserializer strips xlink from xlink:html svg image tag
http://stackoverflow.com/questions/8979267/xmlserializer-strips-xlink-from-xlinkhtml-svg-image-tag

<!DOCTYPE html> <!-- IE9 でも表示できるようドキュメントタイプは HTML5 とする -->
<html>
<head>
<title>Test setAttributeNS</title>
</head>
<body>
  <script>
    var XMLNS_NS = 'http://www.w3.org/2000/xmlns/';
    var SVG_NS = 'http://www.w3.org/2000/svg';

    var root = document.createElementNS(SVG_NS, 'svg:svg');
    root.setAttributeNS(XMLNS_NS, 'xmlns:svg', SVG_NS);
    var el1 = document.createElementNS(SVG_NS, 'svg:rect');
    root.appendChild(el1);

    text = (new XMLSerializer()).serializeToString(root);
    text = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    document.write(text);

  </script>
</body>
</html>

[Web開発] userData ビヘイビア behavior 動かない 保存できない 機能しない

 
UserData ビヘイビアが動作しない場合には、適用されているドキュメントモードを確認してみると良い。
ドキュメントモードについては以下を参照のこと。

標準モードと互換モードについて
http://www.dspt.net/html_tag/mode.html

ドキュメントモードに対する UserData ビヘイビアの動作状況は下表の通り。
下表は、IE9で検証した結果である。
ドキュメントモード document.compatMode document.documentMode 動作状況
互換モード"BackCompat"5動作する
標準モード(IE7)"CSS1Compat"7動作する
標準モード(IE8)"CSS1Compat"8動作する
標準モード(IE9)"CSS1Compat"9動作しない

UserData ビヘイビアを動作させるためには、さらに、対象のセキュリティゾーンの設定の「UserDataの常設」を有効にする必要がある。
対象のセキュリティ・ゾーンがマイコンピュータ・ゾーンである場合には、レジストリの編集が必要になることもある。
マイコンピュータ・ゾーンの設定は、ファイルプロトコル(file://)によるローカルファイルへのアクセスなどに適用される。

動作確認用HTMLソース(IE用)
<html>

<head>
<!-- 次の meta タグによってレンダリングモードを指定 -->
<meta http-equiv="X-UA-Compatible" content="IE=5" />
<!-- content "IE=5":互換モード, "IE=7":標準モード(IE7), "IE=8":標準モード(IE8), "IE=9":標準モード(IE9) -->
<script>

function DoSave() {
form1.data.setAttribute("content", form1.textbox.value);
form1.data.save("EditContent");
}

function DoLoad() {
form1.data.load("EditContent");
content = form1.data.getAttribute("content");
form1.textbox.value = content || "default";
}

function DoClear() {
form1.textbox.value = "";
}

</script>
</head>
<body onload="DoLoad();">
<pre>
<script>
if(document.compatMode)
document.writeln("document.compatMode:" + document.compatMode);
if(document.documentMode)
document.writeln("document.documentMode:" + document.documentMode);
</script>
</pre>
<form name="form1">
<input id="data" type="hidden" style="behavior:url(#default#userdata)" />
<input id="textbox" type="text"/>
<p>
<button onClick='DoSave()'>Save</button>
<button onClick='DoClear();'>Clear</button>
<button onClick='DoLoad()'>Load</button>
</p>
</form>
</body>
</html>
前のページ