📑

【初心者向け/ITスクール55日】XMLパーサー/レスポンシブウェブ/GRID

2023/09/27に公開

はじめに

今日は、ITスクールに通った55日目の日で、今日学んだ知識を記事にシェアしたいと思います。本記事が、ITを勉強を始めた方々にもロードマップになればいいと思います。

明日、お盆ですので、新しいことを学ばずに自習学習する時間を持ちました!

XMLパーサー

https://zenn.dev/eldorado215/articles/8a91c3535f63e0#api呼び出し後、パーサ

昨日は、JSONのみparsingしたので、今日はXMLのparsingを復習します。JSONがほぼ標準になっておりますが、韓国の場合、国家機関やOPENAPIはxmlに提供することも多いので、無視することではないと思います!

その前にXMLパーサーの場合、とても理解しづらいので、XMLパーサーを持っているライブラリからまとめます。ライブラリはXmlPullParser です。


XMLPullParser

XmlPullParserはStringBuffer、ResultSetのようにnext()メソッドを通して、データーを順番に読むことができます。
XmlPullPaserFactoryのオブジェクト(Singtone)から、XmlPullPaserのInterfaceに具象クラスのオブジェクトを入れます。この場合もXmlPullParserFactoryからオブジェクトを得ます。
おそらく、クラスに勝手にアクセスすることを防ぎ、保存するためではないかと思います。

//事前に作成したHttpClientオブジェクトからurlのbodyをダウンロード。そのために、InputStream活用
InputStream is = BeaverHttpClient.download("http://localhost/Sep_26_1_Ajax/GetFruit");

XmlPullParserFactory xppf = XmlPullParserFactory.newInstance();
XmlPullParser xpp = xppf.newPullParser();
//XmlPullParserからEncodingすれば、XMLにパーサー!
xpp.setInput(is, "UTF-8");
int type = xpp.getEventType();

ArrayList<Fruit> fruits = new ArrayList<Fruit>();
Fruit fruit = null;

FruitはDTOで、ArrayListに入れて、requestのattributeに追加するため、事前にオブジェクトを生成します。後ほどJSPからデーターを取り出すためです。

XmlPullParserのEvent一覧

イベント種類 意味
START_DOCUMENT xml文書の始まりを意味します。
END_DOCUMENT xml文書の最後を意味します。
START_TAG xmlタグの開始タグを意味します。 (例: <data>)
END_TAG xmlタグの終了タグを意味します。 (例: </data>)
TEXT xmlタグのコンテンツを意味します。 (例: <data> content </data>)

START_TAG、END_TAGは getName()をTEXT는 getText()を呼び出すします。

<data><data1> content </data1></data>

このような文書の場合、START_TAG, TEXT, START_TAG, TEXT, END_TAG, END_TAG 順にイベントが生じます。つまり、TEXTの値がなくても基本的に発生します。

Code作成


