आदर्श रूप में, मैं जो करना चाहूंगा वह है:
cat xhtmlfile.xhtml |
getElementViaXPath --path='/html/head/title' |
sed -e 's%(^<title>|</title>$)%%g' > titleOfXHTMLPage.txt
आदर्श रूप में, मैं जो करना चाहूंगा वह है:
cat xhtmlfile.xhtml |
getElementViaXPath --path='/html/head/title' |
sed -e 's%(^<title>|</title>$)%%g' > titleOfXHTMLPage.txt
जवाबों:
यह वास्तव में केवल युजेम के उत्तर का स्पष्टीकरण है , लेकिन मुझे ऐसा नहीं लगा कि यह संपादन किसी और को किया जाना चाहिए, और टिप्पणियां प्रारूपण की अनुमति नहीं देती हैं, इसलिए ...
rdom () { local IFS=\> ; read -d \< E C ;}
चलो "rdom" के बजाय उस "read_dom" को कॉल करते हैं, इसे थोड़ा बाहर निकालते हैं और लंबे चर का उपयोग करते हैं:
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
}
ठीक है, इसलिए यह read_dom नामक फ़ंक्शन को परिभाषित करता है। पहली पंक्ति IFS (इनपुट फ़ील्ड विभाजक) को इस फ़ंक्शन के लिए स्थानीय बनाती है और इसे> में बदल देती है। इसका मतलब है कि जब आप स्पेस, टैब या न्यूलाइन्स पर स्वचालित रूप से विभाजित होने के बजाय डेटा पढ़ते हैं तो यह '>' पर विभाजित हो जाता है। अगली पंक्ति स्टड से इनपुट पढ़ने के लिए कहती है, और एक नई रेखा पर रुकने के बजाय, जब आप '<' अक्षर (डेलिमिनेटर फ्लैग के लिए -d) देखते हैं तो रुक जाएं। फिर जो पढ़ा जाता है, वह IFS का उपयोग करके विभाजित होता है और चर ENTITY और CONTENT को सौंपा जाता है। तो निम्नलिखित लें:
<tag>value</tag>
read_dom
खाली स्ट्रिंग पाने के लिए पहला कॉल ('<' पहला पात्र है)। यह आईएफएस द्वारा सिर्फ '' में विभाजित हो जाता है, क्योंकि कोई '>' वर्ण नहीं है। पढ़ें तो दोनों चर के लिए एक खाली स्ट्रिंग प्रदान करता है। दूसरी कॉल को स्ट्रिंग 'टैग> मान' मिलता है। फिर IFS द्वारा दो क्षेत्रों 'टैग' और 'मूल्य' में विभाजित हो जाता है। पढ़ें तो जैसे चर प्रदान करता है: ENTITY=tag
और CONTENT=value
। तीसरी कॉल को स्ट्रिंग '/ टैग>' मिलता है। यह IFS द्वारा दो क्षेत्रों '/ टैग' और '' में विभाजित हो जाता है। पढ़ें तो जैसे चर प्रदान करता है: ENTITY=/tag
और CONTENT=
। चौथी कॉल गैर-शून्य स्थिति लौटाएगी क्योंकि हम फ़ाइल के अंत तक पहुँच चुके हैं।
अब जबकि उसके लूप ने ऊपर से मिलान करने के लिए थोड़ी सफाई की:
while read_dom; do
if [[ $ENTITY = "title" ]]; then
echo $CONTENT
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
पहली पंक्ति बस यही कहती है, "जबकि read_dom शून्य स्थिति का कार्य करता है, निम्न कार्य करें।" दूसरी पंक्ति यह जाँचती है कि जिस इकाई को हमने अभी देखा है वह "शीर्षक" है। अगली पंक्ति टैग की सामग्री को प्रतिध्वनित करती है। चार लाइन से बाहर निकलता है। यदि यह शीर्षक इकाई नहीं थी, तो लूप छठी पंक्ति में दोहराता है। हम मानक इनपुट ( read_dom
फ़ंक्शन के लिए) में "xhtmlfile.xhtml" को रीडायरेक्ट करते हैं और मानक आउटपुट को "titleOfXHTMLPage.txt" (पहले से लूप में गूंज) में रीडायरेक्ट करते हैं।
अब निम्नलिखित दिए गए हैं (S3 पर बाल्टी सूचीबद्ध करने से आपको जो मिलता है) 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>
और निम्नलिखित लूप:
while read_dom; do
echo "$ENTITY => $CONTENT"
done < 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 =>
तो अगर हम while
Yuzem की तरह एक पाश लिखा है :
while read_dom; do
if [[ $ENTITY = "Key" ]] ; then
echo $CONTENT
fi
done < input.xml
हमें S3 बाल्टी में सभी फाइलों की एक सूची मिलेगी।
संपादित करें
यदि किसी कारण से local IFS=\>
आपके लिए काम नहीं करता है और आपने इसे विश्व स्तर पर सेट किया है, तो आपको इसे फ़ंक्शन के अंत में रीसेट करना चाहिए जैसे:
read_dom () {
ORIGINAL_IFS=$IFS
IFS=\>
read -d \< ENTITY CONTENT
IFS=$ORIGINAL_IFS
}
अन्यथा, स्क्रिप्ट में बाद में आप जो भी विभाजन करते हैं, वह गड़बड़ हो जाएगा।
EDIT 2
विशेषता नाम / मूल्य जोड़े को विभाजित करने के लिए आप इस read_dom()
तरह से बढ़ा सकते हैं :
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local ret=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $ret
}
फिर अपने फ़ंक्शन को पार्स करने के लिए लिखें और उस डेटा को प्राप्त करें जो आप इस तरह चाहते हैं:
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
}
फिर जब आप read_dom
फोन करते हैं parse_dom
:
while read_dom; do
parse_dom
done
फिर निम्न उदाहरण मार्कअप दिया गया:
<example>
<bar size="bar_size" type="metal">bars content</bar>
<foo size="1789" type="unknown">foos content</foo>
</example>
आपको यह आउटपुट मिलना चाहिए:
$ cat example.xml | ./bash_xml.sh
bar type is: metal
foo size is: 1789
EDIT 3 एक अन्य उपयोगकर्ता ने कहा कि उन्हें FreeBSD में समस्या हो रही थी और सुझाव दिया कि बाहर निकलने की स्थिति को पढ़ने से बचाएं और इसे read_dom के अंत में लौटा दें:
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local RET=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $RET
}
मुझे कोई कारण नहीं दिख रहा है कि काम क्यों नहीं करना चाहिए
IFS=\< read ...
जो केवल रीड कॉल के लिए IFS सेट करेगा। (ध्यान दें कि मैं किसी भी तरह read
से पार्स एक्सएमएल का उपयोग करने के अभ्यास का समर्थन नहीं कर रहा हूं, और मेरा मानना है कि ऐसा करना जोखिम से भरा हुआ है और इससे बचा जाना चाहिए।)
आप बहुत ही आसानी से केवल बैश का उपयोग कर सकते हैं। आपको केवल यह फ़ंक्शन जोड़ना होगा:
rdom () { local IFS=\> ; read -d \< E C ;}
अब आप पढ़े हुए जैसे html दस्तावेजों के लिए rdom का उपयोग कर सकते हैं। कब कहा जाता है Rdom तत्व को E और वेरिएंट C को वेरिएबल करेगा।
उदाहरण के लिए, वह करना जो आप करना चाहते थे:
while rdom; do
if [[ $E = title ]]; then
echo $C
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
शेल स्क्रिप्ट से कॉल की जा सकने वाली कमांड लाइन टूल में शामिल हैं:
मैं xmllint और xsltproc का उपयोग कमांड लाइन या शेल स्क्रिप्ट में XML प्रोसेसिंग करने के लिए थोड़ा XSL ट्रांसफॉर्म स्क्रिप्ट के साथ करता हूं।
आप xpath उपयोगिता का उपयोग कर सकते हैं। यह पर्ल एक्सएमएल-एक्सपीथ पैकेज के साथ स्थापित है।
उपयोग:
/usr/bin/xpath [filename] query
या XMLStarlet । खुलने के उपयोग पर इसे स्थापित करने के लिए:
sudo zypper install xmlstarlet
या cnf xml
अन्य प्लेटफार्मों पर प्रयास करें ।
xpath
जो प्रीइंस्टॉल्ड आता है, स्क्रिप्ट में एक घटक के रूप में उपयोग के लिए अनुपयुक्त है। उदाहरण के लिए देखें stackoverflow.com/questions/15461737/… एक विस्तार के लिए।
apt-get install xmlstarlet
यह पर्याप्त है ...
xpath xhtmlfile.xhtml '/html/head/title/text()' > titleOfXHTMLPage.txt
apt-get install libxml-xpath-perl
।
की जाँच करें XML2 से http://www.ofb.net/~egnor/xml2/ जो एक लाइन उन्मुख प्रारूप करने के लिए एक्सएमएल बदल देता है।
चाड के जवाब से शुरू, यहाँ UML को पार्स करने के लिए पूर्ण कार्य समाधान है, टिप्पणियों के प्रॉपर हैंडलिंग के साथ, सिर्फ 2 छोटे कार्यों (2 बू से अधिक आप उन सभी को मिला सकते हैं)। मैं नहीं कहता कि चाड का काम बिल्कुल नहीं था, लेकिन इसमें बहुत बुरी तरह से तैयार एक्सएमएल फाइलों के साथ बहुत अधिक समस्याएं थीं: इसलिए आपको टिप्पणियों और गलत स्थानों / सीआर / टीएबी / आदि को संभालने के लिए थोड़ा और मुश्किल होना चाहिए।
इस उत्तर का उद्देश्य तैयार-2-उपयोग को देना है, किसी को भी यूएमएल को पार्सल, पाइथन या किसी अन्य चीज का उपयोग किए बिना जटिल उपकरणों को पार्स करने की जरूरत है। मेरे लिए, मैं पुराने उत्पादन OS के लिए cpan, और perl मॉड्यूल को स्थापित नहीं कर सकता, जिस पर मैं काम कर रहा हूं, और अजगर उपलब्ध नहीं है।
सबसे पहले, इस पोस्ट में उपयोग किए गए यूएमएल शब्दों की एक परिभाषा:
<!-- comment... -->
<tag attribute="value">content...</tag>
EDIT: अपडेट किए गए कार्य, जिनके हैंडल के साथ:
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
}
और दूसरा वाला:
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
}
और अंत में, rtrim, ट्रिम और इको 2 (stderr के लिए) कार्य:
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; }
ओह, और आपको पहले से परिभाषित किए जाने वाले कुछ साफ-सुथरे गतिशील चर की आवश्यकता होगी, और निर्यात भी:
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"'
या तो आप जानते हैं कि कैसे फ़ंक्शंस बनाने और उन्हें FPATH (ksh) या FPATH (बैश) के अनुकरण के माध्यम से लोड करना है
यदि नहीं, तो बस कमांड लाइन पर सब कुछ कॉपी / पेस्ट करें।
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
डीबग मोड (-d) टिप्पणियों के साथ और पार्स की गई विशेषताओं को stderr पर प्रिंट किया जाता है
./read_xml.sh: line 22: (-1): substring expression < 0
:?
[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
मुझे किसी शुद्ध शेल XML पार्सिंग टूल के बारे में जानकारी नहीं है। इसलिए आपको सबसे अधिक दूसरी भाषा में लिखे गए टूल की आवश्यकता होगी।
मेरा XML :: Twig Perl मॉड्यूल एक ऐसा उपकरण है xml_grep
, जहां आप शायद वही लिखेंगे जो आप चाहते हैं xml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt
( -t
विकल्प आपको xml के बजाय पाठ के रूप में परिणाम देता है)
एक और कमांड लाइन टूल मेरी नई Xidel है । यह पहले से उल्लेख किए गए xpath / xmlstarlet के विपरीत, XPath 2 और XQuery का भी समर्थन करता है।
शीर्षक इस तरह पढ़ा जा सकता है:
xidel xhtmlfile.xhtml -e /html/head/title > titleOfXHTMLPage.txt
और इसमें कई वैरिएबल को बैश करने के लिए निर्यात करने के लिए एक अच्छी सुविधा है। उदाहरण के लिए
eval $(xidel xhtmlfile.xhtml -e 'title := //title, imgcount := count(//img)' --output-format bash )
$title
शीर्षक और $imgcount
फ़ाइल में छवियों की संख्या के लिए सेट , जो इसे सीधे बैश में पार्स करने के समान लचीला होना चाहिए।
एक्सएमएल फाइलों में फाइल पथों के लिनक्स और विंडोज प्रारूपों के बीच अनुवाद के लिए कुछ शोध के बाद मुझे दिलचस्प ट्यूटोरियल और समाधान मिले:
हालांकि, कुछ तैयार-तैयार कंसोल उपयोगिताओं हैं जो आप जो चाहते हैं वह कर सकते हैं, संभवतः एक सामान्य प्रयोजन प्रोग्रामिंग भाषा में कोड की कुछ पंक्तियों को लिखने में कम समय लगेगा, जैसे कि पायथन जो आप आसानी से बढ़ा सकते हैं और अनुकूलित कर सकते हैं आपकी ज़रूरतें।
यहाँ एक पाइथन लिपि है जो lxml
पार्सिंग के लिए उपयोग होती है - यह पहले पैरामीटर के रूप में एक फ़ाइल या URL का नाम लेती है, दूसरे पैरामीटर के रूप में एक XPath एक्सप्रेशन, और दिए गए एक्सप्रेशन से मेल खाते स्ट्रिंग्स / नोड्स को प्रिंट करता है।
#!/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
के साथ स्थापित किया जा सकता है pip install lxml
। Ubuntu पर आप उपयोग कर सकते हैं sudo apt install python-lxml
।
python xpath.py myfile.xml "//mynode"
lxml
एक URL को इनपुट के रूप में भी स्वीकार करता है:
python xpath.py http://www.feedforall.com/sample.xml "//link"
नोट : यदि आपके XML में कोई उपसर्ग (जैसे
xmlns=http://abc...
) के साथ एक डिफ़ॉल्ट नाम स्थान है तो आपकोp
अपने भावों में उपसर्ग ('हैक' द्वारा प्रदान) का उपयोग करना होगा, जैसे//p:module
कि किसीpom.xml
फ़ाइल से मॉड्यूल प्राप्त करना । यदिp
आपके एक्सएमएल में पहले से ही उपसर्ग मैप किया गया है, तो आपको दूसरे उपसर्ग का उपयोग करने के लिए स्क्रिप्ट को संशोधित करना होगा।
एक बंद स्क्रिप्ट जो एक अपाचे मावेन फ़ाइल से मॉड्यूल नामों को निकालने के संकीर्ण उद्देश्य को पूरा करती है। ध्यान दें कि नोड नाम ( module
) डिफ़ॉल्ट नामस्थान के साथ कैसे उपसर्ग किया गया है {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>
mod_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
ओवर apt-get
या yum
कॉल को सही ठहरा सकता हूं । धन्यवाद!
फ़ंक्शन और चर असाइनमेंट में <
और >
संकेतों के क्रम को उलटाकर यूज़ेम की विधि में सुधार किया जा सकता है rdom
, ताकि:
rdom () { local IFS=\> ; read -d \< E C ;}
हो जाता है:
rdom () { local IFS=\< ; read -d \> C E ;}
यदि पार्सिंग इस तरह से नहीं की जाती है, तो XML फ़ाइल में अंतिम टैग कभी नहीं पहुंचता है। यह समस्याग्रस्त हो सकता है यदि आप while
लूप के अंत में एक और XML फ़ाइल आउटपुट करने का इरादा रखते हैं ।
यदि आप XML विशेषताएँ चाहते हैं तो यह काम करता है:
$ 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
जबकि ऐसा लगता है कि "XML पार्स कभी नहीं, JSON ... एक उचित उपकरण के बिना बैश से" ध्वनि सलाह है, मैं असहमत हूं। यदि यह साइड जॉब है, तो उचित टूल की तलाश में कमरबंद है, तो इसे सीखें ... अज़क मिनटों में कर सकते हैं। मेरे कार्यक्रमों को उपरोक्त सभी और अधिक प्रकार के डेटा पर काम करना होगा। नरक, मैं 5-7 मिनट के लिए अलग-अलग स्वरूपों को पार्स करने के लिए 30 टूल का परीक्षण नहीं करना चाहता हूं, अगर मुझे समस्या को मिनटों में जगाया जा सकता है। मुझे XML, JSON या जो भी हो उसकी परवाह नहीं है! मुझे उन सभी के लिए एक ही समाधान चाहिए।
एक उदाहरण के रूप में: मेरा स्मार्टहोम प्रोग्राम हमारे घरों को चलाता है। इसे करते समय, यह बहुत सारे अलग-अलग प्रारूपों में डेटा के ढेरों को पढ़ता है जिन्हें मैं नियंत्रित नहीं कर सकता। मैं कभी भी समर्पित, उचित साधनों का उपयोग नहीं करता हूं क्योंकि मैं उन आंकड़ों को पढ़ने में मिनटों से अधिक खर्च नहीं करना चाहता जो मुझे चाहिए। एफएस और आरएस समायोजन के साथ, यह जाग समाधान किसी भी पाठ्य प्रारूप के लिए पूरी तरह से काम करता है। लेकिन, यह उचित उत्तर नहीं हो सकता है जब आपका प्राथमिक कार्य मुख्य रूप से उस प्रारूप में डेटा के भार के साथ काम करना है!
कल टकराव से XML को पार्स करने की समस्या का सामना करना पड़ा। यहाँ मैं इसे किसी भी पदानुक्रमित डेटा प्रारूप के लिए कैसे करता हूँ। एक बोनस के रूप में - मैं डेटा को सीधे बैश स्क्रिप्ट में वेरिएबल्स में असाइन करता हूं।
पढ़ने के लिए आसान बनाने के लिए, मैं चरणों में समाधान प्रस्तुत करूंगा। ओपी परीक्षण डेटा से, मैंने एक फ़ाइल बनाई: test.xml
पार्सिंग ने एक्सएमएल को बाश में कहा और डेटा को 90 वर्णों में निकाला:
awk 'BEGIN { FS="<|>"; RS="\n" }; /host|username|password|dbname/ { print $2, $4 }' test.xml
मैं आमतौर पर अधिक पठनीय संस्करण का उपयोग करता हूं क्योंकि वास्तविक जीवन में इसे संशोधित करना आसान है क्योंकि मुझे अक्सर अलग-अलग परीक्षण करने की आवश्यकता होती है:
awk 'BEGIN { FS="<|>"; RS="\n" }; { if ($0 ~ /host|username|password|dbname/) print $2,$4}' test.xml
मुझे परवाह नहीं है कि प्रारूप को कैसे कहा जाता है। मैं केवल सबसे सरल उपाय चाहता हूं। इस विशेष मामले में, मैं डेटा से देख सकता हूं कि न्यूलाइन रिकॉर्ड सेपरेटर (आरएस) और <> सीमांकित फ़ील्ड (एफएस) है। मेरे मूल मामले में, मेरे पास दो रिकॉर्ड के भीतर 6 मानों की जटिल अनुक्रमणिका थी, उनसे संबंधित, यह ढूंढें कि डेटा कब मौजूद है (फ़ील्ड) रिकॉर्ड्स मौजूद हैं या नहीं। समस्या को पूरी तरह से हल करने के लिए जाग की 4 लाइनें लगीं। इसलिए, उपयोग करने से पहले प्रत्येक आवश्यकता के लिए विचार को अनुकूलित करें!
दूसरा भाग बस यह देखता है कि एक पंक्ति (RS) में वांछित स्ट्रिंग है और यदि ऐसा है, तो आवश्यक फ़ील्ड (FS) प्रिंट करता है। उपरोक्त ने मुझे लगभग 30 सेकंड तक कॉपी किया और अंतिम कमांड से मैंने इस तरह से उपयोग किया (4 बार लंबा)। और वह यह है! 90 वर्णों में किया गया।
लेकिन, मुझे हमेशा अपनी स्क्रिप्ट में डेटा को चर में प्राप्त करने की आवश्यकता होती है। मैं पहली बार इस तरह से निर्माणों का परीक्षण करता हूं:
awk 'BEGIN { FS="<|>"; RS="\n" }; { if ($0 ~ /host|username|password|dbname/) print $2"=\""$4"\"" }' test.xml
कुछ मामलों में मैं प्रिंट के बजाय प्रिंटफ का उपयोग करता हूं। जब मैं देखता हूं कि सब कुछ ठीक है, तो मैं बस चर मानों को असाइन करना समाप्त करता हूं। मुझे पता है कि बहुत से "बुराई" "बुराई" है, टिप्पणी करने की कोई आवश्यकता नहीं है :) सालों से मेरे चारों नेटवर्क पर ट्रिक पूरी तरह से काम करती है। लेकिन सीखते रहें अगर आपको समझ में नहीं आता है कि यह बुरा अभ्यास क्यों हो सकता है! बैश चर असाइनमेंट और पर्याप्त रिक्ति सहित, मेरे समाधान को सब कुछ करने के लिए 120 वर्णों की आवश्यकता है।
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"