web-dev-qa-db-ja.com

NamedNodeMapの一般的なforeach反復

Javaでは、 NamedNodeMap インターフェースを見て、ジェネリックスでどのように反復しますか? StringではなくNodeを使用しているようですが、Nodeオブジェクト...

NamedNodeMap namedNodeMap = doc.getAttributes();
Map<String, String> stringMap = (Map<String, String>) namedNodeMap;
for (Map.Entry<String, String> entry : stringMap.entrySet()) {
  //key,value stuff here
}

はい、ジェネリックを使用せず、通常のforループを使用して反復する方法を確認できますが、上記のイディオムを使用したいですか?地図用。もちろん、問題は、名前にもかかわらず、NamedNodeMapが実際にはMapインターフェイスを実装していないことであるように思われます。 :(

ここで弾丸を噛んで、次のようなことをしなければならないと思います。

/*
 * Iterates through the node attribute map, else we need to specify specific 
 * attribute values to pull and they could be of an unknown type
 */
private void iterate(NamedNodeMap attributesList) {
    for (int j = 0; j < attributesList.getLength(); j++) {
        System.out.println("Attribute: "
                + attributesList.item(j).getNodeName() + " = "
                + attributesList.item(j).getNodeValue());
    }
}

これ以上良いものはありませんか?

22
Thufir

これらのAPIを使用するためのより良い方法はないと思います。 (更新:OK-多分 https://stackoverflow.com/a/28626556/139985 ニースとしてカウントされます。)

W3C DOM Java APIはJavaがジェネリックまたは新しいfor構文、さらにはIteratorinterface。JavaのW3CDOM APIは、実際にはIDL仕様をJavaにマッピングした結果であることに注意してください。

メモリ内のXMLなどを操作するためのより優れたAPIが必要な場合は、JDOMを検討する必要があります。

7
Stephen C

Iterable用に独自のNamedNodeMapラッパーを作成し、それをforeachループで使用できます。

たとえば、これは単純な実装である可能性があります。

public final class NamedNodeMapIterable implements Iterable<Node> {

    private final NamedNodeMap namedNodeMap;

    private NamedNodeMapIterable(NamedNodeMap namedNodeMap) {
        this.namedNodeMap = namedNodeMap;
    }

    public static NamedNodeMapIterable of(NamedNodeMap namedNodeMap) {
        return new NamedNodeMapIterable(namedNodeMap);
    }

    private class NamedNodeMapIterator implements Iterator<Node> {

        private int nextIndex = 0;

        @Override
        public boolean hasNext() {
            return (namedNodeMap.getLength() > nextIndex);
        }
        @Override
        public Node next() {
            Node item = namedNodeMap.item(nextIndex);
            nextIndex = nextIndex + 1;
            return item;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

    }

    @Override
    public Iterator<Node> iterator() {
        return new NamedNodeMapIterator();
    }
}

この場合、これは使用法になります。

private void iterate(NamedNodeMap attributesList) {
    for (Node node : NamedNodeMapIterable.of(attributesList)) {
        System.out.println("Attribute: "
                + node.getNodeName() + " = " + node.getNodeValue());
    }
}

同様のアプローチで、Map.Entry<String, String>インスタンス上にIterableを作成できます。

9
Paolo Fulgoni

NamedNodeMapMap にキャストできないため、次のような古典的なforループを使用してループすることをお勧めします。

int numAttrs = namedNodeMap.getLength();
System.out.println("Attributes:");
for (int i = 0; i < numAttrs; i++){
   Attr attr = (Attr) pParameterNode.getAttributes().item(i);
   String attrName = attr.getNodeName();
   String attrValue = attr.getNodeValue();
   System.out.println("\t[" + attrName + "]=" + attrValue);
}
4
Charles Follet

Java 8ソリューションから:

private static Iterable<Node> iterableNamedNodeMap(final NamedNodeMap namedNodeMap) {
    return () -> new Iterator<Node>() {

        private int index = 0;

        @Override
        public boolean hasNext() {
            return index < namedNodeMap.getLength();
        }

        @Override
        public Node next() {
            if (!hasNext())
                throw new NoSuchElementException();
            return namedNodeMap.item(index++);
        }
    };
}
0
Michel