//XmlPullParserFactory xppf = XmlPullParserFactory.newInstance();
//XmlPullParser xpp = xppf.newPullParser();
.
.
.

  while(type!=XmlPullParser.END_DOCUMENT) {
	//ROUTE 1 start tagなら
	if(type==XmlPullParser.START_TAG) {
	   tagName = xpp.getName();
	 }
	 
	  ///ROUTE 2 TEXTなら
	 else if(type==XmlPullParser.TEXT) {
	    		 
	 }
	 
        ///ROUTE 3 end tagなら
	else if(type==XmlPullParser.END_TAG) {
	    		 
	 }

まずは大きな部分から制御文のフローを作成します。START TAGの分岐店をルート1、2にEND TAGの分岐点をルート3と名づけます。

  //Route 1
 if(type==XmlPullParser.START_TAG) {
	tagName = xpp.getName();
    //1->starttag
    if(tagName.equals("fruit"){
     fruit = new Fruit();
     } 1->starttag end
 }    
  //Route 2
    else if(type==XmlPullParser.TEXT){
       if(tagName.equals("f_name"){
       }
       else if(tagName.equals("f_price"){
       }
    } //2->text end
}//Route 1,2 end

ルート1の場合、starttagの値を得てからそれがfruitと一致している場合で*、一致してない場合に分かれます。一致したら1に入ってDTOを生成、**してない場合2に入りフィールド名を入れ、データーを得ます。

starttag


   //ROUTE 1 start tagなら
   if(type==XmlPullParser.START_TAG) {
    //タグ名をパーサーから得てString変数tagNameに入れて  
    tagName = xpp.getName();
    //1->fruit そのタグ名がfruitの場合、DTOを生成
    if(tagName.equals("fruit")) {
	  fruit=new Fruit();
	   }///1->text

    else if(type == XmlPullParser.TEXT) {
           if(tagName.equals("f_name")) {
	          fruit.setF_name(xpp.getText());
	   } else if(tagName.equals("f_price")) {
	          fruit.setF_price(Integer.parseInt(xpp.getText()));
	       }
    }

endtag

endtagの場合、オブジェクト名のエンドタグから情報を入れた状態なので、ArrayListにfriutを入れます。

else if(type == XmlPullParser.END_TAG) {
        if(xpp.getName().equals("fruit")) {
              fruits.add(fruit);
             }
        }

後処理

route 1 もしくは route 2が終わったら、次のイベントが必要になります。next()メソッドを呼び出す必要があります。

xpp.next();
type = xpp.getEventType();

最終Code

	public static void getAllFruitsXML(HttpServletRequest req) {
		try {
			
		//事前に作成したHttpClientオブジェクトからurlのbodyをダウンロード。そのために、InputStream活用
		 InputStream is = BeaverHttpClient.download("http://localhost/Sep_26_1_Ajax/GetFruit");

		 //XmlPullParserFactoryから、XmlPullParserのInterfaceに具象オブジェクトを参照させます。
		 XmlPullParserFactory xppf = XmlPullParserFactory.newInstance();
		 XmlPullParser xpp = xppf.newPullParser();
		 //XmlPullParserからEncodingすれば、XMLにパーサー!
		 xpp.setInput(is, "UTF-8");
		 
		 int type = xpp.getEventType();
		 String tagName = null;
		 
		 ArrayList<Fruit> fruits = new ArrayList<Fruit>();
	     Fruit fruit = null;
	     
	     //ROUTE 1 OR ROUTE 2
	     while(type!=XmlPullParser.END_DOCUMENT) {
	    	 //ROUTE 1 start tagなら
	    	 if(type==XmlPullParser.START_TAG) {
	    		 //タグ名をパーサーから得てString変数tagNameに入れて
	    		 tagName = xpp.getName();
	    		 //1->fruit そのタグ名がfruitの場合、DTOを生成
	    		 if(tagName.equals("fruit")) {
	    			 fruit=new Fruit();
	    		 }
	    	 }//ROUTE 2 start tagだけどfruitでなないなら
	    	else if(type == XmlPullParser.TEXT) {
	                  if(tagName.equals("f_name")) {
	                fruit.setF_name(xpp.getText());
	                 } else if(tagName.equals("f_price")) {
	                   fruit.setF_price(Integer.parseInt(xpp.getText()));
	                 }
	    	}
	    	///ROUTE 3 end tagなら
	        else if(type == XmlPullParser.END_TAG) {
	                 if(xpp.getName().equals("fruit")) {
	                     fruits.add(fruit);
	                 }
	             }
	    	 
	    	 xpp.next();
	         type = xpp.getEventType();
	     }
	     
	     req.setAttribute("fruitsxml", fruits);
		 
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

<c:forEach var="fruit" items="${fruitsxml }">
		${fruit.f_name} - ${fruit.f_price} <br>
</c:forEach>
	<br>

レスポンシブウェブデザイン

今まで、Media Queryの概念は知っておりましたが、今日初めて、DESKTOPでもモバイルでもサイズに合わせてレイアウトが変更されるように、youtubeの講座を見ながらnav_barを作成してみました。最後にはJSのqueryselectorというAPIで、DOMのclassnameで変更する属性を定数に割り当て、mediaqueryの際に、click eventを入れることで、素敵なNavigation barを作成しました!

const toggleBtn = document.querySelector('.navbar__toogleBtn');
const menu = document.querySelector('.navbar__menu');
const icons = document.querySelector('.navbar__icons');

toggleBtn.addEventListener('click',()=>{
    menu.classList.toggle('active');
    icons.classList.toggle('active');
});
@media screen and (max-width: 768px) {
    .navbar{
        flex-direction: column;
        align-items: flex-start;
    }
    .navbar__menu{
        display: none;
        flex-direction: column;
        align-items: center;
        width: 100%;
    }
    .navbar__menu li{
        text-align: center;
        width: 100%;
        padding: 8px 24px;
    }
    .navbar__icons{
        display: none;
        justify-content: center;
        width: 100%;
    }
    .navbar__toogleBtn{
        display: block;
    }
    .navbar__menu.active,
    .navbar__icons.active{
        display: flex;
    }
}

今まで、pxを使用し、rem,em,vh,vwのように相対的な割合に対しての理解が足りなかったので、そういった勉強もしっかりしたいと思います。

flex-grow : 1
flex-shrink :0
flex-basis: 500px
<!--flex: 1 0 500px >

このように、割合でレスポンシブウェブデザインをコントロールすることも可能です!

more grid

repeat

grid-template-columns:1fr 1fr 1fr 1fr 1fr 1fr
grid-template-rows:1fr 1fr 1fr 1fr 1fr 1fr

grid-template-columns: repeat(6,1fr);
grid-template-rows: repeat(6,1fr);

同じ長さの場合、repeat(個数、長さ)で簡単に設定することができます。

auto-columns/-rows/flow

最初にstatic pageと指定したgridがあるとしましょう。

grid-template-columns: repeat(2,1fr);
grid-template-rows: repeat(2,1fr);

この場合、columnには1frが適用されておりますが、row(height)が崩れています。
1~4も前よりちっちゃくなりました。
このように追加コンテンツの場合が本来のgridを崩れる可能性を想定して、auto-rowsを活用します。

このように、追加コンテンツである5~10と1~4の長さが同じ長さになったことが分かります。
また、gridに何が追加される場合、rowsに追加されることがdefaultといったこともわかります

grid-auto-flow

先ほどのrowsをcolumn、つまり横に背ってした場合はgrid-auto-flowをcolumnにします。
grid-auto-columnsも1frに設定した、以下のような結果になりました。最後まで伸ばしてみると、正方形にもなれました!

align-items&justify-items(place-items,place-self)

基本的にdefaultでgrid itemは一つのcellの空間を全部占めています。

つまり、grid itemsのdefaultは以下のようにstretchが適用されています。

 justify-items: stretch;
 align-items: stretch;

しかし、grid-itemsにwidth,heightを指定すれば、
同じgridのcellに空白ができます。
絶対サイズpxに固定してしまったので、cell全部を埋めるstretchは思ったどおり適用されません。

しかし、絶対サイズに設定した場合、CELL内のitemsを移動することができます。
flex-boxと原理は一緒ですが、この場合はitemsを活用します。また、特定の子要素のみ指定したい場合がselfで指定することができます。

 align-items: end;
 justify-items: end;
 .
 .
 .
 place-self: center center

align content&justify content (place content)

grid-template-columns: repeat(5,100px);
grid-template-rows: repeat(2,100px);

先ほどのitemsはcell ,つまり、templateに設定されたrow,column内の配置であれば、jc,aiはflex-boxのようにcontainerを基準にして整列します。

align-content:centerを親のgridに適用してみます。CELL全体がcontainerの中央に整列されました。
以下がイメージです。

ここからのポイント!

auto-sizing

このようなgrid container, cell, itemsがあります。

grid-containerからcontentのサイズを1frに定義したので、content内部のitem this text is too long
多重ラインになったことが分かります。

grid-template-columns: 1fr max-content 1fr;

max-content(cell内部のcontent(item))の長さを設定することで、cellの割合を自動的に設定することができます。

min-contentに設定した場合は、一番長いcontentを基準にして乳見ます。この場合はlongという単語が一番長いので、そのcontentの大きさに沿って、2番目のcellが父むことが分かります。

しかし、max-content, min-content はサイズが固定されており、gridとしてflexibleする特性を失いました!つまり、固定サイズになりました!

minmax()

flexboxのflex-grow:1 flex-shrink:0 flex-basis:(content size)のように、gridのcellサイズも最初サイズを維持しながら、伸ばすこともできます。
まるでmedia queryみたいな感じですね。

....:1fr minmax(250px,1fr) 1fr;

grid-template-columns:repeat(3,minmax(250px,1fr)) 

以下のようにrepeatと連携することも可能です。

★auto-fill&auto-fit★

次は5つのgrid-contentを持っているgrid-containerで、説明してみます。

.father{
  display: grid;
  gap: 10px;
  height: 100vh;
  grid-template-columns: repeat(5, minmax(200px,1fr));
}

このcssの問題点は、200pxという絶対サイズの影響で、画面が狭くなれば、スクロールができてしまうことです。
このようなレイアウトはモバイルユーザーには不便です。

Flexboxの場合、media Query、grow,shrinkなどを活用したのですが、gridは個数にauto-fill, auto-fitを入れて自動化することが可能です。

 grid-template-columns: repeat(auto-fill, minmax(200px,1fr));
 
grid-template-columns: repeat(auto-fit, minmax(200px,1fr));

最初サイズの200pxの堺から自動的にgridが移動することが分かります。

それでは、auto-fillとauto-fitの違いは何でしょうか?
それは空いているcontainerを埋めるか埋めないかです。

auto-fill

200pxが5個ある場合、1000pxになり、残りの空間できますが、その空間に見えないcellを作ります。
空白には見えますが、実際は見えないcellを追加しています。

auto-fit

auto-fitは空白を既存のcellで埋めるので、長さが変わります。

両方、レスポンシブウェブサイト作成時、よく使われるattribute valueようです。
ちょこちょこgridを活用して、レイアウトも作っていきたいと思います。

Discussion