295 votes

Comment lire le XML à l'aide de XPath en Java

Je veux lire des données XML en utilisant XPath en Java. D'après les informations que j'ai recueillies, je ne suis pas en mesure d'analyser le XML conformément à mes exigences.

voici ce que je veux faire :

Obtenir un fichier XML en ligne via son URL, puis utiliser XPath pour l'analyser, je veux créer deux méthodes dans ce fichier. La première est celle dans laquelle j'entre un identifiant d'attribut de nœud spécifique, et j'obtiens tous les nœuds enfants comme résultat, et la seconde est celle dans laquelle je veux juste obtenir la valeur d'un nœud enfant spécifique uniquement.

<?xml version="1.0"?>
<howto>
  <topic name="Java">
      <url>http://www.rgagnonjavahowto.htm</url>
  <car>taxi</car>
  </topic>
  <topic name="PowerBuilder">
       <url>http://www.rgagnon/pbhowto.htm</url>
       <url>http://www.rgagnon/pbhowtonew.htm</url>
  </topic>
  <topic name="Javascript">
        <url>http://www.rgagnon/jshowto.htm</url>
  </topic>
 <topic name="VBScript">
       <url>http://www.rgagnon/vbshowto.htm</url>
 </topic>
 </howto>

Dans l'exemple ci-dessus, je veux lire tous les éléments si je recherche via @name et aussi une fonction dans laquelle je veux juste que l'url de @name 'Javascript' renvoie seulement un élément de noeud.

2 votes

Ce site lien donnera une démonstration claire de la lecture d'un fichier xml à l'aide de xpath.

2voto

jschnasse Points 1907

Cela vous montre comment

  1. Lire un fichier XML dans un DOM
  2. Filtrer un ensemble de Nodes avec XPath
  3. Effectuer une certaine action sur chacun des extraits Nodes .

Nous appellerons le code avec l'instruction suivante

processFilteredXml(xmlIn, xpathExpr,(node) -> {/*Do something...*/;});

Dans notre cas, nous voulons imprimer des creatorNames d'un book.xml en utilisant "//book/creators/creator/creatorName" comme xpath pour effectuer un printNode sur chaque nœud qui correspond à l'action XPath .

Code complet

