Разбор Java XML-библиотеки iTunes с использованием XPath

1

Поэтому я пытаюсь создать метод, который позволяет мне вводить идентификатор дорожки, который затем возвращает имя дорожки, которое принадлежит идентификатору дорожки.

Я должен использовать XPath для анализа XML-документа в java, который, в свою очередь, будет сериализовать новую библиотеку. Образец моего XML-документа находится здесь:

<plist version="1.0">
    <dict>
        <key>Major Version</key>
        <integer>1</integer>
        <key>Minor Version</key>
        <integer>1</integer>
        <key>Date</key>
        <date>2015-03-16T15:04:23Z</date>
        <key>Application Version</key>
        <string>12.1.0.71</string>
        <key>Features</key>
        <integer>5</integer>
        <key>Show Content Ratings</key>
        <true/>
        <key>Music Folder</key>
        <string>
        file://localhost/C:/Users/Mark/Music/iTunes/iTunes%20Media/
        </string>
        <key>Library Persistent ID</key>
        <string>3B01AE08EA513C21</string>
        <key>Tracks</key>
        <dict>
            <key>646</key>
            <dict>
            <key>Track ID</key>
            <integer>646</integer>
            <key>Name</key>
            <string>Save Me</string>
            <key>Artist</key>
            <string>Avenged Sevenfold</string>
            <key>Album Artist</key>
            <string>Avenged Sevenfold</string>
            <key>Album</key>
            <string>Nightmare</string>
            <key>Genre</key>
            <string>Metal</string>
            <key>Kind</key>
            <string>MPEG audio file</string>
            <key>Size</key>
            <integer>23257166</integer>
            <key>Total Time</key>
            <integer>656535</integer>
            <key>Disc Number</key>
            <integer>1</integer>
            <key>Disc Count</key>
            <integer>1</integer>
            <key>Track Number</key>
            <integer>11</integer>
            <key>Track Count</key>
            <integer>11</integer>
            <key>Year</key>
            <integer>2010</integer>
            <key>Date Modified</key>
            <date>2012-10-21T22:07:20Z</date>
            <key>Date Added</key>
            <date>2012-10-21T22:07:20Z</date>
            <key>Bit Rate</key>
            <integer>276</integer>
            <key>Sample Rate</key>
            <integer>44100</integer>
            <key>Play Count</key>
            <integer>2</integer>
            <key>Play Date</key>
            <integer>3415934327</integer>
            <key>Play Date UTC</key>
            <date>2012-03-30T06:38:47Z</date>
            <key>Artwork Count</key>
            <integer>1</integer>
            <key>Persistent ID</key>
            <string>0000000000001389</string>
            <key>Track Type</key>
            <string>File</string>
            <key>Location</key>
            <string>
            file://localhost/C:/Users/Mark/Music/Avenged%20Sevenfold/Nightmare/11%20-%20Save%20Me.mp3
            </string>
            <key>File Folder Count</key>
            <integer>2</integer>
            <key>Library Folder Count</key>
            <integer>1</integer>
        </dict>
        <key>648</key>
        <dict>
            <key>Track ID</key>
            <integer>648</integer>
            <key>Name</key>
            <string>Welcome 2 Hell</string>
            <key>Artist</key>
            <string>Bad Meets Evil</string>
            <key>Album Artist</key>
            <string>Bad Meets Evil</string>
            <key>Composer</key>
            <string>Havoc, Magnedo7</string>
            <key>Album</key>
            <string>Hell: The Sequel (Deluxe Edition)</string>
            <key>Genre</key>
            <string>Rap</string>
            <key>Kind</key>
            <string>MPEG audio file</string>
            <key>Size</key>
            <integer>7467977</integer>
            <key>Total Time</key>
            <integer>177606</integer>
            <key>Track Number</key>
            <integer>1</integer>
            <key>Year</key>
            <integer>2011</integer>
            <key>Date Modified</key>
            <date>2012-10-21T22:07:20Z</date>
            <key>Date Added</key>
            <date>2012-10-21T22:07:20Z</date>
            <key>Bit Rate</key>
            <integer>320</integer>
            <key>Sample Rate</key>
            <integer>44100</integer>
            <key>Play Count</key>
            <integer>3</integer>
            <key>Play Date</key>
            <integer>3424485861</integer>
            <key>Play Date UTC</key>
            <date>2012-07-07T06:04:21Z</date>
            <key>Skip Count</key>
            <integer>2</integer>
            <key>Skip Date</key>
            <date>2012-11-26T14:02:44Z</date>
            <key>Artwork Count</key>
            <integer>1</integer>
            <key>Persistent ID</key>
            <string>000000000000138A</string>
            <key>Track Type</key>
            <string>File</string>
            <key>Location</key>
            <string>
            file://localhost/C:/Users/Mark/Music/Bad%20Meets%20Evil/Hell_%20The%20Sequel%20(Deluxe%20Edition)/01%20-%20Welcome%202%20Hell.mp3
            </string>
            <key>File Folder Count</key>
            <integer>2</integer>
            <key>Library Folder Count</key>
            <integer>1</integer>
        </dict>
