From: Olyutorskii Date: Tue, 23 Aug 2011 15:57:20 +0000 (+0900) Subject: XML名前空間対応 X-Git-Tag: fromMercurial~52 X-Git-Url: http://git.osdn.net/view?p=mikutoga%2FTogaGem.git;a=commitdiff_plain;h=21250dabe0bcb20203b8844fa20bb2b220e35636 XML名前空間対応 --- diff --git a/src/main/java/jp/sourceforge/mikutoga/xml/DomNsUtils.java b/src/main/java/jp/sourceforge/mikutoga/xml/DomNsUtils.java new file mode 100644 index 0000000..8e338b8 --- /dev/null +++ b/src/main/java/jp/sourceforge/mikutoga/xml/DomNsUtils.java @@ -0,0 +1,269 @@ +/* + * XML DOM utilities with namespace + * + * License : The MIT License + * Copyright(c) 2011 MikuToga Partners + */ + +package jp.sourceforge.mikutoga.xml; + +import java.text.MessageFormat; +import java.util.Iterator; +import javax.xml.bind.DatatypeConverter; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * DOMユーティリティ(名前空間対応)。 + *

各種名前空間引数にnullが渡された場合、全ての名前空間にマッチする。 + *

各種ローカル名引数にnullが渡された場合、全てのローカル名にマッチする。 + *

ノードの持つ名前空間がnullの場合、全ての名前空間引数にマッチする。 + */ +public final class DomNsUtils { + + private static final String ERRMSG_NOELEM = + "Elem:[{0}] was not found in Elem:[{1}]"; + private static final String ERRMSG_NOATTR = + "Attr:[{0}] was not found in Elem:[{1}]"; + private static final String ERRMSG_INVATTR = + "Invalid attribute form Attr[{0}] Value[{1}]"; + + + /** + * 隠しコンストラクタ。 + */ + private DomNsUtils(){ + assert false; + throw new AssertionError(); + } + + + /** + * 名前空間とローカル名が一致するノードか判定する。 + * @param node ノード + * @param nsuri 名前空間URI + * @param localName ローカル名。 + * @return ノードの名前空間およびローカル名が一致したらtrue + */ + public static boolean hasNsLocalNameNode(Node node, + String nsuri, + String localName ){ + String nodeLocalName = node.getLocalName(); + String nodeNsUri = node.getNamespaceURI(); + + boolean needLocalCmp = + localName != null; + boolean needUriCmp = + nsuri != null && nodeNsUri != null; + + if(needLocalCmp && ! localName.equals(nodeLocalName) ) return false; + if(needUriCmp && ! nsuri.equals(nodeNsUri)) return false; + + return true; + } + + /** + * 名前空間とローカル名が一致する要素か判定する。 + * @param node ノード + * @param nsuri 名前空間URI + * @param localName ローカル名。 + * @return 名前空間およびローカル名が一致する要素であればtrue + */ + public static boolean hasNsLocalNameElem(Node node, + String nsuri, + String localName ){ + if(node.getNodeType() != Node.ELEMENT_NODE) return false; + if( ! hasNsLocalNameNode(node, nsuri, localName) ) return false; + return true; + } + + /** + * 指定された名前空間とローカル名に合致する最初の直下子要素を返す。 + * @param parent 親要素 + * @param nsuri 名前空間URI + * @param localName ローカル名 + * @return 最初の直下子要素。見つからなければnull。 + */ + public static Element pickFirstChild(Node parent, + String nsuri, + String localName ){ + Node node = parent.getFirstChild(); + while(node != null){ + if(hasNsLocalNameElem(node, nsuri, localName)){ + break; + } + node = node.getNextSibling(); + } + return (Element) node; + } + + /** + * 指定された名前空間とローカル名に合致する最初の直下子要素を返す。 + *

見つからなければ例外を投げる。 + * @param parent 親要素 + * @param nsuri 名前空間URI + * @param localName ローカル名 + * @return 最初の直下子要素。 + * @throws TogaXmlException 1つも見つからなかった + */ + public static Element getFirstChild(Element parent, + String nsuri, + String localName ) + throws TogaXmlException{ + Element elem = pickFirstChild(parent, nsuri, localName); + + if(elem == null){ + String message = MessageFormat.format(ERRMSG_NOELEM, + localName, + parent.getLocalName() ); + throw new TogaXmlException(message); + } + + return elem; + } + + /** + * 指定された名前の子要素のforeachを返す。 + * @param parent 親要素 + * @param nsuri 名前空間URI + * @param localName 子要素名 + * @return 子要素のforeach + */ + public static Iterable getEachChild(final Element parent, + final String nsuri, + final String localName ){ + Iterable result = new Iterable(){ + @Override + public Iterator iterator(){ + return new SiblingElemIterator(parent, nsuri, localName); + } + }; + return result; + } + + /** + * 要素に属性が存在するか判定する。 + * @param elem 要素 + * @param nsuri 名前空間URI + * @param localName ローカル名 + * @return 存在するならtrue + */ + public static boolean hasAttrNS(Element elem, + String nsuri, + String localName ){ + return elem.hasAttributeNS(nsuri, localName); + } + + /** + * 要素からxsd:string型属性値を読み取る。 + * @param elem 要素 + * @param nsuri 名前空間URI + * @param localName 属性名 + * @return 文字列 + * @throws TogaXmlException 属性値が見つからなかった。 + */ + public static String getStringAttrNS(Element elem, + String nsuri, + String localName ) + throws TogaXmlException{ + if( ! hasAttrNS(elem, nsuri, localName) ){ + String message = MessageFormat.format(ERRMSG_NOATTR, + localName, + elem.getLocalName() ); + throw new TogaXmlException(message); + } + + String result; + try{ + result = elem.getAttributeNS(nsuri, localName); + }catch(DOMException e){ + assert false; + throw new AssertionError(e); + } + + return result; + } + + /** + * 要素からxsd:boolean型属性値を読み取る。 + * @param elem 要素 + * @param nsuri 名前空間URI + * @param localName 属性名 + * @return 真ならtrue + * @throws TogaXmlException 属性値が見つからなかった。 + */ + public static boolean getBooleanAttrNS(Element elem, + String nsuri, + String localName ) + throws TogaXmlException{ + String value = getStringAttrNS(elem, nsuri, localName); + + boolean result; + try{ + result = DatatypeConverter.parseBoolean(value); + }catch(IllegalArgumentException e){ + String message = MessageFormat.format(ERRMSG_INVATTR, + localName, + value ); + throw new TogaXmlException(message, e); + } + + return result; + } + + /** + * 要素からxsd:integer型属性値を読み取る。 + * @param elem 要素 + * @param nsuri 名前空間URI + * @param localName 属性名 + * @return int値 + * @throws TogaXmlException 属性値が見つからなかった。 + */ + public static int getIntegerAttrNS(Element elem, + String nsuri, + String localName ) + throws TogaXmlException{ + String value = getStringAttrNS(elem, nsuri, localName); + + int result; + try{ + result = DatatypeConverter.parseInt(value); + }catch(NumberFormatException e){ + String message = MessageFormat.format(ERRMSG_INVATTR, + localName, + value ); + throw new TogaXmlException(message, e); + } + + return result; + } + + /** + * 要素からxsd:float型属性値を読み取る。 + * @param elem 要素 + * @param nsuri 名前空間URI + * @param localName 属性名 + * @return float値 + * @throws TogaXmlException 属性値が見つからなかった。 + */ + public static float getFloatAttrNS(Element elem, + String nsuri, + String localName ) + throws TogaXmlException{ + String value = getStringAttrNS(elem, nsuri, localName); + + float result; + try{ + result = DatatypeConverter.parseFloat(value); + }catch(NumberFormatException e){ + String message = MessageFormat.format(ERRMSG_INVATTR, + localName, + value ); + throw new TogaXmlException(message, e); + } + + return result; + } + +} diff --git a/src/main/java/jp/sourceforge/mikutoga/xml/SiblingElemIterator.java b/src/main/java/jp/sourceforge/mikutoga/xml/SiblingElemIterator.java new file mode 100644 index 0000000..8337298 --- /dev/null +++ b/src/main/java/jp/sourceforge/mikutoga/xml/SiblingElemIterator.java @@ -0,0 +1,126 @@ +/* + * sibling element iterator on DOM tree + * + * License : The MIT License + * Copyright(c) 2011 MikuToga Partners + */ + +package jp.sourceforge.mikutoga.xml; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * 兄弟要素間用Iterator。 + *

