Заменить динамический контент в файле XML

15

Краткая сводка: Мне нужно создать скрипт Bash для автоматической смены текста в узле каждую неделю. Сценарий будет соответствовать узлу и заменить текст внутри них (если это возможно)? Как мне это сделать?

Длинное резюме: У меня есть сервер Minecraft, в котором есть магазины, каждый из которых имеет свой собственный .xml-файл в каталоге / ShowcaseStandalone / ffs-storage /. Каждое воскресенье мой сервер перезапускает и выполняет несколько команд в терминале для сброса нескольких вещей. Одна вещь, которую я пытаюсь сделать, - это один из магазинов. Я хочу изменить текст в узле & lt; itemstack & gt; и текст в узле & lt; цена & gt ;. Я просто хочу взять текст из .txt-файла в другой папке и вставить его в этот узел. Проблема в том, что текст в узле будет меняться каждую неделю. Есть ли способ заменить определенную строку или текст в двух узлах с помощью bash?

XML-файл:

<?xml version="1.0" encoding="UTF-8"?>
<scs-shop usid="cac8480951254352116d5255e795006252d404d9" version="2" type="storage">
    <enchantments type="string"/>
    <owner type="string">Chadward27</owner>
    <world type="string">Frisnuk</world>
    <itemStack type="string">329:0</itemStack>
    <activity type="string">BUY</activity>
    <price type="double">55.0</price>
    <locX type="double">487.5</locX>
    <locY type="double">179.0</locY>
    <locZ type="double">-1084.5</locZ>
    <amount type="integer">0</amount>
    <maxAmount type="integer">0</maxAmount>
    <isUnlimited type="boolean">true</isUnlimited>
    <nbt-storage usid="23dffac5fb2ea7cfdcf0740159e881026fde4fa4" version="2" type="storage"/>
</scs-shop>

Операционная система: Linux Ubuntu 12.04

    
задан Clucky 13.11.2012 в 23:24
источник
  • Итак, вы просто хотите изменить usid из тега scs-shop? –  Gilles Quenot 13.11.2012 в 23:27
  • XML-манипуляция с использованием исключительно bash? Зачем ограничивать себя? –  Brian Cain 13.11.2012 в 23:28
  • @sputnick Извините, мне приходилось показывать объявления & lt и & gt, потому что он убил мои узлы, но нет, мне нужно заменить текст в узлах «itemstack» и «price», –  Clucky 13.11.2012 в 23:32
  • @ Брайан-Каин Есть ли другой способ сделать это с терминала? Поскольку все эти команды выполняются при выключении сервера –  Clucky 13.11.2012 в 23:33
  • Я бы порекомендовал python - на вашем сервере установлен python или он может? Если нет, java может быть другим вариантом. –  Brian Cain 13.11.2012 в 23:36
Показать остальные комментарии

3 ответа

16

Вы можете использовать xmlstarlet для редактирования файла XML в shell , например:

xmlstarlet edit -L -u "/scs-shop/price[@type='double']" -v '99.66' file.xml

Примечание

  • "/scs-shop/price[@type='double']" - выражение Xpath
  • см. xmlstarlet ed --help
ответ дан Gilles Quenot 13.11.2012 в 23:46
  • Я не хочу заставлять вас делать всю работу для меня, но я визуальный ученик. Как я могу использовать это, чтобы заменить «<price type=" double "> 55.0 <price>" на "<price type=" double "> 25.0 <price>"? –  Clucky 13.11.2012 в 23:52
  • Я могу дать вам полный синтаксис, если вы дадите мне действительный XML –  Gilles Quenot 14.11.2012 в 00:00
  • Вы можете протестировать его так: xmlstarlet val file.xml –  Gilles Quenot 14.11.2012 в 00:02
  • Там я исправил это. Извините, я новичок в stackoverflow, поэтому не знаю, как правильно отформатировать. Но он должен быть действительным файлом xml. –  Clucky 14.11.2012 в 00:04
  • Работал как шарм. Спасибо огромное! –  Clucky 14.11.2012 в 00:16
