LINUX.ORG.RU

Как удалить часть текста между двумя тегами в xml?

 , , , ,


0

1

Собственно сабж. Количество символов между тегами worklog /worklog может превышать 134217728, необходимо написать скрипт, который удалит из набора XML файлов все остальные символы>134217728, но до закрывающего тега /worklog.

Если очень упростить, что-то вроде «worklog text /worklog» заменить на

«worklog shell_substring_equivalent(text,0,134217728) /worklog»

Пример XML: https://pastebin.com/3cgpp3G7



Последнее исправление: xakon (всего исправлений: 5)

Ответ на: комментарий от xakon

ну, напиши как здоровый человек на питоне, и вызывай этот скрипт из баш скрипта. Засчитается?

Просто никто в здравом уме не будет разбирать xml sed-ом и регулярками, тебе все равно нужно что-то что сумеет дерево элементов построить и будет работать с ним.

gnunixon ★★★
()

Можно awk использовать, но опять же придётся самому подсчитывать символы. Проще использовать язык типа Perl, Python или PowerShell с готовыми библиотеками разбора XML.

gedisdone ★★★
()
Ответ на: комментарий от gnunixon

Я нашёл похожую задачу здесь. Если реально удалить весь текст между тегами, то разве нельзя каким-то похожим образом удалить определённое число символов между ними? Как вырезать текст между двумя тэгами в xml?

xakon
() автор топика
<log.xml awk '/<worklog>/||/<\/worklog>/; /<worklog>/,/<\/worklog>/{next;};1'
<id>SOCP00701074202</id>
    <schema>OPS:Trouble Ticket</schema>
    <worklogData>
        <key>Private Work Log</key>
        <worklog>
        </worklog>
    </worklogData>
    <worklogData>
        <key>Public Work Log</key>
        <worklog>
        </worklog>
    </worklogData>

anonymous
()
Ответ на: комментарий от gnunixon

Просто никто в здравом уме не будет разбирать xml sed-ом и регулярками

sed-ом действительно трудно, так как sed построчное и без счётчика. А на bash пишется не сложно, если памяти под текст достаточно. Всасываем всё, находим нужную пару тегов с несложным алгоритмом для вложенных и/или нескольких блоков с одинаковыми уровнями.

тебе все равно нужно что-то что сумеет дерево элементов построить и будет работать с ним.

Да нафига? Нормальный xml достаточно строг, там не надо искать как в html что-то типа если тег не закрылся, а открылся из некого набора, значить тут пропущено закрытие и так далее. Полное дерево надо если хочется потом быстро находить разные блоки.

vodz ★★★★★
()

Перечитал ТС. Тебе надо вот прямо грубо ОБРЕЗАТЬ xml в коде? Т.е. резкультат типа такого тебя устроит?

<id>SOCP00701074202</id>
    <schema>OPS:Trouble Ticket</schema>
    <worklogData>
        <key>Private Work Log</key>
        <worklog>
            <entries>
                <text>SAMPLE TEXT</text>
                <timestamp>2019-03-18T02:46:10Z</timestamp>
                <type>MSS</type>
                <username>AR_ESCALA
        </worklog>
    </worklogData>
    <worklogData>
        <key>Public Work Log</key>
        <worklog>
            <entries>
                <text>SAMPLE TEXT</text>
                <timestamp>2019-03-07T06:24:41Z</timestamp>
                <type>MSS</type>
                <username>atl-prd-w
        </worklog>
    </worklogData>

Но он же невалидный будет!

anonymous
()
Ответ на: комментарий от anonymous

Да, текст между тегами worklog нужно сократить до 134217728 символа. Не имеет значения, если какие-то теги внутри worklog поломаются.

xakon
() автор топика
Ответ на: комментарий от vodz

А можно какое-то пример. Мне совсем непонятно, как делать.

Ещё может плохо объяснил задачу: ‘Текст между тегами worklog нужно сократить до 134217728 символа. Не имеет значения, если какие-то теги внутри worklog поломаются.’

