İdeal olarak, yapabilmek istediğim şey:
cat xhtmlfile.xhtml |
getElementViaXPath --path='/html/head/title' |
sed -e 's%(^<title>|</title>$)%%g' > titleOfXHTMLPage.txt
İdeal olarak, yapabilmek istediğim şey:
cat xhtmlfile.xhtml |
getElementViaXPath --path='/html/head/title' |
sed -e 's%(^<title>|</title>$)%%g' > titleOfXHTMLPage.txt
Yanıtlar:
Bu gerçekten sadece Yuzem'in cevabının bir açıklaması , ama bu kadar düzenlemenin başka birine yapılması gerektiğini hissetmedim ve yorumlar biçimlendirmeye izin vermiyor, bu yüzden ...
rdom () { local IFS=\> ; read -d \< E C ;}
"Rdom" yerine "read_dom" diyelim, biraz boşluk bırakalım ve daha uzun değişkenler kullanalım:
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
}
Tamam, read_dom adlı bir işlevi tanımlar. İlk satır IFS'yi (giriş alanı ayırıcısı) bu işleve yerel yapar ve> olarak değiştirir. Bu, boşlukta, sekmede veya yeni satırlarda otomatik olarak bölünmek yerine verileri okuduğunuzda '>' üzerinde bölündüğü anlamına gelir. Bir sonraki satır, stdin'den girdi okuduğunu ve yeni bir satırda durmak yerine, bir '<' karakteri (ayırıcı bayrağı için -d) gördüğünüzde durduğunu söylüyor. Okunan daha sonra IFS kullanılarak bölünür ve ENTITY ve CONTENT değişkenine atanır. Bu yüzden aşağıdakileri yapın:
<tag>value</tag>
read_dom
Boş bir dize almak için ilk çağrı ('<' ilk karakter olduğundan). '>' Karakteri olmadığı için bu, IFS tarafından sadece '' olarak bölünür. Okuma, ardından her iki değişkene de boş bir dize atar. İkinci çağrı 'tag> value' dizesini alır. Bu daha sonra IFS tarafından 'tag' ve 'value' iki alanına bölünür. Okuyun ve sonra: ENTITY=tag
ve gibi değişkenleri atar CONTENT=value
. Üçüncü çağrı '/ tag>' dizesini alır. Bu, IFS tarafından '/ tag' ve '' iki alanına bölünür. Okuyun ve sonra: ENTITY=/tag
ve gibi değişkenleri atar CONTENT=
. Dosya sonuna ulaştığımız için dördüncü çağrı sıfırdan farklı bir durum döndürecektir.
Şimdi while döngüsü yukarıdakilere uyacak şekilde biraz temizlendi:
while read_dom; do
if [[ $ENTITY = "title" ]]; then
echo $CONTENT
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
İlk satırda "read_dom işlevi sıfır durumuna dönerken aşağıdakileri yapın" yazıyor. İkinci satır, az önce gördüğümüz varlığın "başlık" olup olmadığını kontrol eder. Sonraki satır, etiketin içeriğini yansıtır. Dört çizgi çıkar. Başlık varlığı değilse, döngü altıncı satırda tekrarlanır. "Xhtmlfile.xhtml" dosyasını standart girdiye ( read_dom
işlev için) ve standart çıktıyı "titleOfXHTMLPage.txt" 'ye (döngüden önceki yankı) yönlendiririz.
Şimdi aşağıdakiler verilmiştir (S3'te bir kova listelemekten elde ettiğinize benzer) input.xml
:
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>sth-items</Name>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>item-apple-iso@2x.png</Key>
<LastModified>2011-07-25T22:23:04.000Z</LastModified>
<ETag>"0032a28286680abee71aed5d059c6a09"</ETag>
<Size>1785</Size>
<StorageClass>STANDARD</StorageClass>
</Contents>
</ListBucketResult>
ve aşağıdaki döngü:
while read_dom; do
echo "$ENTITY => $CONTENT"
done < input.xml
Şunları elde etmelisiniz:
=>
ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/" =>
Name => sth-items
/Name =>
IsTruncated => false
/IsTruncated =>
Contents =>
Key => item-apple-iso@2x.png
/Key =>
LastModified => 2011-07-25T22:23:04.000Z
/LastModified =>
ETag => "0032a28286680abee71aed5d059c6a09"
/ETag =>
Size => 1785
/Size =>
StorageClass => STANDARD
/StorageClass =>
/Contents =>
while
Yuzem gibi bir döngü yazarsak:
while read_dom; do
if [[ $ENTITY = "Key" ]] ; then
echo $CONTENT
fi
done < input.xml
S3 grubundaki tüm dosyaların bir listesini alırız.
DÜZENLE
Herhangi bir nedenden dolayı local IFS=\>
sizin için işe yaramazsa ve global olarak ayarlarsanız, aşağıdaki gibi işlevin sonunda sıfırlamanız gerekir:
read_dom () {
ORIGINAL_IFS=$IFS
IFS=\>
read -d \< ENTITY CONTENT
IFS=$ORIGINAL_IFS
}
Aksi takdirde, komut dosyasında daha sonra yaptığınız herhangi bir satır bölme işlemi bozulacaktır.
DÜZENLEME 2
Özellik adı / değer çiftlerini ayırmak için aşağıdakileri artırabilirsiniz read_dom()
:
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local ret=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $ret
}
Ardından ayrıştırmak ve istediğiniz verileri almak için işlevinizi yazın:
parse_dom () {
if [[ $TAG_NAME = "foo" ]] ; then
eval local $ATTRIBUTES
echo "foo size is: $size"
elif [[ $TAG_NAME = "bar" ]] ; then
eval local $ATTRIBUTES
echo "bar type is: $type"
fi
}
Sonra read_dom
aradığınızda parse_dom
:
while read_dom; do
parse_dom
done
Daha sonra aşağıdaki örnek işaretleme verildi:
<example>
<bar size="bar_size" type="metal">bars content</bar>
<foo size="1789" type="unknown">foos content</foo>
</example>
Bu çıktıyı almalısınız:
$ cat example.xml | ./bash_xml.sh
bar type is: metal
foo size is: 1789
EDIT 3 başka bir kullanıcı , FreeBSD'de bununla ilgili sorun yaşadıklarını söyledi ve çıkış durumunun okunmadan kaydedilmesini ve read_dom'un sonunda geri döndürülmesini önerdi:
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local RET=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $RET
}
Bunun çalışmaması için hiçbir neden göremiyorum
IFS=\< read ...
ki bu sadece okuma çağrısı için IFS'yi ayarlar. (Hiçbir şekilde read
xml ayrıştırmak için uygulama uygulamasını onaylamadığımı ve bunun tehlikeyle dolu olduğuna ve kaçınılması gerektiğine inanıyorum.)
Bunu sadece bash kullanarak kolayca yapabilirsiniz. Yalnızca bu işlevi eklemeniz gerekir:
rdom () { local IFS=\> ; read -d \< E C ;}
Artık html'i read gibi ama html belgeleri için kullanabilirsiniz. Rdom çağrıldığında elemanı E değişkenine ve içeriği C değişkenine atar.
Örneğin, yapmak istediğiniz şeyi yapmak için:
while rdom; do
if [[ $E = title ]]; then
echo $C
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
Kabuk komut dosyalarından çağrılabilen komut satırı araçları şunları içerir:
Ben de xmllint ve xsltproc komut satırından veya kabuk komut dosyalarında XML işleme yapmak için küçük XSL dönüşüm komut dosyaları ile kullanın.
Xpath yardımcı programını kullanabilirsiniz. Perl XML-XPath paketiyle birlikte yüklenir.
Kullanımı:
/usr/bin/xpath [filename] query
veya XMLStarlet . Opensuse yüklemek için kullanın:
sudo zypper install xmlstarlet
veya cnf xml
diğer platformlarda deneyin .
xpath
Önceden yüklenmiş olarak gelen birçok sistemde, komut dosyalarında bileşen olarak kullanım için uygun değildir. Ayrıntılı bilgi için bkz . Stackoverflow.com/questions/15461737/… .
apt-get install xmlstarlet
Bu yeterli ...
xpath xhtmlfile.xhtml '/html/head/title/text()' > titleOfXHTMLPage.txt
apt-get install libxml-xpath-perl
.
Check out XML2 dan http://www.ofb.net/~egnor/xml2/ satır yönelimli biçime XML dönüştürür.
Çad'ın cevabından başlayarak, yorumların propper işlenmesi ile, sadece 2 küçük fonksiyonla (2'den fazla bu hepsini karıştırabilirsiniz) UML'yi ayrıştırmak için TAM çalışma çözümü. Çad'ın hiç işe yaramadığını söylemiyorum, ancak kötü biçimlendirilmiş XML dosyalarıyla çok fazla sorunu vardı: Bu yüzden yorumları ve yanlış yerleştirilmiş alanları / CR / TAB / etc'yi işlemek için biraz daha zor olmalısınız.
Bu cevabın amacı, perl, python veya başka bir şey kullanan karmaşık araçlar olmadan UML'yi ayrıştırma ihtiyacı duyan herkese, kullanıma hazır bash işlevlerini vermektir. Bana gelince, üzerinde çalıştığım eski üretim işletim sistemi için cpan veya perl modülleri yükleyemiyorum ve python mevcut değil.
İlk olarak, bu yayında kullanılan UML kelimelerinin tanımı:
<!-- comment... -->
<tag attribute="value">content...</tag>
EDIT: güncellenmiş işlevler, tutamağı ile:
xml_read_dom() {
# /programming/893585/how-to-parse-xml-in-bash
local ENTITY IFS=\>
if $ITSACOMMENT; then
read -d \< COMMENTS
COMMENTS="$(rtrim "${COMMENTS}")"
return 0
else
read -d \< ENTITY CONTENT
CR=$?
[ "x${ENTITY:0:1}x" == "x/x" ] && return 0
TAG_NAME=${ENTITY%%[[:space:]]*}
[ "x${TAG_NAME}x" == "x?xmlx" ] && TAG_NAME=xml
TAG_NAME=${TAG_NAME%%:*}
ATTRIBUTES=${ENTITY#*[[:space:]]}
ATTRIBUTES="${ATTRIBUTES//xmi:/}"
ATTRIBUTES="${ATTRIBUTES//xmlns:/}"
fi
# when comments sticks to !-- :
[ "x${TAG_NAME:0:3}x" == "x!--x" ] && COMMENTS="${TAG_NAME:3} ${ATTRIBUTES}" && ITSACOMMENT=true && return 0
# http://tldp.org/LDP/abs/html/string-manipulation.html
# INFO: oh wait it doesn't work on IBM AIX bash 3.2.16(1):
# [ "x${ATTRIBUTES:(-1):1}x" == "x/x" -o "x${ATTRIBUTES:(-1):1}x" == "x?x" ] && ATTRIBUTES="${ATTRIBUTES:0:(-1)}"
[ "x${ATTRIBUTES:${#ATTRIBUTES} -1:1}x" == "x/x" -o "x${ATTRIBUTES:${#ATTRIBUTES} -1:1}x" == "x?x" ] && ATTRIBUTES="${ATTRIBUTES:0:${#ATTRIBUTES} -1}"
return $CR
}
ve ikincisi:
xml_read() {
# /programming/893585/how-to-parse-xml-in-bash
ITSACOMMENT=false
local MULTIPLE_ATTR LIGHT FORCE_PRINT XAPPLY XCOMMAND XATTRIBUTE GETCONTENT fileXml tag attributes attribute tag2print TAGPRINTED attribute2print XAPPLIED_COLOR PROSTPROCESS USAGE
local TMP LOG LOGG
LIGHT=false
FORCE_PRINT=false
XAPPLY=false
MULTIPLE_ATTR=false
XAPPLIED_COLOR=g
TAGPRINTED=false
GETCONTENT=false
PROSTPROCESS=cat
Debug=${Debug:-false}
TMP=/tmp/xml_read.$RANDOM
USAGE="${C}${FUNCNAME}${c} [-cdlp] [-x command <-a attribute>] <file.xml> [tag | \"any\"] [attributes .. | \"content\"]
${nn[2]} -c = NOCOLOR${END}
${nn[2]} -d = Debug${END}
${nn[2]} -l = LIGHT (no \"attribute=\" printed)${END}
${nn[2]} -p = FORCE PRINT (when no attributes given)${END}
${nn[2]} -x = apply a command on an attribute and print the result instead of the former value, in green color${END}
${nn[1]} (no attribute given will load their values into your shell; use '-p' to print them as well)${END}"
! (($#)) && echo2 "$USAGE" && return 99
(( $# < 2 )) && ERROR nbaram 2 0 && return 99
# getopts:
while getopts :cdlpx:a: _OPT 2>/dev/null
do
{
case ${_OPT} in
c) PROSTPROCESS="${DECOLORIZE}" ;;
d) local Debug=true ;;
l) LIGHT=true; XAPPLIED_COLOR=END ;;
p) FORCE_PRINT=true ;;
x) XAPPLY=true; XCOMMAND="${OPTARG}" ;;
a) XATTRIBUTE="${OPTARG}" ;;
*) _NOARGS="${_NOARGS}${_NOARGS+, }-${OPTARG}" ;;
esac
}
done
shift $((OPTIND - 1))
unset _OPT OPTARG OPTIND
[ "X${_NOARGS}" != "X" ] && ERROR param "${_NOARGS}" 0
fileXml=$1
tag=$2
(( $# > 2 )) && shift 2 && attributes=$*
(( $# > 1 )) && MULTIPLE_ATTR=true
[ -d "${fileXml}" -o ! -s "${fileXml}" ] && ERROR empty "${fileXml}" 0 && return 1
$XAPPLY && $MULTIPLE_ATTR && [ -z "${XATTRIBUTE}" ] && ERROR param "-x command " 0 && return 2
# nb attributes == 1 because $MULTIPLE_ATTR is false
[ "${attributes}" == "content" ] && GETCONTENT=true
while xml_read_dom; do
# (( CR != 0 )) && break
(( PIPESTATUS[1] != 0 )) && break
if $ITSACOMMENT; then
# oh wait it doesn't work on IBM AIX bash 3.2.16(1):
# if [ "x${COMMENTS:(-2):2}x" == "x--x" ]; then COMMENTS="${COMMENTS:0:(-2)}" && ITSACOMMENT=false
# elif [ "x${COMMENTS:(-3):3}x" == "x-->x" ]; then COMMENTS="${COMMENTS:0:(-3)}" && ITSACOMMENT=false
if [ "x${COMMENTS:${#COMMENTS} - 2:2}x" == "x--x" ]; then COMMENTS="${COMMENTS:0:${#COMMENTS} - 2}" && ITSACOMMENT=false
elif [ "x${COMMENTS:${#COMMENTS} - 3:3}x" == "x-->x" ]; then COMMENTS="${COMMENTS:0:${#COMMENTS} - 3}" && ITSACOMMENT=false
fi
$Debug && echo2 "${N}${COMMENTS}${END}"
elif test "${TAG_NAME}"; then
if [ "x${TAG_NAME}x" == "x${tag}x" -o "x${tag}x" == "xanyx" ]; then
if $GETCONTENT; then
CONTENT="$(trim "${CONTENT}")"
test ${CONTENT} && echo "${CONTENT}"
else
# eval local $ATTRIBUTES => eval test "\"\$${attribute}\"" will be true for matching attributes
eval local $ATTRIBUTES
$Debug && (echo2 "${m}${TAG_NAME}: ${M}$ATTRIBUTES${END}"; test ${CONTENT} && echo2 "${m}CONTENT=${M}$CONTENT${END}")
if test "${attributes}"; then
if $MULTIPLE_ATTR; then
# we don't print "tag: attr=x ..." for a tag passed as argument: it's usefull only for "any" tags so then we print the matching tags found
! $LIGHT && [ "x${tag}x" == "xanyx" ] && tag2print="${g6}${TAG_NAME}: "
for attribute in ${attributes}; do
! $LIGHT && attribute2print="${g10}${attribute}${g6}=${g14}"
if eval test "\"\$${attribute}\""; then
test "${tag2print}" && ${print} "${tag2print}"
TAGPRINTED=true; unset tag2print
if [ "$XAPPLY" == "true" -a "${attribute}" == "${XATTRIBUTE}" ]; then
eval ${print} "%s%s\ " "\${attribute2print}" "\${${XAPPLIED_COLOR}}\"\$(\$XCOMMAND \$${attribute})\"\${END}" && eval unset ${attribute}
else
eval ${print} "%s%s\ " "\${attribute2print}" "\"\$${attribute}\"" && eval unset ${attribute}
fi
fi
done
# this trick prints a CR only if attributes have been printed durint the loop:
$TAGPRINTED && ${print} "\n" && TAGPRINTED=false
else
if eval test "\"\$${attributes}\""; then
if $XAPPLY; then
eval echo "\${g}\$(\$XCOMMAND \$${attributes})" && eval unset ${attributes}
else
eval echo "\$${attributes}" && eval unset ${attributes}
fi
fi
fi
else
echo eval $ATTRIBUTES >>$TMP
fi
fi
fi
fi
unset CR TAG_NAME ATTRIBUTES CONTENT COMMENTS
done < "${fileXml}" | ${PROSTPROCESS}
# http://mywiki.wooledge.org/BashFAQ/024
# INFO: I set variables in a "while loop" that's in a pipeline. Why do they disappear? workaround:
if [ -s "$TMP" ]; then
$FORCE_PRINT && ! $LIGHT && cat $TMP
# $FORCE_PRINT && $LIGHT && perl -pe 's/[[:space:]].*?=/ /g' $TMP
$FORCE_PRINT && $LIGHT && sed -r 's/[^\"]*([\"][^\"]*[\"][,]?)[^\"]*/\1 /g' $TMP
. $TMP
rm -f $TMP
fi
unset ITSACOMMENT
}
ve son olarak, rtrim, trim ve echo2 (stderr'a) işlev görür:
rtrim() {
local var=$@
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
echo -n "$var"
}
trim() {
local var=$@
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
echo -n "$var"
}
echo2() { echo -e "$@" 1>&2; }
oh ve ilk başta tanımlanacak ve dışa aktarılacak bazı düzgün renklendirme dinamik değişkenlerine ihtiyacınız olacak:
set -a
TERM=xterm-256color
case ${UNAME} in
AIX|SunOS)
M=$(${print} '\033[1;35m')
m=$(${print} '\033[0;35m')
END=$(${print} '\033[0m')
;;
*)
m=$(tput setaf 5)
M=$(tput setaf 13)
# END=$(tput sgr0) # issue on Linux: it can produces ^[(B instead of ^[[0m, more likely when using screenrc
END=$(${print} '\033[0m')
;;
esac
# 24 shades of grey:
for i in $(seq 0 23); do eval g$i="$(${print} \"\\033\[38\;5\;$((232 + i))m\")" ; done
# another way of having an array of 5 shades of grey:
declare -a colorNums=(238 240 243 248 254)
for num in 0 1 2 3 4; do nn[$num]=$(${print} "\033[38;5;${colorNums[$num]}m"); NN[$num]=$(${print} "\033[48;5;${colorNums[$num]}m"); done
# piped decolorization:
DECOLORIZE='eval sed "s,${END}\[[0-9;]*[m|K],,g"'
Ya fonksiyonlar oluşturmayı ve bunları FPATH (ksh) veya FPATH (bash) öykünmesi yoluyla nasıl yükleyeceğinizi biliyorsunuz
Değilse, komut satırındaki her şeyi kopyalayın / yapıştırın.
xml_read [-cdlp] [-x command <-a attribute>] <file.xml> [tag | "any"] [attributes .. | "content"]
-c = NOCOLOR
-d = Debug
-l = LIGHT (no \"attribute=\" printed)
-p = FORCE PRINT (when no attributes given)
-x = apply a command on an attribute and print the result instead of the former value, in green color
(no attribute given will load their values into your shell as $ATTRIBUTE=value; use '-p' to print them as well)
xml_read server.xml title content # print content between <title></title>
xml_read server.xml Connector port # print all port values from Connector tags
xml_read server.xml any port # print all port values from any tags
Hata Ayıklama modu (-d) ile yorumlar ve ayrıştırılmış öznitelikler stderr
./read_xml.sh: line 22: (-1): substring expression < 0
?
[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
Hiçbir saf kabuk XML ayrıştırma aracı farkında değilim. Yani büyük olasılıkla başka bir dilde yazılmış bir araca ihtiyacınız olacak.
XML :: Twig Perl modülü böyle bir araçla birlikte gelir: xml_grep
muhtemelen istediğiniz şeyi yazabilirsiniz xml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt
( -t
seçenek size sonucu xml yerine metin olarak verir)
Başka bir komut satırı aracı yeni Xidel'im . Ayrıca, daha önce bahsedilen xpath / xmlstarlet'in aksine XPath 2 ve XQuery'yi de destekler.
Başlık şu şekilde okunabilir:
xidel xhtmlfile.xhtml -e /html/head/title > titleOfXHTMLPage.txt
Ayrıca, birden çok değişkeni bash'a aktarmak için harika bir özelliği vardır. Örneğin
eval $(xidel xhtmlfile.xhtml -e 'title := //title, imgcount := count(//img)' --output-format bash )
$title
başlığa ve $imgcount
doğrudan bash içinde ayrıştırmak kadar esnek olması gereken dosyadaki görüntü sayısına ayarlanır .
XML dosyalarındaki dosya yollarının Linux ve Windows formatları arasındaki çeviri araştırmalarından sonra ilginç öğreticiler ve çözümler buldum:
İstediğinizi yapabilen birkaç hazır konsol yardımcı programı olsa da, Python gibi genel amaçlı bir programlama dilinde kolayca genişletebileceğiniz ve uyum sağlayabileceğiniz birkaç satır kod yazmak muhtemelen daha az zaman alacaktır. ihtiyaçlarınızı.
lxml
Ayrıştırma için kullanılan bir python betiği - bir dosyanın veya URL'nin adını ilk parametre olarak, bir XPath ifadesini ikinci parametre olarak alır ve verilen ifadeyle eşleşen dizeleri / düğümleri yazdırır.
#!/usr/bin/env python
import sys
from lxml import etree
tree = etree.parse(sys.argv[1])
xpath_expression = sys.argv[2]
# a hack allowing to access the
# default namespace (if defined) via the 'p:' prefix
# E.g. given a default namespaces such as 'xmlns="http://maven.apache.org/POM/4.0.0"'
# an XPath of '//p:module' will return all the 'module' nodes
ns = tree.getroot().nsmap
if ns.keys() and None in ns:
ns['p'] = ns.pop(None)
# end of hack
for e in tree.xpath(xpath_expression, namespaces=ns):
if isinstance(e, str):
print(e)
else:
print(e.text and e.text.strip() or etree.tostring(e, pretty_print=True))
lxml
ile kurulabilir pip install lxml
. Ubuntu üzerinde kullanabilirsiniz sudo apt install python-lxml
.
python xpath.py myfile.xml "//mynode"
lxml
URL'yi giriş olarak da kabul eder:
python xpath.py http://www.feedforall.com/sample.xml "//link"
Not : XML'nizde önek içermeyen varsayılan bir ad alanı varsa (örneğin
xmlns=http://abc...
)p
, ifadelerinizdeki önekleri ('hack' tarafından sağlanan) kullanmanız gerekir; örneğin//p:module
, modülleri birpom.xml
dosyadan almak için . Önp
ek XML'nizde zaten eşlenmişse, başka bir önek kullanmak için komut dosyasını değiştirmeniz gerekir.
Bir apache maven dosyasından modül adlarını çıkarmak için dar bir amaca hizmet eden tek seferlik bir komut dosyası. Düğüm adının ( module
) varsayılan ad alanı ile nasıl ön ekine sahip olduğuna dikkat edin {http://maven.apache.org/POM/4.0.0}
:
pom.xml :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modules>
<module>cherries</module>
<module>bananas</module>
<module>pears</module>
</modules>
</project>
module_extractor.py :
from lxml import etree
for _, e in etree.iterparse(open("pom.xml"), tag="{http://maven.apache.org/POM/4.0.0}module"):
print(e.text)
pip install
fazlalığı apt-get
veya yum
çağrıyı haklı çıkarabilirim . Teşekkürler!
Yuzem'in yöntemi , işlevdeki ve değişken atamalarındaki <
ve >
işaretlerinin sırasını tersine çevirerek geliştirilebilir rdom
, böylece:
rdom () { local IFS=\> ; read -d \< E C ;}
dönüşür:
rdom () { local IFS=\< ; read -d \> C E ;}
Ayrıştırma bu şekilde yapılmazsa, XML dosyasındaki son etikete asla ulaşılmaz. while
Döngünün sonunda başka bir XML dosyası çıktısını almak istiyorsanız bu sorunlu olabilir .
XML nitelikleri istiyorsanız bu çalışır:
$ cat alfa.xml
<video server="asdf.com" stream="H264_400.mp4" cdn="limelight"/>
$ sed 's.[^ ]*..;s./>..' alfa.xml > alfa.sh
$ . ./alfa.sh
$ echo "$stream"
H264_400.mp4
"Asla XML, JSON ... düzgün bir araç olmadan bash gelen ayrıştırmak" gibi görünüyor olsa da, ben tavsiye etmiyorum. Eğer bu yan iş ise, uygun aracı aramak çok zordur, sonra öğrenin ... Awk dakikalar içinde yapabilir. Programlarımın yukarıda belirtilen tüm veriler ve daha fazla veri üzerinde çalışması gerekiyor. Cehennem, problemi dakikalar içinde uyandırabilirsem 5-7-10 farklı formatı ayrıştırmak için 30 aracı test etmek istemiyorum. XML, JSON ya da her neyse umrumda değil! Hepsi için tek bir çözüme ihtiyacım var.
Örnek olarak: SmartHome programım evlerimizi işletiyor. Bunu yaparken, kontrol edemediğim çok farklı formatlarda çok sayıda veri okur. İhtiyacım olan verileri okumak için birkaç dakikadan fazla zaman harcamak istemediğim için asla özel ve uygun araçlar kullanmıyorum. FS ve RS ayarlamaları ile bu awk çözümü herhangi bir metin formatı için mükemmel çalışır. Ancak, birincil göreviniz öncelikle bu formattaki bir sürü veriyle çalışmak uygun bir cevap olmayabilir!
Dün karşılaştığım bash'den XML ayrıştırma sorunu. Herhangi bir hiyerarşik veri biçimi için bunu nasıl yapacağım. Bir bonus olarak - doğrudan bir bash betiğindeki değişkenlere veri atarım.
İncileri okumayı kolaylaştırmak için aşamalı olarak çözüm sunacağım. OP test verilerinden bir dosya oluşturdum: test.xml
Bahsedilen XML'yi bash'de ayrıştırma ve verileri 90 karakterde çıkarma:
awk 'BEGIN { FS="<|>"; RS="\n" }; /host|username|password|dbname/ { print $2, $4 }' test.xml
Normalde daha okunabilir sürümü kullanıyorum çünkü gerçek hayatta değişmek daha kolay olduğu için sıklıkla farklı testler yapmam gerekiyor:
awk 'BEGIN { FS="<|>"; RS="\n" }; { if ($0 ~ /host|username|password|dbname/) print $2,$4}' test.xml
Formatın nasıl adlandırıldığı umurumda değil. Sadece en basit çözümü arıyorum. Bu özel durumda, verilerden yeni satırın kayıt ayırıcı (RS) ve <> sınırlama alanları (FS) olduğunu görebiliyorum. Orijinal durumumda, iki kayıt içinde 6 değerin karmaşık indekslemesini yaptım, bunlarla ilgili olarak, verinin ne zaman mevcut olduğunu ve ayrıca alanların (kayıtların) bulunup bulunmayabileceğini buldum. Sorunu mükemmel bir şekilde çözmek için 4 satır awk aldı. Bu yüzden, fikri kullanmadan önce her ihtiyaca uyarlayın!
İkinci kısım, bir satırda (RS) istenen dize olduğunu ve gerekli alanları (FS) yazdırdığını görünüyor. Yukarıdakiler, bu şekilde kullandığım son komuttan (4 kat daha uzun) kopyalayıp uyarlamak için yaklaşık 30 saniye sürdü. Ve işte bu! 90 karakterle tamamlandı.
Ancak, verileri her zaman komut dosyamdaki değişkenlere düzgün bir şekilde almam gerekiyor. İlk önce yapıları şu şekilde test ediyorum:
awk 'BEGIN { FS="<|>"; RS="\n" }; { if ($0 ~ /host|username|password|dbname/) print $2"=\""$4"\"" }' test.xml
Bazı durumlarda print yerine printf kullanıyorum. Her şeyin iyi göründüğünü gördüğümde, değişkenlere değer atamayı bitiriyorum. Birçoğunun "eval" in "kötü" olduğunu düşündüğünü biliyorum, yorum yapmaya gerek yok :) Trick yıllarca ağlarımın her birinde mükemmel çalışıyor. Ancak bunun neden kötü bir uygulama olabileceğini anlamadıysanız öğrenmeye devam edin! Bas değişken atamaları ve geniş boşluklar dahil, çözümüm her şeyi yapmak için 120 karaktere ihtiyaç duyuyor.
eval $( awk 'BEGIN { FS="<|>"; RS="\n" }; { if ($0 ~ /host|username|password|dbname/) print $2"=\""$4"\"" }' test.xml ); echo "host: $host, username: $username, password: $password dbname: $dbname"