</plist>

Теперь я довольно новичок в XPath и XML в целом и изо всех сил стараюсь перемещаться по XML файлу iTunes из-за его сложности и массивного размера.

До сих пор я думал перейти к <key>646</key> чтобы проверить идентификатор, а затем на имя дорожки <string>Save Me</string> используя "//dict/key[.="646"]/string[1]/text()".

Это дает NULL. Код, который я написал на Java до сих пор:

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

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.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

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


public class XMLparse {

    public XMLparse(){
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder;
        Document doc = null;
        try {
            builder = factory.newDocumentBuilder();
            doc = builder.parse(new File("C:\\musicLibrary.xml"));

            // Create XPathFactory object
            XPathFactory xpathFactory = XPathFactory.newInstance();

            // Create XPath object
            XPath xpath = xpathFactory.newXPath();

            int id = 646;

            String name = getTrackNameById(doc, xpath, id);
            System.out.println("Track Name with ID " + id + ": " + name);

        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
        }

    }

    public static String getTrackNameById(Document doc, XPath xpath, int id) {
        String name = null;
        try {
            XPathExpression expr = xpath.compile("//dict/integer[.="+id+"]/string[1]/text()");
            name = (String) expr.evaluate(doc, XPathConstants.STRING);
        } catch (XPathExpressionException e) {
            e.printStackTrace();
        }

        return name;
    }

}

Любая помощь будет оценена.

РЕДАКТИРОВАТЬ:

Используя предложение Матиаса Мюллера, вы получите правильный результат "Save Me" для трека 646, как и ожидалось. Однако, когда я вводим другой идентификатор дорожки, он также возвращает "Сохранить меня", что неверно.

Я понятия не имею, почему он это делает, поскольку я думал, что он вернет только имя трека ввода ID i, но он возвращает другое название трека?

ВТОРОЙ РЕДАКТИРОВАНИЕ:

-Included больше XML

ТРЕТЬЕ ИЗМЕНЕНИЕ:

Изменено выражение XPath для //dict[integer ="+id+"]/string[1]/text(), используя совет Mathias. Это прекрасно работает.

Теги:
xpath
parsing
itunes

1 ответ

1
Лучший ответ

Я не могу комментировать код Java, но я могу объяснить вам выражение XPath, которое вы должны использовать. Предполагая, что введенный образец, который вы показали, применяя

//dict[key='646']/dict/key[. = 'Name']/following-sibling::*[1]

вернется

<string>Save Me</string>

который является тем элементом, который вы искали. Чтобы выбрать только текст, используйте

//dict[key='646']/dict/key[. = 'Name']/following-sibling::*[1]/text()

и результат будет

Save Me

Выражение пути работает следующим образом:

//dict                    select 'dict' elements anywhere in the document
[key='646']               but only if they have an immediate child 'key' whose text
                          content is equal to "646"
/dict                     select their child elements called 'dict'
/key[. = 'Name']          of those 'dict' elements select their child elements 'key',
                          but only if their text content is equal to "Name"
/following-sibling::*[1]  of those 'key' elements, select the first following sibling
                          element
/text()                   and select its text content

Ваше исходное выражение, опираясь на позицию string элемента, также работает с незначительными изменениями:

//dict[key ="646"]/dict/string[1]/text()
  • 0
    Ваше решение сработало частично, очень хорошо объяснено, но когда я ищу другие идентификаторы треков, оно все равно возвращает название трека как «Save Me», когда это не должно. У Вас есть какие-то предложения?
  • 0
    @ user3068854 конечно, но вам нужно будет показать больше входного документа. Образец, который содержит более одной дорожки. Я предполагаю, что вы не жестко закодировали значение идентификатора в выражении?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню