2016-06-13 5 views
0

xml文字列のすべてのノード名、ノード値、および属性を読み取るxpath式を作成する際に助けが必要です。私はこれを作った:Java、XPathすべてのノード名、ノード値、および属性を読み取る式

private List<String> listOne = new ArrayList<String>(); 
private List<String> listTwo = new ArrayList<String>(); 

public void read(String xml) { 
    try { 
     // Turn String into a Document 
     Document document = DocumentBuilderFactory.newInstance() 
       .newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes())); 

     // Setup XPath to retrieve all tags and values 
     XPath xPath = XPathFactory.newInstance().newXPath(); 
     NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']", document, XPathConstants.NODESET); 

     // Iterate through nodes 
     for(int i = 0; i < nodeList.getLength(); i++) { 
      Node node = nodeList.item(i); 
      listOne.add(node.getNodeName()); 
      listTwo.add(node.getNodeValue()); 
      // Another list to hold attributes 
     } 

    } catch(Exception e) { 
     LogHandle.info(e.getMessage()); 
    } 
} 

私は式//text()[normalize-space()='']をオンラインで見つけました。ただし、動作しません。ノード名をlistOneから取得しようとすると、ちょうど#textになります。私は//を試しましたが、それはどちらもうまくいきません。私が持っていた場合は、このXML:

<Data xmlns="Somenamespace.nsc"> 
    <Test>blah</Test> 
    <Foo>bar</Foo> 
    <Date id="2">12242016</Date> 
    <Phone> 
     <Home>5555555555</Home> 
     <Mobile>5555556789</Mobile> 
    </Phone> 
</Data> 

listOne[0]Dataを保持する必要がありますlistOne[1]Testを保持する必要がありますlistTwo[1]blahなどを保持する必要があり、...すべての属性は、別の並列リストに保存されます。

xPathはどのような式を評価する必要がありますか?

注:XML文字列には異なるタグを使用できるため、何もハードコードできません。

更新:このループを試しましたが:

NodeList nodeList = (NodeList) xPath.evaluate("//*", document, XPathConstants.NODESET); 

// Iterate through nodes 
for(int i = 0; i < nodeList.getLength(); i++) { 
    Node node = nodeList.item(i); 

    listOne.add(i, node.getNodeName()); 

    // If null then must be text node 
    if(node.getChildNodes() == null) 
     listTwo.add(i, node.getTextContent()); 
} 

しかし、これが唯一のルート要素Dataを取得し、その後、ちょうど停止します。

+1

です。「text()」は要素の内容を参照しています。 XMLの例では、「blah」、「bar」、および「12242016」はテキストノードです。したがって、 'text()'はおそらくあなたが望むものではありません。 – VGR

+0

ありがとう! 'text()'が要素の内容を与えるなら、 'node()'はノードを与えますか? – syy

+1

私はいくつかの明確化が必要かもしれないと思います。 XMLでは、「ノード」は、テキスト、コメント、処理命令などを含むXML文書内のすべての可能な情報を指し、「要素」は、開始タグと一致する終了タグのいずれかからなる情報を指すか、または単一の自己閉鎖タグ( '')。あなたは本当にすべてのノード、あるいはすべての要素とその属性を読みたいのですか? – VGR

答えて

1

はすべての要素ノードを選択します。すべての属性ノードは//@*です。しかし、要素ノードはDOMに意味のあるノード値を持たないため、getNodeValueの代わりにgetTextContent()を読み出す必要があります。

あなたは私はあなたがすべての子要素があるかどうかを確認する必要があると思う「ヌル」値持つように子要素を持つ要素を考慮するように見えるとして:サンプル入力

<Data xmlns="Somenamespace.nsc"> 
    <Test>blah</Test> 
    <Foo>bar</Foo> 
    <Date id="2">12242016</Date> 
    <Phone> 
     <Home>5555555555</Home> 
     <Mobile>5555556789</Mobile> 
    </Phone> 
</Data> 
について

DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); 
    docBuilderFactory.setNamespaceAware(true); 

    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); 

    Document doc = docBuilder.parse("sampleInput1.xml"); 

    XPathFactory fact = XPathFactory.newInstance(); 
    XPath xpath = fact.newXPath(); 

    NodeList allElements = (NodeList)xpath.evaluate("//*", doc, XPathConstants.NODESET); 

    ArrayList<String> elementNames = new ArrayList<>(); 
    ArrayList<String> elementValues = new ArrayList<>(); 

    for (int i = 0; i < allElements.getLength(); i++) 
    { 
     Node currentElement = allElements.item(i); 
     elementNames.add(i, currentElement.getLocalName()); 
     elementValues.add(i, xpath.evaluate("*", currentElement, XPathConstants.NODE) != null ? null : currentElement.getTextContent()); 
    } 

    for (int i = 0; i < elementNames.size(); i++) 
    { 
     System.out.println("Name: " + elementNames.get(i) + "; value: " + (elementValues.get(i))); 
    } 

出力は

Name: Data; value: null 
Name: Test; value: blah 
Name: Foo; value: bar 
Name: Date; value: 12242016 
Name: Phone; value: null 
Name: Home; value: 5555555555 
Name: Mobile; value: 5555556789 
+0

'getTextContext()'で '// *'を行い、タグ名と値を取得できました。しかし、 'Data'のような親ノードの場合、それが返すテキストコンテンツはその子ノードからすべてです。だから 'listTwo.get(0)'は 'blah、bar、12242016'を返します。私は 'getChildNodes()'がヌルでないかどうかをチェックしてみましたが、テキストの内容を取得しませんでしたが、ループが止まりました。 listOne(0)は 'Data'、' listTwo(0) 'は' null'、 'listOne(1)'は 'Test'、' listTwo(1) 'は' blah'です。私はOPを更新します。 – syy

+1

'getChildNodes'は' NodeList'を返します。決して 'null'です。また、 ' bar'にも子ノード、テキストノードがあります。また、 '

のような混合コンテンツで何をしたいのですか?太字のです。

'?どのような結果が必要なのかをもっと慎重に説明する必要があります。 –

+0

ああ、私は今参照してください。あなたの例に関しては、私はそのようなケースを持っていません。これは厳密にOPに表示されるものに似ています(XMLの例に少し追加されています)。私は 'listOne'がすべての要素を保持し、' listTwo'がそれらに関連付けられたテキストを保持したいだけです。しかし、要素に子要素があり直接テキストがない場合、その索引では、上記のコメントの例に示すように、 'listTwo'は' null'にする必要があります。 – syy

関連する問題