同じ親と名前空間とローカル名を持つ要素同士を「兄弟要素」とする。 + *

ノードの持つ名前空間がnullの場合、全ての名前空間引数にマッチする。 + *

削除操作は未サポート。 + */ +public class SiblingElemIterator implements Iterator { + + private Element next; + private final String nsuri; + private final String localName; + + + /** + * コンストラクタ。 + * @param first 最初の兄弟要素。nullだと一度もiterateしない。 + */ + public SiblingElemIterator(Element first){ + super(); + + this.next = first; + + if(this.next == null){ + this.nsuri = null; + this.localName = null; + }else{ + this.nsuri = this.next.getNamespaceURI(); + this.localName = this.next.getLocalName(); + } + + return; + } + + /** + * コンストラクタ。 + *

名前空間引数にnullが渡された場合、全ての名前空間にマッチする。 + *

ローカル名引数にnullが渡された場合、全てのローカル名にマッチする。 + * @param parent 親要素 + * @param nsuri 子要素の名前空間URI + * @param localName 子要素のローカル名 + */ + public SiblingElemIterator(Element parent, + String nsuri, + String localName ){ + super(); + + this.next = DomNsUtils.pickFirstChild(parent, nsuri, localName); + + if(this.next == null){ + this.nsuri = null; + this.localName = null; + }else{ + this.nsuri = nsuri; + this.localName = localName; + } + + return; + } + + + /** + * {@inheritDoc} + * @return {@inheritDoc} + */ + @Override + public boolean hasNext(){ + if(this.next != null) return true; + return false; + } + + /** + * {@inheritDoc} + * @return {@inheritDoc} + * @throws NoSuchElementException {@inheritDoc} + */ + @Override + public Element next() throws NoSuchElementException { + if(this.next == null) throw new NoSuchElementException(); + + Element result = this.next; + + Node sibNode = result; + do{ + sibNode = sibNode.getNextSibling(); + if(sibNode == null) break; + }while( ! matchElemName(sibNode) ); + this.next = (Element) sibNode; + + return result; + } + + /** + * 兄弟要素にふさわしい名前を持つか判定する。 + * @param node 判定対象 + * @return 兄弟にふさわしい名前を持つならtrue + */ + private boolean matchElemName(Node node){ + return DomNsUtils.hasNsLocalNameElem(node, + this.nsuri, this.localName ); + } + + /** + * {@inheritDoc} + * ※削除不可。 + * @throws UnsupportedOperationException 削除を試みたので失敗した + */ + @Override + public void remove() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + +}