У меня есть входной файл и файл xml.
входной файл-
/user/sht
227_89,45_99
/user/sht1
230_90
/user/sht2
441_50
В файле есть альтернативные строки, содержащие путь и позицию.
xml файл-
<aaa><command name="move">
<domain>
<path></path>
<positions></positions>
</domain>
<domain>
<path></path>
<positions></positions>
</domain>
<domain>
<path></path>
<positions></positions>
</domain>
</command>
</aaa>
Мне нужно написать сценарий, чтобы получить требуемый xml-файл, а затем запустить несколько команд, используя указанный ниже xml в качестве ввода-
<aaa><command name="move">
<domain>
<path>/user/sht</path>
<positions>227_89,45_99</positions>
</domain>
<domain>
<path>/user/sht1</path>
<positions>230_90</positions>
</domain>
<domain>
<path>/user/sht2</path>
<positions>441_50</positions>
</domain>
</command>
</aaa>
Я попытался извлечь построчно из входного файла и поместить это в xml, но проблема в том, что каждое вхождение
заменяется первой строкой ввода.
Использование GNU bash 4.1.2.
С помощью одного сценария GNU sed
вы можете сделать что-то вроде
sed -n '/<aaa>/,/<.aaa>/!{H;d}
G;:a
s_>\(</path>.*\n\)\n\([^\n]*\)_>\2\1_
s_>\(</positions>.*\n\)\n\([^\n]*\)_>\2\1_;
ta;P;s/.*\n\n/\n/;h' input.txt input.xml
Первая строка собирает все строки из первого файла в буфере хранения.
Затем для каждой строки второго файла к буферу хранения добавляется G
. Если это путь
или позиции
, первый сегмент буфера хранения перемещается внутри тегов с помощью одной из двух команд s
.
В любом случае строка печатается (P
) и удаляется (s/.*\n\n/\n/
), а то, что осталось от списка замены, перемещается обратно в буфер хранения для следующего цикла (h
).
В оболочке:
echo '<aaa><command name="move">'
echo '<domain>'
while true
do read v || break
echo "<path>$v</path>"
read v || break
echo "<positions>$v</positions>"
done < /path/to/YourInputFile
echo '</domain>
</command>
</aaa>'
Используя GNU sed и формат XML, как показано:
sed -e '
/<domain>/,/<\/domain>/!b
/<\(path\|positions\)><\/\1>/!b
s//<\1>/
R input_file
' XML_file |
sed -e '
/<\(path\|positions\)>.*/N
s//&\n<\/\1>/
s/\n//g
'
<aaa><command name="move">
<domain>
<path>/user/sht</path>
<positions>227_89,45_99</positions>
</domain>
<domain>
<path>/user/sht1</path>
<positions>230_90</positions>
</domain>
<domain>
<path>/user/sht2</path>
<positions>441_50</positions>
</domain>
</command>
</aaa>
Сценарий оболочки, отвечающий вашим требованиям
#!/bin/bash
count=0 ## counting lines
while read var
do
occurance=$[$count/2+1]; ## check nth occurance of search path/position from file
if [ $((count%2)) -eq 0 ]; ## If counting even replace path values else replace position values
then
perl -pe 's{<path>*}{++$n == '$occurance' ? "<path>'$var'" : $&}ge' xml > xml1
else
perl -pe 's{<positions>*}{++$n == '$occurance' ? "<positions>'$var'" : $&}ge' xml > xml1
fi
yes|cp xml1 xml
count=$[$count +1]
done <./input
rm xml1
Обратите внимание, что XML (, а также HTML )не являются обязательной структурой с«1 тегом на 1 строку»-он может иметьнесколькоразных тегов на] однустроку.
В таком случае я бы предложилPythonрешение:
заполнить _xml.pyскрипт:
import collections, xml.etree.ElementTree as ET
tree = ET.parse('yourxmlfile.xml') # <- specify your actual xml file name
root = tree.getroot()
with open('input.txt', 'r') as f:
d = collections.defaultdict(list)
for k,l in enumerate(f.read().splitlines()):
if k % 2 == 0: # treating each 2nd line as `positions` value
d['path'].append(l)
else:
d['positions'].append(l)
# iterating through `path`/`positions` node pairs
for k, nodes in enumerate(zip(root.findall('.//path'), root.findall('.//positions'))):
nodes[0].text = d['path'][k] # setting `path` value
nodes[1].text = d['positions'][k] # setting `positions` value
tree.write('result.xml') # write to the result file
Использование:
python fill_xml.py
Содержание result.xml
:
<aaa><command name="move">
<domain>
<path>/user/sht</path>
<positions>227_89,45_99</positions>
</domain>
<domain>
<path>/user/sht1</path>
<positions>230_90</positions>
</domain>
<domain>
<path>/user/sht2</path>
<positions>441_50</positions>
</domain>
</command>
</aaa>