#XMLファイルの書き方について振り返りたい!
現在の案件先(Java)で、xmlファイルを活用する機会があり、勉強したので、ちらっと書いときます。
今回は、Javaで活用できる形式です!
的外れなことを記載していたらご指摘よろしくお願いします。
##そもそもxmlファイルって?
extensible Markup Languageといい、簡単に言うと、データをやり取りするために利用されるファイルです。
HTMLと同じ、マークアップ言語であり、タグを使って、記載していきます。
(ちなみに、Javaはコンパイラ言語、PHPなどはスクリプト言語と言います)
HTMLに直接書き込んだり、DBから出力すればよくないかと思うかもしれませんが、xmlファイルに定義することでどのようなデータを出力するか明記することで、可読性や保守性を向上することができます。
特に大規模なシステムになると情報1つ出力するだけでも、細心の注意が必要なので実装することが大切です!
簡単に言うと、こんな感じです。
<?xml version="1.0" encoding="Shift_JIS"?>
<買い物リスト>
<内容>
<日付>8月21日</日付>
<買う物>カレー</買う物>
<金額>500円</金額>
</内容>
<内容>
<日付>8月22日</日付>
<買う物>ラーメン</買う物>
<金額>600円</金額>
</内容>
<内容>
<日付>8月23日</日付>
<買う物>寿司</買う物>
<金額>15000円</金額>
</内容>
</買い物リスト>
このような書き方をします!
詳しく見ていきましょう!
##タグ一覧
まずは、必要なタグ一覧から見ていきます。
###サーブレット<servlet>
|要素 |必須 |内容 |
|:|:|:|
|<servlet-name>|○ |web.xmlにて、サーブレットを定義するために記載する。 |
|<display-name>|- |GUIツールによって表示される名前。 |
|<description> |- |サーブレットのテキストによる説明。 |
|<servlet-class> |- |サーブレットの完全修飾名のこと。とは必ず入れる必要はありません。オプションのような感覚です。 |
|<jsp-file> |- |JSPファイルのフルパス。とは必ず入れる必要はありません。オプションのような感覚です。 |
|<init-param> |- |サーブレットのキーと値の初期値を設定する。 |
|<load-on-startup> |- |サーブレットがロードされる順番を設定する。値には正の整数を指定し、値が低い順から読み込まれていく。 |
###サーブレット・マッピング
サーブレットマッピングは、サーブレット要素とURLを紐付ける役割があります。
|要素 |内容 |
|:|:|
|<servlet-name>|web.xmlにて、サーブレットを定義するために記載する。 |
|<url-name>|URLを解決するために用いられる。「http://host:port+WebApplicationName」 に続く部分をサーバーによって比較され、同一の場合は、サーブレットに紐づけられたサーブレットが呼び出される。|
##web.xmlを使用した際の流れ
web.xmlを使用した際の実際の流れを見ていく。URLによって呼び出されたサーブレットのディレクトリは以下の通りである。
URL: http://host:port/AutumnServletXml/Autumn
AutumnServletXml // コンテキストパス
└ WEB-INF
└ classes
└ AutumnServlet // サーブレットパス + ここにマッピングさせるURL
ファイルの中身はこんな感じです。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<servlet>
<servlet-name>autumnservlet</servlet-name>
<servlet-class>AutumnServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>autumnservlet</servlet-name>
<url-pattern>/AutumnServlet</url-pattern>
</servlet-mapping>
</web-app>
次は、サーブレットを継承したファイルです。
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AutumnServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// レスポンスにコンテキストタイプの設定(何も出力するか見たいな)
response.setContentType("text/html");
// レスポンスで返す内容を設定
PrintWriter out = response.getWriter();
out.println("<html><head></head><body>");
out.println("<p>Autumn Application</p>");
out.println("<p>Hello Autumn!</p>");
out.println("</body></html>");
}
}
###実行結果
クライアントからのリクエストパスはこのようになる。
http://localhost:8080/AutumnServletXml/AutumnServlet
ブラウザには、Autumn Applicationと**Hello Autumn!**が出力されている。
###解説
先程のAutumnServlet.javaの説明をしておきます!
・HttpServletを継承して、AutumnServletを作成します。
・doGetメソッドをオーバーロードして定義します。
・Context Typeにtext/htmlを指定する。
・HTMLに出力するためのoutオブジェクトを取得する。
・最後は出力する内容を定義する。
といった内容となってます!
##パッケージになっている場合
パッケージとは、いくつものクラスをまとめたものです。
そこで、を見ていただくと、クラス名の完全修飾となっています。
これは、パッケージ名も含めて定義をする必要があると言うことです。
sampleというパッケージに入っているものと仮定すると、このような形式になります。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<servlet>
<servlet-name>autumnservlet</servlet-name>
<servlet-class>sample.AutumnServlet</servlet-class> // sampleが追加されてます。
</servlet>
<servlet-mapping>
<servlet-name>autumnservlet</servlet-name>
<url-pattern>/AutumnServlet</url-pattern>
</servlet-mapping>
</web-app>
###web.xmlの定義
AutumnServletXml // コンテキストパス
└ WEB-INF
└ classes
└ sample // パッケージ追加
└ Autumn // サーブレットパス + ここにマッピングさせるURL
##web.xmlの<init-param>による初期設定
xmlの要素の要素を渡して、初期値設定をします。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<servlet>
<servlet-name>autumnservlet</servlet-name>
<servlet-class>AutumnServlet</servlet-class>
<init-param> // 追加開始
<param-name>name</param-name>
<param-value>John</param-value>
</init-param>
<init-param>
<param-name>age</param-name>
<param-value>89</param-value>
</init-param> // 追加終了
</servlet>
<servlet-mapping>
<servlet-name>autumnservlet</servlet-name>
<url-pattern>/AutumnServlet</url-pattern>
</servlet-mapping>
</web-app>
サーブレットはこのような内容です。
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AutumnServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 初期設定値を取得し、変数に代入
String name = getInitParameter("name");
String age = getInitParameter("age");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html><head></head><body>");
out.println("<p>Simple Application</p>");
out.println("<p>Hello Autumn! + " " + "名前は" + name + " " + age + "歳"</p>");
out.println("</body></html>");
}
}
###実行結果
ルートパスは、変わりません。
出力内容としては、Simple Application、Hello Autumn! 名前はjohn 89歳と出力されます。
###解説
大きくは変わっていませんが、が使用されています。
getInitParameter("name")、getInitParameter("age")でそれぞれ値をxmlファイルから呼び出しています。
##デフォルトサーブレット
指定されたサーブレットパスがなくても、デフォルトで用意しておいたHTMLを出力します。
ディレクトリは以下の通りです。
AutumnServletXml // コンテキストパス
└ WEB-INF
└ classes
└ AutumnServlet // サーブレットパス + ここにマッピングさせるURL
└ Default // デフォルト追加
web.xmlファイルの内容を定義します。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<servlet>
<servlet-name>autumnservlet</servlet-name>
<servlet-class>AutumnServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>defaultservlet</servlet-name>
<servlet-class>DefaultServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>autumnservlet</servlet-name>
<url-pattern>/AutumnServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>defaultservlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
サーブレットは以下の内容です。
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DefaultServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html><head></head><body>");
out.println("<p>Servlet not found.</p>");
out.println("<p>Default Servlet</p>");
out.println("</body></html>");
}
}
###実行結果
以下のような存在しないパスを指定した際に、デフォルトのHTMLが返されます。
// 存在しないパス
http://localhost:8080/AutumnServletXml/SummerServlet
出力内容は、Servlet not found.,Default Servletとなる。
###解説
サーブレットの内容としては変わらないが、web.xmlのパス指定の際に"/"を定義してあげたことで、存在しないパスを指定した時でも、HTMLが表示されるようになった。
###おまけ
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
この1行が何をしているのかの解説もしておきます!
###xmlns:xsi, xmlns, xmlns:schemaLocation
これは、名前空間を定義してあげています。名前空間とはxmlに限った話ではなく、ざまざまな場面で使われています。
必要性としては、HTMLには複数のxmlファイルが利用されることがあるからです。万が一、どのxmlファイルにもtitleタグがあった場合、どちらを参照したら良いか困惑してしまいます。そこで、「1号室」などを指定してあげれば、読み込む側も、困惑することなく利用することができるといった内容です。
ただ、「1号室」という定義あったとしても、星のリゾートの「1号室」なのか、帝国ホテルの「1号室」なのか分からないですよね。
したがって、どのホテルの「1号室」なのかを定義してあげることで、識別できるようにしてあげます!
イメージとしては、**ルート要素(ホテルの種類)**を定義する。次に、**ルート要素にURL(何号室)**を定義するといった順番です。
まずは、ルート要素を定義してあげます。ルート要素は、xmlns要素で定義します。
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
次に、URLを定義してあげます。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
最後に、schemaLocationですが、これは、ファイルの場所を指定してあげます。というのも、名前空間はあくまで識別するためのものであり、スキーマの場所を示しているわけではないからです。
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
このタグにより、どうファイル内の同じ識別します!
###id, version
idに関しては、どのアプリのIDなのか(必須ではない)、versionは、どのバージョンのサーブレットを使用しているかなどを定義します(javaでサーブレットを使用する場合で、他の場合は別のバージョンを指定する)。
###参照したサイト
https://ponsuke-tarou.hatenablog.com/entry/2021/06/07/224803
https://www.mlab.im.dendai.ac.jp/~yamada/web/xml/namespace.html
https://www.mlab.im.dendai.ac.jp/~yamada/web/xml/namespace.html