2016年11月25日 星期五

JS常用功能

W3C英文
W3C中文

※基本

window.onload = function(){
    let input = document.getElementsByTagName('input')[0];
    input.value = 'xxx';
    
    document.getElementById('btn').onclick = function(){
        document.getElementsByName('cb')[2].checked = true;
        document.getElementsByName('ro')[0].checked = true;
    }
    
    document.getElementsByName('cb')[1].defaultChecked = true;
    
    let cls = document.getElementsByClassName('cls')[0];
    let select = document.createElement('select');
    let op1 = document.createElement('option');
    let op2 = document.createElement('option');
    
    select.appendChild(op1);
    select.appendChild(op2);
    
    cls.appendChild(select);
    
    op1.text = 'option1';
    op1.value = 0;
    
    op2.text = 'option2';
    op2.value = 1;
    op2.defaultSelected = true;
}
--------------------
<input /><br />
<button id="btn">click me</button><br />
<input type="checkbox" name="cb" />c1
<input type="checkbox" name="cb" />c2
<input type="checkbox" name="cb" />c3<br />
<div class="cls"></div>
<input type="radio" name="ro" />r1
<input type="radio" name="ro" />r2
<input type="radio" name="ro" />r3<br />

※基本上就是對照上面的網址就很夠用了,只是要特別注意瀏覽器有沒有支援,裡面都有寫,如果是HTML5也有特別標記的圖示

※document.getElement除了Id外,其他都有加s,所以有s還要用[]指定哪一個



※表格

var table = document.getElementById('tab');
table.setAttribute('border', '1');
var tbody = document.createElement('tbody');
var tr = document.createElement('tr');
var td = document.createElement('td');
    
// 上下
var tabBody = table.appendChild(tbody);
var a00 = tabBody.appendChild(tr);
a00.appendChild(td).appendChild(document.createTextNode('00'));
    
table.insertRow().insertCell().appendChild(document.createTextNode('10'));
    
var a20 = table.insertRow();
a20.insertCell().appendChild(document.createTextNode('20'));
    
// 左右
a00.insertCell().appendChild(document.createTextNode('01'));
a20.insertCell().appendChild(document.createTextNode('21'));

※表格要注意有tbody的存在,雖然不寫也可以,但有時會有不如預期的行為

※appendChild只能使用一次,且一定要有一次(除非寫在HTML)

SOAP

※SOAPBody

try {
    // 查API javax.xml.soap的MessageFactory和SOAPMessage就會有以下的順序
    MessageFactory factory = MessageFactory.newInstance();
    SOAPMessage msg = factory.createMessage();
    SOAPPart part = msg.getSOAPPart();
    SOAPEnvelope envlope = part.getEnvelope();
    SOAPBody body = envlope.getBody();
    
    // <xx:bMethod xmlns:xx="!@#" />
    SOAPBodyElement element = body.addBodyElement(new QName("!@#", "bMethod", "xx"));
    element.setValue("1"); // element.setTextContent("1");
    element.addChildElement("p1").setValue("2");
    element.addChildElement("p2").setValue("3");
    msg.writeTo(System.out);
} catch (SOAPException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
--------------------
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <xx:bMethod xmlns:xx="!@#">
            1
            <p1>2</p1>
            <p2>3</p2>
        </xx:bMethod>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

※上面的測試是不需要啟動伺服器的



※主要程式

※IMessage.java

package webservice;
    
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import jaxb.Dept;
    
@WebService
public interface IMessage {
    @WebResult(name = "dept") // 使用JAXB的unmarshal時,一定要叫dept,才能轉換,否則會出預期xxx的錯
    public Dept aMethod(@WebParam(name = "dept") Dept d);// 使用XPath的NodeList時,一定要叫dept(預設是arg0),這樣XML才會正確,否則都找不到資料
    
    /*
        @WebResult的name裡面不要有空格,將SOAPMessage傳進來時,
        例如將「bFunctionReturn」改成「b function return」之後,
        會出「關聯元素類型 "b" 的屬性名稱 "function"
        之後必須緊接 ' = ' 字元。」的錯
    */
    @WebResult(name = "bFunctionReturn")
    public String bMethod(@WebParam(name = "num") Integer i);
    
    @WebResult(name = "dept") // 名稱要對應到QName,然後給HeaderElement
    public Dept cMethod(@WebParam(name = "headerName", header = true) String headInfo);
}


※MessageImpl.java

package webservice;
    
import java.util.ArrayList;
import java.util.List;
import javax.jws.WebService;
import jaxb.Dept;
import jaxb.Employee;
    
@WebService(endpointInterface = "webservice.IMessage")
public class MessageImpl implements IMessage {
    @Override
    public Dept aMethod(Dept dept) {
        System.out.println("a方法" + dept);
        return dept;
    
    }
    
    @Override
    public String bMethod(Integer i) {
        System.out.println("b方法");
        return i + "b";
    }
    
    @Override
    public Dept cMethod(String headInfo) {
        System.out.println("headInfo=" + headInfo);
        List<Employee> list = new ArrayList<>();
        list.add(new Employee("e1", 1));
        list.add(new Employee("e2", 2));
        return new Dept("d1", 123, list);
    }
}


※MyServer.java

package webservice;
    
import javax.xml.ws.Endpoint;
    
public class MyServer {
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:8888/aaa/bbb/ccc", new MessageImpl());
        System.out.println("server is start...");
    }
}

※打開xxx~~~?wsdl的網頁

<definitions
    ...
    targetNamespace="http://webservice/" 
    name="MessageImplService">
    
    ...
    <service name="MessageImplService">
        <port name="MessageImplPort" binding="tns:MessageImplPortBinding">
            <soap:address location="http://localhost:8888/aaa/bbb/ccc"/>
        </port>
    </service>
</definitions>

※會用到definitions標籤的targetNamespace和name、還有service的子標籤port的name屬性



※測試Service.Mode.MESSAGE

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
    