10

XML-путь классный, но если вам нужно использовать обычные инструменты bash, вы можете изменить строку с помощью sed. Например:

PRICE=123
sed -i "s/\(<price.*>\)[^<>]*\(<\/price.*\)/$PRICE/" $XML_FILE_TO_MODIFY

Это заменит цену на 123.

Эта команда sed кажется сложной, поэтому позвольте мне сломать ее:

\(<price.*>\)[^<>]*\(<\/price.*\) - это шаблон для соответствия. \( ... \) - это скобки для группировки. <price.*> соответствует начальному ценнику. [^<>]* соответствует чему угодно, кроме угловых скобок, и в этом случае будет соответствовать содержимому ценника. <\/price.* соответствует концу ценника. Прямая косая черта - это разделитель в sed, поэтому я избегаю ее с обратной косой чертой.

$PRICE - это текст для замены согласованного текста. относится к первой сопоставленной группе скобок, которая является начальным ценовым тегом. $PRICE - это переменная с желаемой ценой. относится ко второй группе скобок, в этом случае закрывающий тег.

    
ответ дан Dan Bliss 14.11.2012 в 00:24
  • Это неправильный путь. Вы не можете реалистично анализировать языки разметки на основе тегов, такие как HTML или XML, используя Bash, grep, sed, cut и т. Д. См. Codinghorror.com/blog/archives/001311.html (вы знаете сайт блога от создателя SO?) о HTML, но это то же самое для XML ... –  Gilles Quenot 14.11.2012 в 00:30
  • Если в Linux появился хороший инструмент xml, например xmlstarlet, я бы согласился с тем, что это неправильный путь. Пока это не так, sed - это мой инструмент go-to. Реально, вы можете использовать sed в 99% случаев, включая этот. –  Dan Bliss 14.11.2012 в 00:34
  • Я не сказал «что не работает», но: «это ненадежно». В простом случае это кажется «хорошим» для некоторых людей, но что происходит, когда XML становится более сложным с вложенными тегами? Я говорю о надежном способе сделать вещи чистыми. sudo apt-get install xmlstarlet не имеет большого значения. –  Gilles Quenot 14.11.2012 в 00:38
  • ", но я думаю, что это так же неправильно, как требовать, чтобы всякая тривиальная задача обработки HTML обрабатывалась полномасштабным механизмом синтаксического анализа" - это цитата из сообщения в блоге, которое вы цитируете. Несмотря на это, для записи: я предпочитаю решение xmlstarlet. Но если xmlstarlet недоступен, sed будет выполнен. –  Dan Bliss 14.11.2012 в 00:42
  • @sputnick: apt-get install не так-то просто, например. вам нужно подключение к Интернету и свободное пространство на HD (если вы используете что-то вроде Backtrack, у вас есть 4-гигабайтный ramdisk, и если он заполнен, он сбой). И недавно моя аппетитная система сломалась, и я не мог использовать apt-get install для чего-либо в течение 3 месяцев! –  BeniBela 14.11.2012 в 01:16
Показать остальные комментарии
1

У меня не было роскоши иметь xmlstarlet. Я нашел решение, просто сделав встроенную замену;

шаблон-parameter.xml

<ns:Parameter>
    <ns:Name required="true">##-ParamName-##</ns:Name>
    <ns:Value>
        <ns:Text>##-ParamValue-##</ns:Text>
    </ns:Value>
</ns:Parameter>

Отрывок

tokenName="foo"
tokenValue="bar"    

#Replace placeholders in parameter template element
myParamElement=$(cat template-parameter.xml)
myParamElement=${myParamElement//##-ParamName-##/$tokenName}
myParamElement=${myParamElement//##-ParamValue-##/$tokenValue}  

Результат

<ns:Parameter>
    <ns:Name required="true">foo</ns:Name>
    <ns:Value>
        <ns:Text>bar</ns:Text>
    </ns:Value>
</ns:Parameter>
    
ответ дан Denno 21.09.2016 в 22:42