xakon
() автор топика
Ответ на: комментарий от xakon

Необходимо решить вопрос с помощью bash скрипта

Тогда пиши XML парсер на баше. Врукопашную.

deep-purple ★★★★★
()

Тут главное выбрать правильный инструмент. Что работает с xml из коробки, питон, перл, повершел.. Что-то еще.

anonymous
()

Наверняка на перле это изи делается.

anonymous
()
Ответ на: комментарий от anonymous

А смысл? Если только зациклится на баше, то да, можно подыскать инструмент под задачу.

anonymous
()
Ответ на: комментарий от xakon

А можно какое-то пример.

Таки заставили подняпрячься.

Запускать xml-cut.sh < in.xml > out.xml

Вырезает из in.xml <tag [attrs]>.*</tag> первого уровня (тег без учёта регистра), то есть оставляя то, что внутри .*, вложенные эти теги остаются тоже. Теги могут быть в виде несколько блоков первого уровня, на выходе только первый блок. Всякие пробелы там и сям — допускаются.

#!/usr/bin/env bash

TAG=tag
TAGC='[Tt][Aa][Gg]'

IFS= read -r -d '' b

r=$'(\r+)(.*)'
while [[ $b =~ $r ]]; do
	b=${b:0:${#b}-${#BASH_REMATCH[0]}}${BASH_REMATCH[2]}
done

a=
r=$'<[ \t\n]*'$TAGC$'([ \t\n]+([^>]*))?>[ \t\n]*(.*)'
while [[ $b =~ $r ]]; do
	a+="${b:0:${#b}-${#BASH_REMATCH[0]}}<$TAG ${BASH_REMATCH[2]}>"
	b=${BASH_REMATCH[3]}
done
b=$a$b

a=
r=$'[ \t\n]*</[ \t\n]*'$TAGC$'[ \t\n]*>(.*)'
while [[ $b =~ $r ]]; do
	a+="${b:0:${#b}-${#BASH_REMATCH[0]}}</$TAG>"
	b=${BASH_REMATCH[1]}
done
b=$a$b

r="<$TAG [^>]*>(.*)</$TAG>"
if [[ $b =~ $r ]]; then
	b=${BASH_REMATCH[1]}
else
	echo "<$TAG [attrs]>.*</$TAG> не найдено" >&2
	exit 1
fi

while true; do
	 r="(.*)<$TAG "
	 if [[ $b =~ $r ]]; then
		 p=${BASH_REMATCH[1]}
		 a=${b:${#BASH_REMATCH[0]}}
		 b=$a
		 r="</$TAG>"
		 if [[ ! $b =~ $r ]]; then
			 b=$p
			 r="(.*)</$TAG>"
			 if [[ $b =~ $r ]]; then
				 b=${BASH_REMATCH[1]}
				 continue
			 fi
			 echo "(<$TAG [attrs]>.*</$TAG>)+ несбалансировано" >&2
			 exit 1
		 fi
		 b="$p<$TAG $a"
	 fi
	 break
done

a=
r="<$TAG >(.*)"
while [[ $b =~ $r ]]; do
	a+="${b:0:${#b}-${#BASH_REMATCH[0]}}<$TAG>"
	b=${BASH_REMATCH[1]}
done
b=$a$b

printf "%s" "$b"

Коментарии к этому за отдельный интересный вопрос.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от vodz

А если очень сильно упростить задачу и просто урезать текст между worklog /worklog до 134217728 символов. Не рассматривая файл, как xml, а как просто текстовый.

xakon
() автор топика

Рекомендую использовать язык с поточным XML-парсером. Например Java и SAX. В противном случае решение весьма вероятно будет неэффективным и не во всех случаях корректным.

Legioner ★★★★★
()
Ответ на: комментарий от anonymous

Вот, пример. Нужно просто урезать текст между всеми worklog /worklog в тексте до 134217728 символов. Без разницы, как обрежутся теги и прочее. Если воспринимать xml как просто текстовый файл.

https://pastebin.com/Sek5cz7s

xakon
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.