@Test
public void printXml() {
    try (InputStream in = readFile("book.xml")) {
        processFilteredXml(in, "//book/creators/creator/creatorName", (node) -> {
            printNode(node, System.out);
        });
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

private InputStream readFile(String yourSampleFile) {
    return Thread.currentThread().getContextClassLoader().getResourceAsStream(yourSampleFile);
}

private void processFilteredXml(InputStream in, String xpath, Consumer<Node> process) {
    Document doc = readXml(in);
    NodeList list = filterNodesByXPath(doc, xpath);
    for (int i = 0; i < list.getLength(); i++) {
        Node node = list.item(i);
        process.accept(node);
    }
}

public Document readXml(InputStream xmlin) {
    try {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        return db.parse(xmlin);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

private NodeList filterNodesByXPath(Document doc, String xpathExpr) {
    try {
        XPathFactory xPathFactory = XPathFactory.newInstance();
        XPath xpath = xPathFactory.newXPath();
        XPathExpression expr = xpath.compile(xpathExpr);
        Object eval = expr.evaluate(doc, XPathConstants.NODESET);
        return (NodeList) eval;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

private void printNode(Node node, PrintStream out) {
    try {
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
        StreamResult result = new StreamResult(new StringWriter());
        DOMSource source = new DOMSource(node);
        transformer.transform(source, result);
        String xmlString = result.getWriter().toString();
        out.println(xmlString);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Imprimés

<creatorName>Fosmire, Michael</creatorName>

<creatorName>Wertz, Ruth</creatorName>

<creatorName>Purzer, Senay</creatorName>

Pour book.xml

<book>
  <creators>
    <creator>
      <creatorName>Fosmire, Michael</creatorName>
      <givenName>Michael</givenName>
      <familyName>Fosmire</familyName>
    </creator>
    <creator>
      <creatorName>Wertz, Ruth</creatorName>
      <givenName>Ruth</givenName>
      <familyName>Wertz</familyName>
    </creator>
    <creator>
      <creatorName>Purzer, Senay</creatorName>
       <givenName>Senay</givenName>
       <familyName>Purzer</familyName>
    </creator>
  </creators>
  <titles>
    <title>Critical Engineering Literacy Test (CELT)</title>
  </titles>
</book>

1voto

Yash Points 4565

Lire un fichier XML en utilisant XPathFactory, SAXParserFactory et StAX (JSR-173) .

En utilisant XPath, obtenez un nœud et ses données enfant.

public static void main(String[] args) {
    String xml = "<soapenv:Body xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'>"
            + "<Yash:Data xmlns:Yash='http://Yash.stackoverflow.com/Services/Yash'>"
            + "<Yash:Tags>Java</Yash:Tags><Yash:Tags>Javascript</Yash:Tags><Yash:Tags>Selenium</Yash:Tags>"
            + "<Yash:Top>javascript</Yash:Top><Yash:User>Yash-777</Yash:User>"
            + "</Yash:Data></soapenv:Body>";
    String jsonNameSpaces = "{'soapenv':'http://schemas.xmlsoap.org/soap/envelope/',"
            + "'Yash':'http://Yash.stackoverflow.com/Services/Yash'}";
    String xpathExpression = "//Yash:Data";

    Document doc1 = getDocument(false, "fileName", xml);
    getNodesFromXpath(doc1, xpathExpression, jsonNameSpaces);
    System.out.println("\n===== ***** =====");
    Document doc2 = getDocument(true, "./books.xml", xml);
    getNodesFromXpath(doc2, "//person", "{}");
}
static Document getDocument( boolean isFileName, String fileName, String xml ) {
    Document doc = null;
    try {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating(false);
        factory.setNamespaceAware(true);
        factory.setIgnoringComments(true);
        factory.setIgnoringElementContentWhitespace(true);

        DocumentBuilder builder = factory.newDocumentBuilder();
        if( isFileName ) {
            File file = new File( fileName );
            FileInputStream stream = new FileInputStream( file );
            doc = builder.parse( stream );
        } else {
            doc = builder.parse( string2Source( xml ) );
        }
    } catch (SAXException | IOException e) {
        e.printStackTrace();
    } catch (ParserConfigurationException e) {
        e.printStackTrace();
    }
    return doc;
}

/**
 * ELEMENT_NODE[1],ATTRIBUTE_NODE[2],TEXT_NODE[3],CDATA_SECTION_NODE[4],
 * ENTITY_REFERENCE_NODE[5],ENTITY_NODE[6],PROCESSING_INSTRUCTION_NODE[7],
 * COMMENT_NODE[8],DOCUMENT_NODE[9],DOCUMENT_TYPE_NODE[10],DOCUMENT_FRAGMENT_NODE[11],NOTATION_NODE[12]
 */
public static void getNodesFromXpath( Document doc, String xpathExpression, String jsonNameSpaces ) {
    try {
        XPathFactory xpf = XPathFactory.newInstance();
        XPath xpath = xpf.newXPath();

        JSONObject namespaces = getJSONObjectNameSpaces(jsonNameSpaces);
        if ( namespaces.size() > 0 ) {
            NamespaceContextImpl nsContext = new NamespaceContextImpl();

            Iterator<?> key = namespaces.keySet().iterator();
            while (key.hasNext()) { // Apache WebServices Common Utilities
                String pPrefix = key.next().toString();
                String pURI = namespaces.get(pPrefix).toString();
                nsContext.startPrefixMapping(pPrefix, pURI);
            }
            xpath.setNamespaceContext(nsContext );
        }

        XPathExpression compile = xpath.compile(xpathExpression);
        NodeList nodeList = (NodeList) compile.evaluate(doc, XPathConstants.NODESET);
        displayNodeList(nodeList);
    } catch (XPathExpressionException e) {
        e.printStackTrace();
    }
}

static void displayNodeList( NodeList nodeList ) {
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node node = nodeList.item(i);
        String NodeName = node.getNodeName();

        NodeList childNodes = node.getChildNodes();
        if ( childNodes.getLength() > 1 ) {
            for (int j = 0; j < childNodes.getLength(); j++) {

                Node child = childNodes.item(j);
                short nodeType = child.getNodeType();
                if ( nodeType == 1 ) {
                    System.out.format( "\n\t Node Name:[%s], Text[%s] ", child.getNodeName(), child.getTextContent() );
                }
            }
        } else {
            System.out.format( "\n Node Name:[%s], Text[%s] ", NodeName, node.getTextContent() );
        }

    }
}
static InputSource string2Source( String str ) {
    InputSource inputSource = new InputSource( new StringReader( str ) );
    return inputSource;
}
static JSONObject getJSONObjectNameSpaces( String jsonNameSpaces ) {
    if(jsonNameSpaces.indexOf("'") > -1)    jsonNameSpaces = jsonNameSpaces.replace("'", "\"");
    JSONParser parser = new JSONParser();
    JSONObject namespaces = null;
    try {
        namespaces = (JSONObject) parser.parse(jsonNameSpaces);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return namespaces;
}

Document XML

<?xml version="1.0" encoding="UTF-8"?>
<book>
<person>
  <first>Yash</first>
  <last>M</last>
  <age>22</age>
</person>
<person>
  <first>Bill</first>
  <last>Gates</last>
  <age>46</age>
</person>
<person>
  <first>Steve</first>
  <last>Jobs</last>
  <age>40</age>
</person>
</book>

Sortie pour l'expression XPathExpression donnée :

String xpathExpression = "//person/first";
/*OutPut:
 Node Name:[first], Text[Yash] 
 Node Name:[first], Text[Bill] 
 Node Name:[first], Text[Steve] */

String xpathExpression = "//person";
/*OutPut:
     Node Name:[first], Text[Yash] 
     Node Name:[last], Text[M] 
     Node Name:[age], Text[22] 
     Node Name:[first], Text[Bill] 
     Node Name:[last], Text[Gates] 
     Node Name:[age], Text[46] 
     Node Name:[first], Text[Steve] 
     Node Name:[last], Text[Jobs] 
     Node Name:[age], Text[40] */

String xpathExpression = "//Yash:Data";
/*OutPut:
     Node Name:[Yash:Tags], Text[Java] 
     Node Name:[Yash:Tags], Text[Javascript] 
     Node Name:[Yash:Tags], Text[Selenium] 
     Node Name:[Yash:Top], Text[javascript] 
     Node Name:[Yash:User], Text[Yash-777] */

Voir ce lien pour notre propre mise en œuvre de NamespaceContext

0voto

En complément de l'excellente réponse de @bluish et @Yishai, voici comment faire en sorte que les NodeLists et les attributs de nœuds prennent en charge les itérateurs, c'est-à-dire que la fonction for(Node n: nodelist) interface.

Utilise-le comme ça :

NodeList nl = ...
for(Node n : XmlUtil.asList(nl))
{...}

et

Node n = ...
for(Node attr : XmlUtil.asList(n.getAttributes())
{...}

Le code :

/**
 * Converts NodeList to an iterable construct.
 * From: https://stackoverflow.com/a/19591302/779521
 */
public final class XmlUtil {
    private XmlUtil() {}

    public static List<Node> asList(NodeList n) {
        return n.getLength() == 0 ? Collections.<Node>emptyList() : new NodeListWrapper(n);
    }

    static final class NodeListWrapper extends AbstractList<Node> implements RandomAccess {
        private final NodeList list;

        NodeListWrapper(NodeList l) {
            this.list = l;
        }

        public Node get(int index) {
            return this.list.item(index);
        }

        public int size() {
            return this.list.getLength();
        }
    }

    public static List<Node> asList(NamedNodeMap n) {
        return n.getLength() == 0 ? Collections.<Node>emptyList() : new NodeMapWrapper(n);
    }

    static final class NodeMapWrapper extends AbstractList<Node> implements RandomAccess {
        private final NamedNodeMap list;

        NodeMapWrapper(NamedNodeMap l) {
            this.list = l;
        }

        public Node get(int index) {
            return this.list.item(index);
        }

        public int size() {
            return this.list.getLength();
        }
    }
}

0voto

Dele Taylor Points 101

Vous pouvez combiner XPath et les expressions régulières en utilisant ma cadre de migration des données -- Data Pipeline .

Voici des exemples d'utilisation de XPath pour lire des enregistrements XML, JSON et Java Beans.

Analyser JSON à partir d'une source en ligne en utilisant XPath

Analyser les beans Java à l'aide de XPath

Analyser le XML à l'aide de XPath

Ce qui suit extrait les enregistrements de links.xml en utilisant XPath pour identifier les champs nom et url.

DataReader reader = new XmlReader(new File("links.xml"))
    .addField("name", "//topic/@name")
    .addField("url", "//topic/url/text()")
    .addRecordBreak("//topic")
    .setExpandDuplicateFields(true);

Ensuite, il filtre/sélectionne les enregistrements dont le champ nom correspond au modèle regex. Power.* .

reader = new FilteringReader(reader)
    .add(new FieldFilter("name")
        .addRule(new PatternMatch("Power.*")));

Il écrit ensuite les enregistrements sous forme de CSV dans System.out.

CSVWriter writer = new  CSVWriter(new OutputStreamWriter(System.out));

JobTemplate.DEFAULT.transfer(reader, writer);

Voici le résultat.

name,url
PowerBuilder,http://www.rgagnon/pbhowto.htm
PowerBuilder,http://www.rgagnon/pbhowtonew.htm

Vous pouvez également travailler avec les enregistrements de manière programmatique au lieu de les écrire en CSV.

reader.open();
try {
    Record record;
    while ((record = reader.read()) != null) {
        System.out.println(record);
    }
} finally {
    reader.close();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X