이름으로 XML 직계 자식 요소만 가져오기

내 질문은: 부모 요소의 <손자>와 같은 이름을 가진 다른 요소가 있을 때 특정 부모 요소 바로 아래에 있는 요소를 어떻게 가져올 수 있나요?

Java DOM 라이브러리를 사용하여 XML 요소를 구문 분석하고 있는데 문제가 발생하고 있습니다. 다음은 제가 사용하고 있는 XML의 일부(일부)입니다:

<notifications>
  <notification>
    <groups>
      <group name="zip-group.zip" zip="true">
        <file location="C:\valid\directory\" />
        <file location="C:\another\valid\file.doc" />
        <file location="C:\valid\file\here.txt" />
      </group>
    </groups>
    <file location="C:\valid\file.txt" />
    <file location="C:\valid\file.xml" />
    <file location="C:\valid\file.doc" />
  </notification>
</notifications>

보시다시피 파일 요소를 배치할 수 있는 위치에는 두 가지가 있습니다. 그룹 내부 또는 그룹 외부입니다. 저는 이 방식으로 구조화하는 것이 더 사용자 친화적이기 때문입니다.

이제 notificationElement.getElementsByTagName("file");을 호출할 때마다 그룹 요소 아래에 있는 요소를 포함하여 모든 파일 요소를 제공합니다. 저는 이러한 종류의 파일을 각각 다르게 처리하므로 이 기능은 바람직하지 않습니다.

두 가지 해결책을 생각해 봤습니다:

  1. 파일 요소의 상위 요소를 가져 와서 그에 따라 처리합니다 (알림 또는 그룹인지에 따라 다름).
  2. 혼동을 피하기 위해 두 번째 <file 요소의 이름을 바꿉니다.

이 두 가지 방법 중 어느 것도 <notification 요소의 직접 자식인 <file 요소만 가져오는 것만큼 바람직한 해결책은 없습니다.

이 작업을 수행하는 가장 좋은 방법에 대한 IMPO의 의견과 답변에 열려 있지만이 프로젝트의 나머지 부분에서 사용하고 있기 때문에 DOM 솔루션에 정말 관심이 있습니다. 고마워요.

질문에 대한 의견 (5)

내가 이 일을 해법을 찾은 것은 지난 5월 깨닫게 @kentcdodds 인도하심이라만일 상당히 유사한 문제가 있는 것으로, 이제 그냥 I& # 39, ve 생쥐라. (아마도 내 우스카스 있지만, 당신 애두요), 해법을.

예를 들어 매우 상투적이고 내 XML 형식으로 표시됨을 아래 -

<?xml version="1.0" encoding="utf-8"?>










I want, 형식을 통해 알 수 있듯이 이 스니핏을 용이하게 할 수 있는 것은 분명 문제가 있다, 그래서 내가 갖고 중첩할 n 수준 장치당 [릴레이션십] 노드입니다 노엘가제차일드노스 () 는 모든 레벨에서 노드입니다 계층 없이 모두 가져오는 거라고 어떤 종류의 힌트 '으로 노드입니다 심도입니다.

  • Apiu * 바라보는 건 물론, 당분간 다른 두 가지가 있을 수 있는 방법을 실제로 일부 사용 -
  • [노엘가제퍼스트차일드 ()] [2]
  • [노엘가제넥치블링 ()] [3]

이 두 가지 방법이 제공하는 데 필요한 모든 것, 함께 있던 모든 즉시인지 하위 요소를 노드입니다. 다음 코드 줘야 할 기본적인 개념은 상당히 jsp 구현 방법 이. 지금은 JSP. 하지만, 이제 이 붙여넣습니다 i& # 39 m, t # 39 시간은 아직 큰 콩 didn& 완전히 다른 버전의 apc® 자신의 코드를 만들 수 있습니다.

이 코드는 다음과 같은 출력물을 직접 보여 줄 것 "이라고 자식 요소로 디렉토리에만 초기 스크립트루트 노드입니다.

NODE num:-1
NODE num:-1.1
NODE num:-1.2

따라서 누군가가 희망을 겁니다. 건배 최초 게시물로의.

[2]: http://docs.oracle.com/javase/1.4.2/docs/api/org/w3c/dom/Node.html # getFirstChild% 28%29 [3]: http://docs.oracle.com/javase/1.4.2/docs/api/org/w3c/dom/Node.html # getNextSibling% 28%29

해설 (3)

이를 위해 XPath를 사용하여 두 경로를 가져와서 다르게 처리할 수 있습니다.

파일노드를 가져오려면 ``알림 노드의 직접 자식인 //알림/파일을 사용하고 /그룹 노드의 자식인 //groups/group/file을 사용하세요.

이것은 간단한 샘플입니다:

public class SO10689900 {
    public static void main(String[] args) throws Exception {
        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = db.parse(new InputSource(new StringReader("\n" + 
                "  \n" + 
                "    \n" + 
                "      \n" + 
                "        \n" + 
                "        \n" + 
                "        \n" + 
                "      \n" + 
                "    \n" + 
                "    \n" + 
                "    \n" + 
                "    \n" + 
                "  \n" + 
                "")));
        XPath xpath = XPathFactory.newInstance().newXPath();
        XPathExpression expr1 = xpath.compile("//notification/file");
        NodeList nodes = (NodeList)expr1.evaluate(doc, XPathConstants.NODESET);
        System.out.println("Files in //notification");
        printFiles(nodes);

        XPathExpression expr2 = xpath.compile("//groups/group/file");
        NodeList nodes2 = (NodeList)expr2.evaluate(doc, XPathConstants.NODESET);
        System.out.println("Files in //groups/group");
        printFiles(nodes2);
    }

