Извлечение значений дочернего узла XML на основе родительского - PullRequest
0 голосов
/ 30 ноября 2018

У меня довольно большой xml, который выглядит следующим образом:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">
<tv source-info-url="http://blah blah blah.com/" source-info-name="blah.com" generator-info-name="zap2xml" generator-info-url="zap2xml@gmail.com">
                        <channel id="IX.XXXXXX.blah.com">
                                <display-name>WCBS</display-name>
                                <display-name>2 WCBS</display-name>
                                <display-name>2</display-name>
                                <icon src="https://blah blah blah.png" />
                        </channel>
                        <channel id="IX.XXXXX.blah.com">
                                <display-name>WCBSDT</display-name>
                                <display-name>2 WCBSDT</display-name>
                                <display-name>2</display-name>
                                <icon src="https://blah blah blah.png" />
                        </channel>
                        <channel id="IX.XXXXX.blah.com">
                                <display-name>WNBC</display-name>
                                <display-name>4 WNBC</display-name>
                                <display-name>4</display-name>
                                <icon src="https://blah blah blah.png" />
                        </channel>
                        .....
    </tv>

Сейчас я просто хочу пройтись по .xml, извлечь значение TAG идентификатора канала, затем извлечь первый и третий "значения тега display-name "и отображать их для каждого канала на основе этого идентификатора.

У меня есть следующее:

#!/bin/bash
file='/path/to/xml/file/file.xml'
cat $file | while read line ; do
        if [[ $line == *"<channel id="* ]]; then
        channelid=$(echo $line|awk -F'"' '{print $2}')
        channelnum=$(xmlstarlet sel -t -v "//channel[@id='$channelid']//display-name[3]" -n $file)
        callsign=$(xmlstarlet sel -t -v "//channel[@id='$channelid']//display-name[1]" -n $file)
        clear
        echo "Here are the details for channel id: $channelid"
        echo ""
        echo "Channel Number is: $channelnum"
        echo "Channel Call Sign is: $callsign"
        echo ""
        sleep 2
        fi
done

, которое делает то, что я хочу, но весь процесс замедляетсяпотому что он продолжает искать ссылки на внешние объекты для каждого канала, с которым сталкивается - выдает следующее:

Here are the details for channel id: IX.XXXXX.blah.com

Channel Number is: 2
Channel Call Sign is: WCBS

/path/to/the/epg.xml:2.30: failed to load external entity "/path/to/the/script/xmltv.dtd"
<!DOCTYPE tv SYSTEM "xmltv.dtd">
                                ^
/path/to/the/xmlfile.xml:2.30: failed to load external entity "/path/to/the/script/xmltv.dtd"
<!DOCTYPE tv SYSTEM "xmltv.dtd">

Как я могу подавить эти поиски?Я просто хочу разобрать эти значения.

1 Ответ

0 голосов
/ 30 ноября 2018

Как я могу подавить эти поиски?

Сначала вы можете использовать команду xmlstarlet fo (формат) , чтобы удалить объявление DOCTYPE.

Вы также сможете получить всезначения, которые вам нужны, просто используя xmlstarlet sel (выберите) команду и XPath.Попытка отследить файл, прочитать строки и проанализировать с помощью регулярных выражений может быть хрупкой.

Полный пример ...

#!/bin/bash

file='/path/to/the/file.xml'

xmlstarlet fo -D $file | \
xmlstarlet sel -T -t -m "/tv/channel" \
    -v "concat('Here are the details for channel id: ', @id)" -nl -nl \
    -v "concat('  Channel Number is: ', display-name[3])" -nl \
    -v "concat('  Channel Call Sign is: ', display-name[1])" -nl -nl

Вывод ...

Here are the details for channel id: IX.XXXXXX.blah.com

  Channel Number is: 2
  Channel Call Sign is: WCBS

Here are the details for channel id: IX.XXXXX.blah.com

  Channel Number is: 2
  Channel Call Sign is: WCBSDT

Here are the details for channel id: IX.XXXXX.blah.com

  Channel Number is: 4
  Channel Call Sign is: WNBC
...