String ns = "http://webservice/";
try {
    URL url = new URL("http://localhost:8888/aaa/bbb/ccc?wsdl");
    QName sqname = new QName(ns, "MessageImplService");
    Service service = Service.create(url, sqname);
    
    QName qname = new QName(ns, "MessageImplPort");
    Dispatch<SOAPMessage> dispatch = service.createDispatch(qname, SOAPMessage.class, Service.Mode.MESSAGE);
    
    MessageFactory factory = MessageFactory.newInstance();
    SOAPMessage msg = factory.createMessage();
    SOAPPart part = msg.getSOAPPart();
    SOAPEnvelope envlope = part.getEnvelope();
    SOAPBody body = envlope.getBody();
    
    SOAPBodyElement element = body.addBodyElement(new QName(ns, "bMethod", "xx"));
    // 不打num會接收不到,物件會接收「null」字串;基本型別接收「0」
    element.addChildElement("num").setValue("2");
    msg.writeTo(System.out);
    System.out.println();
    
    // 將msg傳到server
    SOAPMessage resMsg = dispatch.invoke(msg);
    resMsg.writeTo(System.out);
    System.out.println();
    
    // 從server傳回來的訊息
    Document doc = resMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
    NodeList nodeList = doc.getElementsByTagName("bFunctionReturn");
    
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node node = nodeList.item(i);
        System.out.println(node.getTextContent()); // 2b
    }
} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (SOAPException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}
--------------------
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <xx:bMethod xmlns:xx="http://webservice/">
            <num>2</num>
        </xx:bMethod>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
--------------------
<S:Envelope
    xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    
    <SOAP-ENV:Header/>
    <S:Body>
        <ns2:bMethodResponse xmlns:ns2="http://webservice/">
            <bFunctionReturn>2b</bFunctionReturn>
        </ns2:bMethodResponse>
    </S:Body>
</S:Envelope>



※Service.Mode.PAYLOAD

import java.io.StringReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.NodeList;
import jaxb.Dept;
import jaxb.Employee;
    
public void serviceModePAYLOADExample() {
    String ns = "http://webservice/";
    try {
        URL url = new URL("http://localhost:8888/aaa/bbb/ccc?wsdl");
        QName sqname = new QName(ns, "MessageImplService");
        Service service = Service.create(url, sqname);
    
        QName qname = new QName(ns, "MessageImplPort");
        Dispatch<Source> dispatch = service.createDispatch(qname, Source.class, Service.Mode.PAYLOAD);
    
        List<Employee> list = new ArrayList<>();
        list.add(new Employee("Bruce", 123));
        list.add(new Employee("Jacky", 456));
        list.add(new Employee("Mary", 789));
        Dept dept = new Dept("information", 2, list);
    
        JAXBContext jaxb = JAXBContext.newInstance(Dept.class);
        Marshaller ms = jaxb.createMarshaller();
    
        // 去掉前面的<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        ms.setProperty(Marshaller.JAXB_FRAGMENT, true);
        StringWriter out = new StringWriter();
        ms.marshal(dept, out);
    
        StringBuffer payload = new StringBuffer();
        payload.append("<xxx:aMethod xmlns:xxx=\"");
        payload.append(ns);
        payload.append("\">");
        payload.append(out.toString());
        payload.append("</xxx:aMethod>");
    
        System.out.println(payload);
        StreamSource rs = new StreamSource(new StringReader(payload.toString()));
    
        Source response = (Source) dispatch.invoke(rs);
        Transformer tran = TransformerFactory.newInstance().newTransformer();
        DOMResult result = new DOMResult();
        tran.transform(response, result);
    
        XPath xpath = XPathFactory.newInstance().newXPath();
        // 如果是找dept它的子元素,能找到,但unmarshal會有錯誤
        NodeList nodeList = (NodeList) xpath.evaluate("//dept", result.getNode(), XPathConstants.NODESET);
        System.out.println(nodeList.getLength());
        for (int i = 0; i < nodeList.getLength(); i++) {
            System.out.println(nodeList.item(i));
            Dept ru = (Dept) jaxb.createUnmarshaller().unmarshal(nodeList.item(i));
            System.out.println(ru.getName() + System.getProperty("line.separator"));
    
            for (Employee emp : ru.getEmps()) {
                System.out.println(emp.getName());
            }
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (JAXBException e) {
        e.printStackTrace();
    } catch (TransformerConfigurationException e) {
        e.printStackTrace();
    } catch (TransformerFactoryConfigurationError | TransformerException e) {
        e.printStackTrace();
    } catch (XPathExpressionException e) {
        e.printStackTrace();
    }
}



※SOAP Header測試

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import jaxb.Dept;
    
public void soapHeadTest() {
    String ns = "http://webservice/";
    try {
        URL url = new URL("http://localhost:8888/aaa/bbb/ccc?wsdl");
        QName sqname = new QName(ns, "MessageImplService");
        Service service = Service.create(url, sqname);
    
        QName qname = new QName(ns, "MessageImplPort");
        Dispatch<SOAPMessage> dispatch = service.createDispatch(qname, SOAPMessage.class, Service.Mode.MESSAGE);
    
        MessageFactory factory = MessageFactory.newInstance();
        SOAPMessage msg = factory.createMessage();
        SOAPPart part = msg.getSOAPPart();
        SOAPEnvelope envlope = part.getEnvelope();
        SOAPBody body = envlope.getBody();
    
        SOAPHeader header = envlope.getHeader();
        if (header == null) {
            header = envlope.addHeader();
        }
        SOAPHeaderElement headElement = header.addHeaderElement(new QName(ns, "headerName", "xx"));
        headElement.setValue("header value!");
    
        body.addBodyElement(new QName(ns, "cMethod", "xx"));
        msg.writeTo(System.out);
        System.out.println();
    
        // 將msg傳到server
        SOAPMessage resMsg = dispatch.invoke(msg);
        resMsg.writeTo(System.out);
        System.out.println();
    
        // 從server傳回來的訊息
        Document doc = resMsg.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
        // Document doc = resMsg.getSOAPBody().extractContentAsDocument();
        NodeList nodeList = doc.getElementsByTagName("dept");
    
        JAXBContext jaxb = JAXBContext.newInstance(Dept.class);
        for (int i = 0; i < nodeList.getLength(); i++) {
            Dept dept = (Dept) jaxb.createUnmarshaller().unmarshal(nodeList.item(i));
            System.out.println(dept.getName());
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (SOAPException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (JAXBException e) {
        e.printStackTrace();
    }
}




※Exception

加入Exception後,會在wsdl的網址出現fault的標籤

@WebResult(name = "dept")
public Dept dMethod(@WebParam(name = "name") String name, @WebParam(name = "did") int did) throws DeptException;
--------------------
@Override
public Dept dMethod(String name, int did) throws DeptException {
    if ("xxx".equals(name) && did == 111) {
        List<Employee> list = new ArrayList<>();
        list.add(new Employee("e1", 1));
        list.add(new Employee("e2", 2));
        Dept dept = new Dept("xxx", 111, list);
        return dept;
    }
    
    /*
     * 使用RuntimeException,也會在伺服器端的console報錯,因為DeptException在wsdl的網頁有截取(fault
     * );而RuntimeException沒有
     * 只要有在wsdl有設定Exception,截取到就會直接往客戶端拋,所以伺服器端沒有截取錯誤訊息
     * 如沒有在wsdl設定,則伺服器端和客戶端接會拋出訊息
     */
    // throw new RuntimeException(name + " and " + did + " not match!" +
    // System.getProperty("line.separator"));
    
    throw new DeptException(name + " and " + did + " not match!" + System.getProperty("line.separator"));
}

※name是xxx,did是111才不會出錯,但這裡要測試出錯,所以待會的測試類不要輸入這一組


※DeptException.java

public class DeptException extends Exception {
    public DeptException() {
        super();
    }
    
    public DeptException(String arg0, Throwable arg1, boolean arg2, boolean arg3) {
        super(arg0, arg1, arg2, arg3);
    }
    
    public DeptException(String message, Throwable cause) {
        super(message, cause);
    }
    
    public DeptException(String message) {
        super(message);
    }
    
    public DeptException(Throwable cause) {
        super(cause);
    }
}

※這裡的建構子都是用IDE產生的


※測試類

String ns = "http://webservice/";
try {
    URL url = new URL("http://localhost:8888/aaa/bbb/ccc?wsdl");
    QName sqname = new QName(ns, "MessageImplService");
    Service service = Service.create(url, sqname);
    
    QName qname = new QName(ns, "MessageImplPort");
    Dispatch<SOAPMessage> dispatch = service.createDispatch(qname, SOAPMessage.class, Service.Mode.MESSAGE);
    
    MessageFactory factory = MessageFactory.newInstance();
    SOAPMessage msg = factory.createMessage();
    SOAPPart part = msg.getSOAPPart();
    SOAPEnvelope envlope = part.getEnvelope();
    SOAPBody body = envlope.getBody();
    
    SOAPBodyElement element = body.addBodyElement(new QName(ns, "dMethod", "xx"));
    element.addChildElement("name").setValue("xxx");// 不打num會接收null;但如果是int會接收0
    element.addChildElement("did").setValue("222");
    msg.writeTo(System.out);
    System.out.println();
    
    // 將msg傳到server
    SOAPMessage resMsg = dispatch.invoke(msg);
    resMsg.writeTo(System.out);
    System.out.println();
    
    // 從server傳回來的訊息
    Document doc = resMsg.getSOAPBody().extractContentAsDocument();
    NodeList nodeList = doc.getElementsByTagName("dept");
    
    JAXBContext jaxb = JAXBContext.newInstance(Dept.class);
    for (int i = 0; i < nodeList.getLength(); i++) {
        Dept dept = (Dept) jaxb.createUnmarshaller().unmarshal(nodeList.item(i));
        for (Employee e : dept.getEmps()) {
            System.out.println(e.getName());
        }
    }
} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (SOAPException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (JAXBException e) {
    e.printStackTrace();
} catch (SOAPFaultException e) {
    // 不可截取DeptException,使用wsimport就可以知道
    System.out.println(e.getMessage());// call DeptException(String)
}





※Handler

LogicalHandler:獲取SOAPBody的訊息
SOAPHandler:獲取SOAPMessage的訊息
伺服器和客戶端都可以設定很多LH的和SH
客戶端都先處理LH,全部的LH處理完才處理SH
伺服器端則相反

參考網址:apache JAVAEE連結






@WebService(endpointInterface = "webservice.IMessage")
@HandlerChain(file="/soap/handler/handlers.xml")
public class MessageImpl implements IMessage {
    // ...
}

※這裡的@HandlerChain裡的xml路徑只要抓的到,在啟伺服器時才不會出錯


※handlers.xml

<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
    <handler-chain>
        <handler>
            <handler-name>ooo.xxx.z1</handler-name>
            <handler-class>soap.handler.Handler1</handler-class>
        </handler>
        <handler>
            <handler-name>ooo.xxx.z2</handler-name>
            <handler-class>soap.handler.Handler2</handler-class>
        </handler>
    </handler-chain>
</handler-chains>

※寫了兩支處理handler的xml,所以也要實作出來,將上面的網址複製下來改即可


※Handler1.xml

public class Handler1 implements SOAPHandler<SOAPMessageContext> {
    @Override
    public void close(MessageContext arg0) {
        System.out.println("s1 close");
    }
    
    @Override
    public boolean handleFault(SOAPMessageContext arg0) {
        System.out.println("s1 handleFault");
        return true;
    }
    
    @Override
    public boolean handleMessage(SOAPMessageContext arg0) {
        System.out.println("s1 handleMessage");
        return true;
    }
    
    @Override
    public Set<QName> getHeaders() {
        System.out.println("s1 getHeaders");
        return null;
    }
}



※Handler2.java

public class Handler2 implements SOAPHandler<SOAPMessageContext> {
    @Override
    public void close(MessageContext arg0) {
        System.out.println("s2 close");
    }
    
    @Override
    public boolean handleFault(SOAPMessageContext arg0) {
        System.out.println("s2 handleFault");
        return true;
    }
    
    @Override
    public boolean handleMessage(SOAPMessageContext arg0) {
        System.out.println("s2 handleMessage");
        return true;
    }
    
    @Override
    public Set<QName> getHeaders() {
        System.out.println("s2 getHeaders");
        return null;
    }
}

※測試時還是用Exception的測試類

※沒有錯時的結果為:
s1 getHeaders
s2 getHeaders
server is start...
s2 handleMessage
s1 handleMessage
s1 handleMessage
s2 handleMessage
s1 close
s2 close

※有錯時的結果為:
s1 getHeaders
s2 getHeaders
server is start...
s2 handleMessage
s1 handleMessage
s1 handleFault
s2 handleFault
s1 close
s2 close

※可以發現在啟何服器時都會先執行兩支的getHeaders方法,結束也都會執行close

※有錯時才會執行handleFault方法

※要注意handleMessage和其他是相反的,先執行s2;後執行s1
沒錯時,一支handleMessage是request和response,共兩次;有錯時只會執行一次

※handleMessage執行完才會執行Exception;使用RuntimeException還是會在伺服器端報錯

2016年11月22日 星期二

三級聯動

※第一步

const scn = {'south':'北', 'center':'中', 'north':'南'};
let arr = [scn.south, scn.center, scn.north];
arr[scn.south] = ['s1', 's2', 's3'];
arr[scn.center] = ['c1', 'c2'];
arr[scn.north] = ['n1', 'n2', 'n3', 'n4'];
    
arr['s1'] = ['s11', 's12', 's13', 's14', 's15'];
arr['s2'] = ['s21', 's22', 's23', 's24'];
arr['s3'] = ['s31', 's32'];
    
arr['c1'] = ['c11', 'c12'];
arr['c2'] = ['c21', 'c22', 'c23', 'c24'];
    
arr['n1'] = ['n11', 'n12', 'n13'];
arr['n2'] = ['n21', 'n22'];
arr['n3'] = ['n31', 'n32', 'n33'];
arr['n4'] = ['n41', 'n42', 'n43', 'n44', 'n45'];
    
window.onload = function(){
    //alert(arr[0]);//北
    //alert(arr[arr[0]][0]);//s1
    //alert(arr[arr[arr[0]][0]][0]);//s11
    //arr[]裡面包上一層的內容,然後看要顯示第幾個就加[number]
    
    //alert(arr.length); // 3
    //alert(arr[arr[0]].length); // 3
    //alert(arr[arr[arr[0]][0]].length); // 5
    
    //預設為:北/s1/s11
    for(let i=0; i<arr.length; i++){
        let option = new Option();
        option.value = i;
        option.text = arr[i];
        document.getElementById('first').options.add(option);
    }
    
    // arr[arr[0]] = arr[scn.south] = arr['北']
    for(let j=0; j<arr[arr[0]].length; j++){
        let option = new Option(arr[arr[0]][j], j);
        document.getElementById('second').options.add(option);
    }
    
    for(let k=0; k<arr[arr[arr[0]][0]].length; k++){
        let option = new Option(arr[arr[arr[0]][0]][k], k);
        document.getElementById('third').options.add(option);
    }
}
    
function firstChangeSecond(val){
    document.getElementById('second').options.length = 0;
    for(let j=0; j<arr[arr[val]].length; j++){
        let option = new Option(arr[arr[val]][j], j);
        document.getElementById('second').options.add(option);
    }
    
    secondChangeThird(this.getOptionValue('second'));
}
    
function secondChangeThird(val){
    /*
    alert('00=' + arr[arr[arr[0]][0]]);//s11~s15
    alert('10=' + arr[arr[arr[1]][0]]);//c11 c12
    alert('01=' + arr[arr[arr[0]][1]]);//s21~24
    */
    
    let firstSelectValue = this.getOptionValue('first');
    document.getElementById('third').options.length = 0;
    for(let k=0; k<arr[arr[arr[firstSelectValue]][val]].length; k++){
        let option = new Option(arr[arr[arr[firstSelectValue]][val]][k], k);
        document.getElementById('third').options.add(option);
    }
}
    
function getOptionValue(id){
    let ops = document.getElementById(id).options;
    for(let i=0; i<ops.length; i++){
        if(ops[i].selected){
            return i;
        }
    }
}
--------------------
<select id='first' onchange="firstChangeSecond(this.value)"></select>
<select id='second' onchange="secondChangeThird(this.value)"></select>
<select id='third'></select>




※第二步,將相同用法提出

window.onload = function(){
    //預設為:北/s1/s11
    changeSelect(arr, 'first');
    changeSelect(arr[arr[0]], 'second');
    changeSelect(arr[arr[arr[0]][0]], 'third');
}
    
function firstChangeSecond(val){
    changeSelect(arr[arr[val]], 'second');
    secondChangeThird(this.getOptionValue('second'));
}
    
function secondChangeThird(val){
    let firstSelectValue = this.getOptionValue('first');
    changeSelect(arr[arr[arr[firstSelectValue]][val]], 'third');
}
    
function getOptionValue(id){
    let ops = document.getElementById(id).options;
    for(let i=0; i<ops.length; i++){
        if(ops[i].selected){
            return i;
        }
    }
}
    
function changeSelect(arr, id){
    document.getElementById(id).options.length = 0;
    for(let i=0; i<arr.length; i++){
        let option = new Option(arr[i], i);
        document.getElementById(id).options.add(option);
    }
}



2016年11月21日 星期一

物件導向 (JavaScript 7)

※Object

Object 屬性 方法 繼承

let o = {
    id:5,
    name:function(){
        return "bruce";
    },
    set nid(id){
        this.id = id;
    },
    get nid(){
        return this.id;
    }
};
    
console.log(o.id); // 5
o.nid = 100;
console.log(o.id); // 100
console.log(o.nid); // 100
    
let o_child = Object.create(o); // 繼承
console.log(o_child.nid); // 100

※set get 取名時不能和已有的 key 相同

※set 只能剛好有一個參數; get 不能有參數

※使用["name"]這種方式也行,裡面可以有特殊符號、空格,甚至還可以是變數



set/get 方法名稱為變數

let variable = "nid";
let o = {
    id:5,
    name:function(){
        return "bruce";
    },
    set [variable](id){
        this.id = id;
    },
    get [variable](){
        return this.id;
    }
};
    
console.log(o.id); // 5
o.nid = 100;
console.log(o.id); // 100
console.log(o.nid); // 100
    
let o_child = Object.create(o);
console.log(o_child.nid); // 100

※主要看 o.id 有沒有變化
因為 o.nid 本來就可以在物件外給 key-value,如果 set 沒成功,o.id 和 o_child.id 的值會是 5



var

// var o = {
//     id:6
// };
    
var o = o || {
    id:5,
    name:function(){
        return "bruce";
    },
    set nid(id){
        this.id = id;
    },
    get nid(){
        return this.id;
    }
};
    
console.log(o.id); // 5
o.nid = 100;
console.log(o.nid); // 100
    
let o_child = Object.create(o);
console.log(o_child.nid); // 100

※如果宣告用 var 的話,還可以用 var o = o || {};,表示如果已經有 o 這個變數就用,不然就用空的,但用 const 或 let 都不行



※function

return 物件

function Xxx(){
    this.name = "x";
    // return 10;
    // return {a:1};
}
    
var x = new Xxx();
console.log(x.name);// x
// console.log(new Xxx());// Xxx {name: "x"}
// console.log(x.a);

※寫了 this.xxx 而且不管有沒有寫 return 一般的值,這兩者都可以 new 後直接.屬性/方法

※寫了 this.xxx 而且寫了 return 物件或 funtion,那 new 後直接.屬性和.方法不加「()」會是undefined,但可內部調用



function 屬性 方法 繼承

function X(){
    this.id = 5;
    this["name"] = function() {
        return "bruce";
    },
    this.setId = function(id) {
        this.id = id;
    }
    this.getId = function() {
        return this.id;
    }
}
    
let xxx = new X();
console.log(xxx.id);
xxx.setId(50);
console.log(xxx.getId());
    
function x_child(){}
x_child.prototype = new X(); // prototype 繼承
let x_child2 = Object.create(new X()); // Object 繼承
    
let x_child1 = new x_child();
console.log(x_child1.getId());
console.log(x_child2.getId());

※「.」也可用「[ ]」

※function 有兩種繼承

※如果在 function 內宣告 var 屬性和方法,只能內部調用,外面呼叫都是 undefined



新增/修改屬性、方法

function X(){
    this.id = 5;
    this["name"] = function() {
        return "bruce";
    },
    this.setId = function(id) {
        this.id = id;
    }
    this.getId = function() {
        return this.id;
    }
}
    
X.prototype.method = function(){
    return "method";
}
    
let xxx = new X();
console.log(xxx.method()); // method
    
function x_child(){}
x_child.prototype = new X(); // prototype 繼承
let x_child2 = Object.create(new X()); // Object 繼承
    
let x_child1 = new x_child();
console.log(x_child1.method()); // method
console.log(x_child2.method()); // method

※可以在 function 外直接新增,使用 function名稱.prototype.方法或屬性即可

※注意寫在 function 外的屬性和方法可以一直覆蓋下去,但本來就在 function 裡的屬性和方法,並不會覆蓋,而且也不會報錯

※宣告的 prototype 上面可加個 if 判斷,如 if(!X.prototype.method),沒有的才做,可以避開瀏覽器不支援的情形



一次新增多個屬性、方法

function X(){
    this.id = 5;
    this["name"] = function() {
        return "bruce";
    },
    this.setId = function(id) {
        this.id = id;
    }
    this.getId = function() {
        return this.id;
    }
}
    
// X.prototype.method1 = function(){
//     return "method1";
// }
    
// X.prototype.method2 = function(){
//     return "method2";
// }
    
X.prototype = {
    method1 : function(){
        return "method1";
    },
    method2 : function(){
        return "method2";
    },
};
    
let x = new X();
console.log(x.method1()); // method1
console.log(x.method2()); // method2

※當然還是會後者蓋前者



※class

class 繼承

class SonDate extends Date {
    xxx() {
        return "xxx";
    }
}
    
let son = new SonDate();
console.log(son.getDate());
console.log(son.xxx());

※由於繼承了內鍵的 Date,所以可以用它的方法

※也可以繼承自己寫的 class

※只能在方法裡寫變數(this.xxx、var xxx 都一樣)



class getter/setter constructor

class SonDate {
    xxx(){
        return this.id + "-" + this.name;
    }
    
    constructor(id, name) {
        this.id = id;
        this.name = name;
    }
    
    get abc(){
        return this.id;
    }
    
    set abc(id){
        this.id = id;
    }
}
    
let son = new SonDate(7, "mary");
console.log(son.xxx()); // 7-mary
console.log(son.abc); // 7
son.abc = 50;
console.log(son.abc); // 50

※set get 取名時不能和屬性相同

※如果有繼承,而且寫了 constructor ,那第一行就一定要寫 super(),當然參數就看繼承誰了

※最多只能有一個 constructor



set/get 方法名稱為變數

let variable = "abc";
    
class SonDate {
    xxx(){
        return this.id + "-" + this.name;
    }
    
    constructor(id, name) {
        this.id = id;
        this.name = name;
    }
    
    get [variable](){
        return this.id;
    }
    
    set [variable](id){
        this.id = id;
    }
}
    
let son = new SonDate(7, "mary");
console.log(son.xxx()); // 7-mary
console.log(son.abc); // 7
son.abc = 50;
console.log(son.abc); // 50

※主要看第二個 son.abc,失敗的話是 undefined



static

class SonDate {
    static method() {
        return SonDate.xxx();
    }
    
    static xxx() {
        return "x1";
    }
    
    xxx() {
        return "x2";
    }
}
    
console.log(SonDate.method()); // x1

※static 呼叫 static,要用「類.static 方法名」(java直接呼叫 static 方法名);
呼叫 non static 用 new

※static 不能寫屬性

※如果有繼承,還可用 super.父類方法名

2016年11月14日 星期一

Schema標籤用法

參考資料

※simpleType、complexType

※test.xsd

<element name="root">
    <complexType>
        <sequence>
            <element name="aaa" type="date" />
            <element name="bbb" type="boolean" default="false" />
            <element name="ccc" type="decimal" fixed="20.0" />
            <element name="ddd" type="bruce:sType1" />
            <element name="eee" type="bruce:sType2" />
    
            <element name="fff">
                <simpleType>
                    <restriction base="integer">
                        <pattern value="[0-9]{3}" />
                    </restriction>
                </simpleType>
            </element>
            
            <element name="ggg" type="bruce:cType" />
        </sequence>
    </complexType>
</element>
    
<simpleType name="sType1">
    <restriction base="int">
        <minInclusive value="100" />
        <maxExclusive value="1000" />
    </restriction>
</simpleType>
    
<simpleType name="sType2">
    <restriction base="string">
        <minLength value="2" />
        <maxLength value="4" />
    </restriction>
</simpleType>
    
<complexType name="cType">
    <sequence>
        <element name="g1" type="string" />
        <element name="g2" type="string" />
    </sequence>
</complexType>

※上一篇有說明命名空間了,所以只把必要的程式碼列出

※type有很多,但最長用的有6個,分別是string、decimal、integer、boolean、date、time

※pattern是正則表達式

※sequence表示元素要按照順序出現;如果不要順序,可以用all

※sType1是針對數字範圍的設定
include表示有包括0、exclude表示排除0,所以
maxExclusive:>
maxInclusive:>=
minExclusive:<
minInclusive:<=
會自動有min不能大於max的檢核


※sType2是針對字串範圍的設定,有3種
minLength、maxLength:<=、>=
length:如果上面兩個設定一樣,例如長度<=2,而且>=2,那就設定這一個就好了

※test.xml

<?xml version="1.0" encoding="UTF-8"?>
<b:root xmlns:b="456" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="456 Test.xsd">
    
    <b:aaa>2010-10-12</b:aaa>
    <b:bbb>true</b:bbb>
    <b:ccc>20.0</b:ccc>
    <b:ddd>123</b:ddd>
    <b:eee>abc</b:eee>
    <b:fff>456</b:fff>
    <b:ggg>
        <b:g1>g1</b:g1>
        <b:g2>g2</b:g2>
    </b:ggg>
</b:root>

※ddd和fff的檢核其實是一樣的



※空元素、屬性

※Test.xsd

<element name="root">
    <complexType>
        <sequence minOccurs="1" maxOccurs="1" >
    
            <element name="aaa">
                <complexType>
                    <attribute name="attr1" type="nonPositiveInteger" use="required" />
                </complexType>
            </element>
    
            <element name="bbb">
                <complexType>
                    <complexContent>
                        <restriction base="bruce:cType" />
                    </complexContent>
                </complexType>
            </element>
    
            <element name="ccc" type="bruce:cType" />
        </sequence>
    </complexType>
</element>
    
<complexType name="cType">
    <attribute name="attr2" type="nonNegativeInteger" use="required" />
</complexType>



※Test.xml

<bruce:root xmlns:bruce="456"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="456 Test.xsd ">
    
    <bruce:aaa attr1="-1" />
    <bruce:bbb attr2="1" />
    <bruce:ccc attr2="1" />
</bruce:root>

※屬性的use有三種:
optional:預設,表示可選的
required:一定要有
prohibited:一定不能有

※type的數字有四種,non開頭表示有包括0,所以
nonPositiveInteger:負整數,有包括0
nonNegativeInteger:正整數,有包括0
positiveInteger:正整數,不包括0
negativeInteger:負整數,不包括0

※minOccurs和maxOccurs預設都是1,表示以下的元素只能出現一次
unbounded是無限多次,也就是*的意思



※元素的多選一、屬性組、元素組

※Test.xsd

<element name="root">
    <complexType>
        <group ref="bruce:gp" />
        <attributeGroup ref="bruce:agp" />
    </complexType>
</element>
    
<group name="gp">
    <sequence>
        <element name="aaa" type="string" />
        <element name="bbb" type="string" />
        <element name="ccc">
            <complexType>
                <attribute name="cccAttr" type="date" use="required" />
            </complexType>
        </element>
        <choice>
            <element name="choice1" type="string" />
            <element name="choice2">
                <complexType>
                    <attribute name="c2attr" type="string" use="required" />
                </complexType>
            </element>
            <element name="choice3" type="boolean" />
        </choice>
    </sequence>
</group>
    
<attributeGroup name="agp">
    <attribute name="attr1" type="string" use="required" />
    <attribute name="attr2" type="int" use="required" />
    <attribute name="attr3" type="boolean" use="required" />
</attributeGroup>

※group是設定元素組的地方

※attributeGroup是設定屬性組的地方

※choice裡面的元素是多選一

※Test.xml

<?xml version="1.0" encoding="UTF-8"?>
<b:root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="456 Test.xsd"
    attr1="xxx"
    attr2="0"
    attr3="true"
    xmlns:b="456">
    
    <b:aaa>b:aaa</b:aaa>
    <b:bbb>b:bbb</b:bbb>
    <b:ccc cccAttr="2001-01-01" />
    <b:choice2 c2attr="ooo" />
</b:root>




※延伸、限制

※Test.xsd

<element name="root">
    <complexType>
        <all>
            <element name="aaa">
                <complexType>
                    <simpleContent>
                        <extension base="integer">
                            <attribute name="attr1" type="bruce:allSize" use="required" />
                        </extension>
                    </simpleContent>
                </complexType>
            </element>
    
            <element ref="bruce:bbb" />
    
            <element name="ccc">
                <simpleType>
                    <restriction base="int">
                        <minExclusive value="100" />
                        <maxExclusive value="1000" />
                    </restriction>
                </simpleType>
            </element>
    
            <element name="ddd" type="bruce:allSize" />
        </all>
    </complexType>
</element>
    
<simpleType name="allSize">
    <restriction base="string">
        <enumeration value="S" />
        <enumeration value="M" />
        <enumeration value="L" />
        <enumeration value="XL" />
        <enumeration value="XXL" />
    </restriction>
</simpleType>
    
<complexType name="baseElement">
    <choice>
        <element name="base1" type="string" />
        <element name="base2" type="string" />
    </choice>
</complexType>
    
<element name="bbb">
    <complexType>
        <complexContent>
            <extension base="bruce:baseElement">
                <sequence>
                    <element name="base3" type="string" />
                    <element name="base4" type="string" />
                </sequence>
            </extension>
        </complexContent>
    </complexType>
</element>

※extension和restriction裡面可以是空的,也就是等於的意思

※aaa延伸integer的功能,還是int

※bbb延伸baseElement的二選一功能,變成134或234,complexContent才可以增加元素

※ccc是限制數字的範圍

※ddd是限制字串只能是5個其中之一


※Test.xml

<?xml version="1.0" encoding="UTF-8"?>
<b:root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:b="456"
    xsi:schemaLocation="456 Test.xsd">
    
    <b:aaa attr1="S">0</b:aaa>
    <b:bbb>
        <b:base1>one</b:base1>
        <b:base3>three</b:base3>
        <b:base4>four</b:base4>
    </b:bbb>
    <b:ccc>101</b:ccc>
    <b:ddd>S</b:ddd>
</b:root>





※any、anyAttribute

※Test.xsd

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="456"
    xmlns:bruce="456" 
    elementFormDefault="qualified">
    
    <element name="root">
        <complexType>
            <sequence>
                <element name="aaa">
                    <complexType>
    
                        <!-- <anyAttribute /> -->
    
                        <simpleContent>
                            <extension base="string">
                                <anyAttribute />
                            </extension>
                        </simpleContent>
    
                    </complexType>
                </element>
                <any minOccurs="1" maxOccurs="3" />
            </sequence>
    
            <anyAttribute />
    
        </complexType>
    </element>
</schema>

※註解那行改成下面的simpleContent,
如果不註解沒辦法在aaa設定型態,aaa的內容只能是空的
在aaa設定型態會出「Element 'aaa' has both a 'type' attribute and a 'anonymous type' child. Only one of these is allowed for an element.」的錯
所以改成simpleContent,下面用extension的base屬性指定型態


※Test2.xsd

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
    targetNamespace="+-"
    elementFormDefault="qualified">
    
    <element name="bbb" type="string" />
    <attribute name="bAttr" type="int" />
</schema>

※設定一個元素和屬性

※Test.xml

<?xml version="1.0" encoding="UTF-8"?>
<b:root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:b="456"
    xmlns:b2="+-"
    xsi:schemaLocation="456 Test.xsd +- Test2.xsd" 
    b2:bAttr="1">
    
    <b:aaa b2:bAttr="2">xxx</b:aaa>
    <b2:bbb>ooo</b2:bbb>
</b:root>

※如果將Test.xsd的any或anyAttrubute註解,將會報錯



※substitution

代換和禁止代換

※test.xsd

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="456"
    xmlns:bruce="456" 
    elementFormDefault="qualified">
    
    <element name="up" type="bruce:pType" />
    <element name="root" substitutionGroup="bruce:up" />
    
    <element name="p1" type="string" />
    <element name="p2" substitutionGroup="bruce:p1" />
    
    <element name="b1" type="string" block="substitution"/>
    <element name="b2" substitutionGroup="bruce:b1" />
    
    <complexType name="pType">
        <sequence>
            <element ref="bruce:p1" />
            <element ref="bruce:b1" />
        </sequence>
    </complexType>
</schema>



※test.xml

<?xml version="1.0" encoding="UTF-8"?>
<b:up xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:b="456"
    xsi:schemaLocation="456 Test.xsd">
    
    <b:p2></b:p2>
    <b:b1></b:b1>
</b:up>

※up和root可以互換;p1和p2也可以互換,但b1不能用b2替換,因為b1有設block="substitution",不給替換,所以打b2會有錯

2016年11月13日 星期日

XPath

參考資料(英文版)
參考資料(簡中版)
XPath在javax.xml.xpath包裡
這篇的Document、Element、NodeList是import org.w3c.dom 這一包,不要import錯了

※test.xml

<root>
    <first fa="f1">
        <second sa="s1">a1</second>
        <second>
            <third>
                a2
                <fourth>
                    a3
                </fourth>
            </third>
            b1
        </second>
        <second>c1</second>
    </first>
    
    <first fa="f2">
        <second sa="s2">d1</second>
        <first fa="f2">
            e1
            <second sa="s3">
                e2
                <third>e3</third>
            </second>
        </first>
        <second>f1</second>
    </first>
    
    <first fa="f3">
        <second sa="s3">g1</second>
        <second>
            h1
            <first fa="f3">
                h2
                <third>
                    h3
                    <second>
                        h4
                    </second>
                </third>
            </first>
        </second>
        <second>i1</second>
    </first>
</root>

※測試用的xml


※Test.java

try (InputStream is = Test.class.getClassLoader().getResourceAsStream("test.xml")) {
    try {
        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = db.parse(is);
        XPath xpath = XPathFactory.newInstance().newXPath();
        NodeList list = (NodeList) xpath.evaluate("//first[@fa='f1']", doc, XPathConstants.NODESET);
    
        for (int i = 0; i < list.getLength(); i++) {
            Element element = (Element) list.item(i);
            NodeList list2 = element.getElementsByTagName("second");
            for (int j = 0; j < list2.getLength(); j++) {
                // System.out.println("node name=" + list2.item(j).getNodeName());
                System.out.println("text content=" + list2.item(j).getTextContent());
                
                NamedNodeMap map = list2.item(j).getAttributes();
                System.out.println("attr=>" + map.getNamedItem("sa"));
                System.out.println("==========");
            }
        }
    } catch (ParserConfigurationException e) {
        e.printStackTrace();
    } catch (SAXException e) {
        e.printStackTrace();
    } catch (XPathExpressionException e) {
        e.printStackTrace();
    }
} catch (IOException e1) {
    e1.printStackTrace();
}

※XPathConstants.NODESET表示回傳什麼型態,有5種
NUMBER、STRING、BOOLEAN這3個就不用說了
NODESET:回傳0~多個結點
NODE:回傳0~1個結點
下面還會說明兩者的差異

※「//first[@fa='f1']」的結果為:
text content=a1
attr=>sa="s1"
==========
text content=

a2

a3


b1

attr=>null
==========
text content=c1
attr=>null
==========

second有3個,所以會跑3次,可以看到第2個second以下的(包括子元素)都會跑,甚至連換行都有


※「//first[@fa='f2']」的結果為:
text content=d1
attr=>sa="s2"
==========
text content=
e2
e3

attr=>sa="s3"
==========
text content=f1
attr=>null
==========
text content=
e2
e3

attr=>sa="s3"
==========

因為first屬性是f2的有兩個,所以會跑4次


※「//first[@fa='f3']」的結果為:
text content=g1
attr=>sa="s3"
==========
text content=
h1

h2

h3

h4




attr=>null
==========
text content=
h4

attr=>null
==========
text content=i1
attr=>null
==========
text content=
h4

attr=>null
==========

first屬性是f3有兩個,第一次跑second有4個
然後第二次又再跑一次,所以是5次


※「//」和「/」的差別

//:不管任何層級,全部都會找
/:只會從根目錄開始找,以上面的例子,就是root

以「//first[@fa='f2']」為例,改成「/first[@fa='f2']」什麼結果都沒有,因為根目錄是root
再改成「/root/first[@fa='f2']」可以找到,但因為是從根目錄開始找,所以結果只會跑3次,少了子元素是first且屬性是fa,值是f2的那一次

※以上面的例子「/root/first」 可以發現NodeList長度為3,也就是全部都抓,如果只想抓第二筆,可以用「/root/first[2]」,要注意是從1開始的


※XPathConstants.NODESET/NODE差異

※「/」也可以用Node,就是上面程式碼的XPathConstants.NODESET,改成XPathConstants.NODE,如下:
try (InputStream is = TestJunit.class.getClassLoader().getResourceAsStream("xml.xml")) {
    try {
        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = db.parse(is);
        XPath xpath = XPathFactory.newInstance().newXPath();
        Element element = (Element) xpath.evaluate("//first[@fa='f2']", doc, XPathConstants.NODE);
        NodeList list2 = element.getElementsByTagName("second");

        System.out.println(list2.getLength());
        for (int j = 0; j < list2.getLength(); j++) {
            System.out.println("text content=" + list2.item(j).getTextContent());
    
            NamedNodeMap map = list2.item(j).getAttributes();
            System.out.println("attr=>" + map.getNamedItem("sa"));
            System.out.println("==========");
        }
    } catch (ParserConfigurationException e) {
        e.printStackTrace();
    } catch (SAXException e) {
        e.printStackTrace();
    } catch (XPathExpressionException e) {
        e.printStackTrace();
    }
} catch (IOException e1) {
    e1.printStackTrace();
}

※Node強轉成Element;Node強轉成NodeList

2016年11月11日 星期五

XMLInputFactory

※XMLInputFactory


※xml.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <first fa="f1">
        <second1 sa="s1">aaa</second1>
        <second2>bbb</second2>
        <second3>ccc</second3>
    </first>
    
    <first fa="f2">
        <second1 sa="s2">ddd</second1>
        <second2>eee</second2>
        <second3>fff</second3>
    </first>
    
    <first fa="f3">
        <second1 sa="s3">ggg</second1>
        <second2>hhh</second2>
        <second3>iii</second3>
    </first>
</root>

※測試用的xml


※循序讀取

public void readXMLSequence() throws XMLStreamException {
    XMLInputFactory factory = XMLInputFactory.newInstance();
    try (InputStream is = Test.class.getClassLoader().getResourceAsStream("xml.xml")) {
        XMLStreamReader reader = null;
        reader = factory.createXMLStreamReader(is);
        while (reader.hasNext()) {
            int type = reader.next();
            System.out.println("type=" + type);
    
            if (type == XMLStreamConstants.START_ELEMENT) {
                System.out.println("<" + reader.getName() + ">");
            } else if (type == XMLStreamConstants.CHARACTERS) {
                System.out.println("tag之間=" + reader.getText().trim());
            } else if (type == XMLStreamConstants.END_ELEMENT) {
                System.out.println("</" + reader.getName() + ">");
            }
        }
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

※tag和tag之間也會讀取


※讀取屬性

public void readXMLAttribute() throws XMLStreamException {
    XMLInputFactory factory = XMLInputFactory.newInstance();
    try (InputStream is = Test.class.getClassLoader().getResourceAsStream("xml.xml")) {
        XMLStreamReader reader = null;
        reader = factory.createXMLStreamReader(is);
        while (reader.hasNext()) {
            int type = reader.next();
            if (type == XMLStreamConstants.START_ELEMENT) {
                String name = reader.getName().toString();
                if ("first".equals(name)) {
                    for (int i = 0; i < reader.getAttributeCount(); i++) {
                        System.out.println("attribute name=" + reader.getAttributeName(i));
                        System.out.println("attribute value=" + reader.getAttributeValue(i));
                    }
                }
            }
        }
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

※getResourceAsStream不熟的可看這篇


※讀取指定的元素

public void readXMLElement() throws XMLStreamException {
    XMLInputFactory factory = XMLInputFactory.newInstance();
    try (InputStream is = Test.class.getClassLoader().getResourceAsStream("xml.xml")) {
        XMLStreamReader reader = null;
        reader = factory.createXMLStreamReader(is);
    
        while (reader.hasNext()) {
            int type = reader.next();
            if (type == XMLStreamConstants.START_ELEMENT) {
                String name = reader.getName().toString();
                if ("second2".equals(name)) {
                    System.out.println("second2=" + reader.getElementText());
                }
    
                if ("second3".equals(name)) {
                    System.out.println("second3" + reader.getElementText() + System.getProperty("line.separator"));
                }
            }
        }
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

※只抓元素是second2和second3


※讀取指定的元素2

public void readXMLElement2() throws XMLStreamException {
    XMLInputFactory factory = XMLInputFactory.newInstance();
    try (InputStream is = Test.class.getClassLoader().getResourceAsStream("xml.xml")) {
        XMLEventReader reader = factory.createXMLEventReader(is);
    
        int count = 0;
        while (reader.hasNext()) {
            XMLEvent event = reader.nextEvent();
            if (event.isStartElement()) {
                String name = event.asStartElement().getName().toString();
                if ("second2".equals(name)) {
                    System.out.println("second2=" + reader.getElementText());
                }
                if ("second3".equals(name)) {
                    System.out.println("second3" + reader.getElementText());
                }
            }
            count++;
        }
        System.out.println(count);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

※使用XMLEvent


※使用過濾器

public void readXMLFilter() throws IOException {
    XMLInputFactory factory = XMLInputFactory.newInstance();
    try (InputStream is = Test.class.getClassLoader().getResourceAsStream("xml.xml")) {
        XMLEventReader reader = factory.createFilteredReader(factory.createXMLEventReader(is), new EventFilter() {
            @Override
            public boolean accept(XMLEvent event) {
                if (event.isStartElement()) {
                    String name = event.asStartElement().getName().toString();
                    if (Arrays.asList("second2", "second3").contains(name)) {
                        return true;
                    }
                }
                return false;
            }
        });
    
        int count = 0;
        while (reader.hasNext()) {
            XMLEvent event = reader.nextEvent();
            if (event.isStartElement()) {
                String name = event.asStartElement().getName().toString();
                if ("second2".equals(name)) {
                    System.out.println("second2=" + reader.getElementText());
                }
                if ("second3".equals(name)) {
                    System.out.println("second3" + reader.getElementText());
                }
            }
            count++;
        }
        System.out.println(count);
    } catch (XMLStreamException e) {
        e.printStackTrace();
    }
}