4

次のXML(basic.xml)があるとします。

<rdr>
  <details>
    <detail>
        <name>version</name>
        <value>15.0</value>
    </detail>
    <detail>
        <name>resolution</name>
        <value>1080X1920</value>
    </detail>
  </details>
</rdr>

名前とバージョンを出したいので、次のコードがあります。これはあまり整頓されていませんが、説明のためにこれを作成しましたが、コードは完全に機能します。

import java.io.FileInputStream;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Example {

    private static XPath factoryXpath = null;

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
        FileInputStream fin = new FileInputStream("basic.xml");
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(fin);

        XPathFactory xPathFactory = XPathFactory.newInstance();
        factoryXpath = xPathFactory.newXPath();

        printDetails(document);
    }

    public static void printDetails(Node node) throws XPathExpressionException {
        NodeList nodes = (NodeList) factoryXpath.evaluate("//detail", node, XPathConstants.NODESET);

        printNameAndValue(nodes.item(0));
        printNameAndValue(nodes.item(1));

    }

    public static void printNameAndValue(Node node) throws XPathExpressionException {
        System.out.println("Name=" + (String) factoryXpath.evaluate("//name", node, XPathConstants.STRING));
        System.out.println("Value=" + (String) factoryXpath.evaluate("//value", node, XPathConstants.STRING));
    }

}

これにより、次のように出力されます。

Name=version
Value=15.0
Name=version
Value=15.0

なぜ同じ名前と値を両方とも出力するのですか?

最初にノードのクローンを作成すると、printNameAndValueは次のようになります。

public static void printNameAndValue(Node node) throws XPathExpressionException {
    Node clonedNode = node.cloneNode(true);
    System.out.println("Name=" + (String) factoryXpath.evaluate("//name", clonedNode, XPathConstants.STRING));
    System.out.println("Value=" + (String) factoryXpath.evaluate("//value", clonedNode, XPathConstants.STRING));
}

次の出力が得られます。

Name=version
Value=15.0
Name=resolution
Value=1080X1920

複製されたノードの動作が異なるのはなぜですか?

複製されたノードを削除し、元の例に戻しましたが、ここで説明されているメソッドhttps://stackoverflow.com/a/2325407/211560を追加しましたが、属性にドキュメントではなくノードを使用しています。これにより、次の結果が出力されます。

<?xml version="1.0" encoding="UTF-8"?><detail>
        <name>version</name>
        <value>15.0</value>
    </detail>
Name=version
Value=15.0
<?xml version="1.0" encoding="UTF-8"?><detail>
        <name>resolution</name>
        <value>1080X1920</value>
    </detail>
Name=version
Value=15.0

このことから、ノードが私たちが期待するものであることは明らかです。ただし、XPathを最初のノード、または元のドキュメントに適用しています。ノードのクローンを作成してそれを使用しても問題ありませんが、なぜこれが発生しているのかを知りたいのです。

4

1 に答える 1

3

XPath式//name絶対パス(で始まる)であるため、コンテキストノードが属するドキュメント内の/すべての要素を含むノードセットを選択します。nameしたがって、XPath 1.0データモデルに従ってその式を文字列として評価すると、ドキュメント順に最初のそのようなノードの文字列値が得られます。

その最初の文の重要な部分は「コンテキストノードが属するドキュメント」です。複製されたノードはドキュメントにアタッチされていないため、XPathエバリュエーターはノード自体をドキュメントフラグメントのルートとして扱い、それに対して式を評価します。元のドキュメント(2つ含まれている)に対してではなく、フラグメント(1つのname要素のみが含まれている)。

printNameAndValue代わりに相対XPath式を使用した場合

public static void printNameAndValue(Node node) throws XPathExpressionException {
    System.out.println("Name=" + (String) factoryXpath.evaluate("name", node, XPathConstants.STRING));
    System.out.println("Value=" + (String) factoryXpath.evaluate("value", node, XPathConstants.STRING));
}

(または.//namename要素が直接の子ではなく孫またはより深い子である可能性がある場合)、期待する出力、つまり指定されたの最初のname(それぞれvalue)要素の子の値を取得する必要がありますnode

于 2012-12-18T11:51:15.933 に答える