    public static void printFiles(NodeList nodes) {
        for (int i = 0; i < nodes.getLength(); ++i) {
            Node file = nodes.item(i);
            System.out.println(file.getAttributes().getNamedItem("location"));
        }
    }
}

출력되어야 합니다:

Files in //notification
location="C:\valid\file.txt"
location="C:\valid\file.xml"
location="C:\valid\file.doc"
Files in //groups/group
location="C:\valid\directory\"
location="C:\this\file\doesn't\exist.grr"
location="C:\valid\file\here.txt"
해설 (4)
해결책

글쎄요, 이 질문에 대한 DOM 솔루션은 너무 우아하지는 않지만 실제로는 매우 간단합니다. notificationElement.getElementsByTagName("file");을 호출할 때 반환되는 filesNodeList를 반복할 때 부모 노드의 이름이 알림인지 확인하고 그렇지 않은 경우 그룹 요소에서 처리하므로 무시합니다. 제 코드 솔루션은 다음과 같습니다:

for (int j = 0; j < filesNodeList.getLength(); j++) {
  Element fileElement = (Element) filesNodeList.item(j);
  if (!fileElement.getParentNode().getNodeName().equals("notification")) {
    continue;
  }
  ...
}
해설 (6)

DOM API를 고수하는 경우

NodeList nodeList = doc.getElementsByTagName("notification")
    .item(0).getChildNodes();

// get the immediate child (1st generation)
for (int i = 0; i < nodeList.getLength(); i++)
    switch (nodeList.item(i).getNodeType()) {
        case Node.ELEMENT_NODE:

            Element element = (Element) nodeList.item(i);
            System.out.println("element name: " + element.getNodeName());
            // check the element name
            if (element.getNodeName().equalsIgnoreCase("file"))
            {

                // do something with you "file" element (child first generation)

                System.out.println("element name: "
                    + element.getNodeName() + " attribute: "
                    + element.getAttribute("location"));

            }
    break;

}

첫 번째 작업은 요소(이 경우 첫 번째 -아이템 (0)-)와 그 모든 자식을 가져오는 것입니다:

NodeList nodeList = doc.getElementsByTagName("notification")
    .item(0).getChildNodes();

(나중에 모든 요소 가져오기를 사용하여 모든 요소로 작업할 수 있습니다).

알림의 모든 자식에 대해:

for (int i = 0; i < nodeList.getLength(); i++)

의 모든 자식에 대해 먼저 그 유형을 가져와서 엘리먼트인지 확인합니다:

switch (nodeList.item(i).getNodeType()) {
    case Node.ELEMENT_NODE:
        //.......
        break;  
}

만약 그렇다면, 그랜드 자식인 '알림'이 아닌 자식인 '파일'이 있는 것입니다;

을 클릭하고 확인할 수 있습니다:

if (element.getNodeName().equalsIgnoreCase("file"))
{

    // do something with you "file" element (child first generation)

    System.out.println("element name:"
        + element.getNodeName() + " attribute: "
        + element.getAttribute("location"));

}

옵션은 다음과 같습니다:

element name: file
element name:file attribute: C:\valid\file.txt
element name: file
element name:file attribute: C:\valid\file.xml
element name: file
element name:file attribute: C:\valid\file.doc
해설 (3)

난 내 프로젝트 중 하나로 경식도 동일한 문제가 좀 있는 한, ',' List&lt 및 작성했습니까 함수은 반환되므로 Element&gt redboot*용 즉시인지 만 명의 자녀를 두고 있다. 기본적으로 각 노드에 대한 검사를 통해 'it' s # 39, 실제로 노드입니다 발렌티노데 it& 반환되었습니다 게테레멘츠비타냐메 경우 우리는 검색: 차일즈 다음과 같다.

public static List getDirectChildsByTag(Element el, String sTagName) {
        NodeList allChilds = el.getElementsByTagName(sTagName);
        List res = new ArrayList();

        for (int i = 0; i < allChilds.getLength(); i++) {
            if (allChilds.item(i).getParentNode().equals(el))
                res.add((Element) allChilds.item(i));
        }

        return res;
    }

이 경우 (예를 들면 손자) 에 의해 잘못된 결과를 수락됨 오토메이티드 켄트크도데스 반환되므로 힐데노데 &quot 불렀으매 notification"; 돌아갈 때, 즉 손자 요소점 &quot group&quot. 있을 이름을 notification&quot ";). 난 내 프로젝트가 진행되고 있는 상황을 평면가공 내가 왜 내 함수은 지었지.

해설 (0)

난 그냥 어디서) 에서 관련 문제를 처리하는 데 필요한 경우에도 즉시 치료를 자식 노드가 모든 &quot file"; 노드입니다 비슷하다. # 39 의 상위 노드입니다 Element& 비교, 난 내 솔루션을 통해 처리되는 요소는 노드로서 여부를 밝혀내기 위해 즉시 아기 "라고 말했다.

NodeList fileNodes = parentNode.getElementsByTagName("file");
for(int i = 0; i < fileNodes.getLength(); i++){
            if(parentNode.equals(fileNodes.item(i).getParentNode())){
                if (fileNodes.item(i).getNodeType() == Node.ELEMENT_NODE) {

                    //process the child node...
                }
            }
        }
해설 (0)

There is a nice LINQ 해결책:

For Each child As XmlElement In From cn As XmlNode In xe.ChildNodes Where cn.Name = "file"
    ...
Next
해설 (0)

내가 이 기능을 작성했습니까 내려받습니다 노드입니다 의해 값이 타냐메, 최상위 수준으로 제한할 수 있습니다.


public static String getValue(Element item, String tagToGet, String parentTagName) {
    NodeList n = item.getElementsByTagName(tagToGet);
    Node nodeToGet = null;
    for (int i = 0; i
해설 (0)