скрипт unix для подсчета количества символов между определенными тегами xml - PullRequest
1 голос
/ 21 сентября 2010

Здравствуйте, я пытаюсь создать скрипт, который будет подсчитывать количество символов между тегами xml и идеально группировать по этим значениям, прежде чем возвращать варианты:

например

<CONTEXT_1>aaaa<CONTEXT_1>
<CONTEXT_2>bb<CONTEXT_2>
<CONTEXT_2>dfgh<CONTEXT_2>
<CONTEXT_6>bb<CONTEXT_6>
<CONTEXT_1>bbbb<CONTEXT_1>

результат будет

<CONTEXT_1> 4
<CONTEXT_2> 2,4
<CONTEXT_6> 4

Любая помощь будет высоко ценится! Я полностью застрял

Спасибо M

Ответы [ 5 ]

1 голос
/ 21 сентября 2010

1.Используйте специфичные для XML утилиты

Я думаю, что любой инструмент командной строки, предназначенный для работы с XML, лучше, чем пользовательские хаки awk / sed.Сценарии, использующие такие инструменты, являются более надежными и не ломаются, когда ввод XML немного переформатирован (например, не имеет значения, где разрывы строк и как отступ документа).Мой инструмент выбора для запросов XML из командной строки: xmlstarlet .

2.Исправьте ваш XML

Затем вам нужно исправить свой XML: правильно закрыть теги и добавить корневой элемент.Примерно так:

<root>
<CONTEXT_1>aaaa</CONTEXT_1>
<CONTEXT_2>bb</CONTEXT_2>
<CONTEXT_2>dfgh</CONTEXT_2>
<CONTEXT_6>bb</CONTEXT_6>
<CONTEXT_1>bbbb</CONTEXT_1>
</root>

3.Используйте XPath и XSLT

Выберите нужные элементы в XPath и обработайте их с помощью выражений XSLT.В вашем примере вы можете посчитать длину элементов с помощью

$ xmlstarlet sel -t -m '//root/*' -v "name(.)" -o ": " -v "string-length(.)" -n test.xml 

//root/*, чтобы выбрать все дочерние узлы root.name(.) печатает имя элемента выбранного в данный момент элемента, а string-length(.) печатает длину его содержимого.

и получает вывод:

CONTEXT_1: 4
CONTEXT_2: 2
CONTEXT_2: 4
CONTEXT_6: 2
CONTEXT_1: 4

Группируйте результаты как вам нравится1026 * или аналогичные инструменты.

0 голосов
/ 21 сентября 2010

Использование Perl:

#! /bin/perl    
open FILE, $ARGV[0] or die $!;
while (my $line = <FILE>) {
        if ($line =~ /^<([^>]*)>(.*)<.*$/) {
            $table{$1}="$table{$1},".length($2);
         }
}    
foreach my $key (sort keys %table) {
  print "$key ".substr($table{$key},1)."\n";
}

Вывод:

CONTEXT_1 4,4
CONTEXT_2 2,4
CONTEXT_6 2
0 голосов
/ 21 сентября 2010
$ awk -F">" '{sub("<.*","",$2);a[$1]=a[$1]","length($2)}END{for (i in a) print i,a[i]}' file
<CONTEXT_6 ,2
<CONTEXT_1 ,4,4
<CONTEXT_2 ,2,4
0 голосов
/ 21 сентября 2010

Вы можете сделать что-то подобное, используя sed:

sed  's/^<\([^>]*\)>\(.*\)<.*$/\1 \2/g' file.xml | sort | while read line
do
    context=`echo $line | cut -d' ' -f1`
    count=`echo $line | cut -d' ' -f2 | tr -d '\n' | wc -c`
    echo $context: $count
done | uniq

который печатает:

CONTEXT_1: 4
CONTEXT_2: 2
CONTEXT_2: 4
CONTEXT_6: 2
0 голосов
/ 21 сентября 2010

Это работа для Awk: полнофункциональный язык обработки текста.

Что-то вроде (не проверено):

awk \
"BEGIN { $INIT_TAB_AWK } \
{ split(\$0, tab, \"\"); \
for (chara in tab) \
{ for (chara2 in tab_search) \
{ if (tab_search[chara2] == tab[chara]) { final_tab[chara2]++ } } } } \
END { for (chara in final_tab) \
{ print tab_search[chara] \" => \" final_tab[chara] } }"
...