Есть ли способ проследить назад по дереву XML с помощью xmllint? - PullRequest
0 голосов
/ 04 августа 2020

В настоящее время работает над проектом, использующим Bash, который анализирует файл XML. Например, если у меня есть книжный магазин. xml:

<bookstore>
    <genre name = "Childrens">
       <book>
           <author>
           <title name = "Cat in the Hat">
       </book>
    </genre/
    <genre name = "Young Adult">
       <book>
           <author>
           <title name = "Twilight">
       </book>
    </genre>
</bookstore>
...

Учитывая, что я уже могу извлечь все имена из файла xml. Теперь я пытаюсь использовать заданное и каким-то образом проследить назад и найти соответствующий и как-то сопоставить книгу с с использованием ассоциативного массива. Например:

books[$title] = $genre
books["Cat in the Hat"] = "Childrens"

Я считаю, что первым шагом является получение названия этого жанра, зная, что у меня уже есть сохранены в отдельном массиве. В конце концов, моя цель - сравнить отдельный файл xml, содержащий только названия книг, и сравнить его с книжным магазином. xml. Когда я запускаю программу и сравниваю ее с книжным магазином. xml, программа все время считывает входной файл и возвращает жанр для каждого заголовка. Для другой справки, вот как я могу извлечь заголовки из данного книжного магазина. xml файл и что я пытаюсь выполнить sh.

TITLES=$(echo 'cat //title/@name' | xmllint --shell $filename | sed -n 's: name=\"\(.*\)\":\1:p') 

for title in $TITLES; do
      BOOKS[$title]="[this will be its respective genre somehow]"
done

В конце, если я введу файл xml только с заголовками и сравню его с книжным магазином. xml, результат должен выглядеть примерно так:

Title: Cat in the Hat Genre: Children's
Title: Twilight Genre: Young Adult

Пожалуйста, помогите с этим и дайте мне знать, если необходимы дальнейшие разъяснения! Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 04 августа 2020

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

titles=$(xmllint --xpath //genre/book/title/@name  file.xml)

и

names=$(xmllint --xpath //genre/@name  file.xml)

Если вместо этого вы можете использовать xmlstarlet, это проще, и вам не нужно использовать переменные:

xmlstarlet select -T -t -m //genre -v " concat('Title: ',book/title/@name, ' ','Genre: ',@name)" -n file.xml
0 голосов
/ 04 августа 2020

Если вы хотите просто go просмотреть файл как бы «снизу вверх», было бы неплохо просто прочитать его с конца. Я написал быстрый пример (с заведомо ужасной средой выполнения), который должен делать то, что вы хотите, при условии, что ваши файлы не слишком большие:

for (( idx=0; idx<${#TITLES[@]}; idx++ )); do
    flag=0

    tac $filename | while IFS= read line; do
        # found the entry, go up until we find the genre
        if [[ $line  == *"${TITLES[$idx]}"* ]]; then
            flag=1
        fi

        if [[ $flag == 1 ]] && [[ $line == *"<genre"* ]]; then
            # trim the line so that it only contains the quoted material:
            genre=${line#*\"}
            genre=${genre%*\">}

            title=${TITLES[$idx]}
            BOOKS[$title] = $genre
            break
        fi
    done
done

Если у вас нет ta c, вы можете использовать это вместо этого (оба примера были взяты из этого сообщения на https://www.unix.com):

perl -e 'print reverse <>' $filename | while IFS= read line; do
    # rest of code in here
done
...