पार्स एक्सएमएल को बैश स्क्रिप्ट में नोड मूल्य प्राप्त करने के लिए?


19

मैं जानना चाहूंगा कि मैं निम्नलिखित रास्तों के साथ नोड का मूल्य कैसे प्राप्त कर सकता हूं:

config/global/resources/default_setup/connection/host
config/global/resources/default_setup/connection/username
config/global/resources/default_setup/connection/password
config/global/resources/default_setup/connection/dbname

निम्नलिखित XML से:

<?xml version="1.0"?>
<config>
    <global>
        <install>
            <date><![CDATA[Tue, 11 Dec 2012 12:31:25 +0000]]></date>
        </install>
        <crypt>
            <key><![CDATA[70e75d7969b900b696785f2f81ecb430]]></key>
        </crypt>
        <disable_local_modules>false</disable_local_modules>
        <resources>
            <db>
                <table_prefix><![CDATA[]]></table_prefix>
            </db>
            <default_setup>
                <connection>
                    <host><![CDATA[localhost]]></host>
                    <username><![CDATA[root]]></username>
                    <password><![CDATA[pass123]]></password>
                    <dbname><![CDATA[testdb]]></dbname>
                    <initStatements><![CDATA[SET NAMES utf8]]></initStatements>
                    <model><![CDATA[mysql4]]></model>
                    <type><![CDATA[pdo_mysql]]></type>
                    <pdoType><![CDATA[]]></pdoType>
                    <active>1</active>
                </connection>
            </default_setup>
        </resources>
        <session_save><![CDATA[files]]></session_save>
    </global>
    <admin>
        <routers>
            <adminhtml>
                <args>
                    <frontName><![CDATA[admin]]></frontName>
                </args>
            </adminhtml>
        </routers>
    </admin>
</config>

इसके अलावा मैं आगे के उपयोग के लिए वैरिएबल को उस मूल्य को असाइन करना चाहता हूं। मुझे अपने विचार बताएं।


7
मनमाने डेटा के संरचित पेड़ों को पार्स करने के लिए कभी भी बैश का उपयोग न करें। एक वास्तविक XML पार्सर का उपयोग करें। मैं XMLStarlet की सलाह देता हूं
क्रिस डाउन

जवाबों:


19

का उपयोग करते हुए bashऔर xmllint(के रूप में टैग द्वारा दिए गए):

xmllint --version  #  xmllint: using libxml version 20703

# Note: Newer versions of libxml / xmllint have a --xpath option which 
# makes it possible to use xpath expressions directly as arguments. 
# --xpath also enables precise output in contrast to the --shell & sed approaches below.
#xmllint --help 2>&1 | grep -i 'xpath'

{
# the given XML is in file.xml
host="$(echo "cat /config/global/resources/default_setup/connection/host/text()" | xmllint --nocdata --shell file.xml | sed '1d;$d')"
username="$(echo "cat /config/global/resources/default_setup/connection/username/text()" | xmllint --nocdata --shell file.xml | sed '1d;$d')"
password="$(echo "cat /config/global/resources/default_setup/connection/password/text()" | xmllint --nocdata --shell file.xml | sed '1d;$d')"
dbname="$(echo "cat /config/global/resources/default_setup/connection/dbname/text()" | xmllint --nocdata --shell file.xml | sed '1d;$d')"
printf '%s\n' "host: $host" "username: $username" "password: $password" "dbname: $dbname"
}

# output
# host: localhost
# username: root
# password: pass123
# dbname: testdb

मामले में सिर्फ एक XML स्ट्रिंग है और एक अस्थायी फ़ाइल के उपयोग से बचना है, फ़ाइल डिस्क्रिप्टर के साथ जाने का तरीका है xmllint(जो कि /dev/fd/3यहां फ़ाइल तर्क के रूप में दिया गया है):

set +H
{
xmlstr='<?xml version="1.0"?>
<config>
    <global>
        <install>
            <date><![CDATA[Tue, 11 Dec 2012 12:31:25 +0000]]></date>
        </install>
        <crypt>
            <key><![CDATA[70e75d7969b900b696785f2f81ecb430]]></key>
        </crypt>
        <disable_local_modules>false</disable_local_modules>
        <resources>
            <db>
                <table_prefix><![CDATA[]]></table_prefix>
            </db>
            <default_setup>
                <connection>
                    <host><![CDATA[localhost]]></host>
                    <username><![CDATA[root]]></username>
                    <password><![CDATA[pass123]]></password>
                    <dbname><![CDATA[testdb]]></dbname>
                    <initStatements><![CDATA[SET NAMES utf8]]></initStatements>
                    <model><![CDATA[mysql4]]></model>
                    <type><![CDATA[pdo_mysql]]></type>
                    <pdoType><![CDATA[]]></pdoType>
                    <active>1</active>
                </connection>
            </default_setup>
        </resources>
        <session_save><![CDATA[files]]></session_save>
    </global>
    <admin>
        <routers>
            <adminhtml>
                <args>
                    <frontName><![CDATA[admin]]></frontName>
                </args>
            </adminhtml>
        </routers>
    </admin>
</config>
'

# exec issue
#exec 3<&- 3<<<"$xmlstr"
#exec 3<&- 3< <(printf '%s' "$xmlstr")
exec 3<&- 3<<EOF
$(printf '%s' "$xmlstr")
EOF

{ read -r host; read -r username; read -r password; read -r dbname; } < <(
       echo "cat /config/global/resources/default_setup/connection/*[self::host or self::username or self::password or self::dbname]/text()" | 
          xmllint --nocdata --shell /dev/fd/3 | 
          sed -e '1d;$d' -e '/^ *--* *$/d'
       )

printf '%s\n' "host: $host" "username: $username" "password: $password" "dbname: $dbname"

exec 3<&-
}
set -H


# output
# host: localhost
# username: root
# password: pass123
# dbname: testdb


6

हालांकि पहले से ही बहुत सारे उत्तर हैं, मैं इसमें झंकार करूंगा xml2

$ xml2 < test.xml
/config/global/install/date=Tue, 11 Dec 2012 12:31:25 +0000
/config/global/crypt/key=70e75d7969b900b696785f2f81ecb430
/config/global/disable_local_modules=false
/config/global/resources/db/table_prefix
/config/global/resources/default_setup/connection/host=localhost
/config/global/resources/default_setup/connection/username=root
/config/global/resources/default_setup/connection/password=pass123
/config/global/resources/default_setup/connection/dbname=testdb
/config/global/resources/default_setup/connection/initStatements=SET NAMES utf8
/config/global/resources/default_setup/connection/model=mysql4
/config/global/resources/default_setup/connection/type=pdo_mysql
/config/global/resources/default_setup/connection/pdoType
/config/global/resources/default_setup/connection/active=1
/config/global/session_save=files
/config/admin/routers/adminhtml/args/frontName=admin

थोड़े से जादू से आप उन्हें सीधे चर के रूप में भी सेट कर सकते हैं:

$ eval $(xml2 < test.xml | tr '/, ' '___' | grep =)
$ echo $_config_global_resources_default_setup_connection_host          
localhost

3

आपके परीक्षण डेटा के विरुद्ध चलने पर निम्नलिखित कार्य:

{ read -r host; read -r username; read -r password; read -r dbname; } \
  < <(xmlstarlet sel -t -m /config/global/resources/default_setup/connection \
      -v ./host -n \
      -v ./username -n \
      -v ./password -n \
      -v ./dbname -n)

इस चर में सामग्री डालता है host, username, passwordऔर dbname


xmlstarlet: कमांड नहीं मिली, इसलिए यह कमांड मेरे लिए उपयोगी नहीं है :(
MagesPycho

@MagePycho bashमें XML पार्सिंग के लिए कोई अंतर्निहित समर्थन नहीं है। आपको या तो एक उपकरण होना चाहिए जो (xmlstarlet, xsltproc, एक आधुनिक पायथन, आदि) करता है, या आप XML को सही तरीके से पार्स नहीं कर सकते।
चार्ल्स डफी

@CharlesDuffy regex पैटर्न या किसी और का उपयोग करने का एक तरीका हो सकता है?
माजेप्सिको 12

5
@MagePsycho आप सिर्फ xmlstarlet स्थापित कर सकते हैं। किसी भी स्थिति में, आपको कभी भी HTML (पृष्ठ) को पार्स करने के लिए नियमित अभिव्यक्ति का उपयोग नहीं करना चाहिए ।
terdon

1
@MagePycho मैं उसी लिंक को पोस्ट करने वाला था, जो पहले ही किया था। संक्षेप में: नहीं
चार्ल्स डफी

3

एक शुद्ध bashकार्य, दुर्भाग्यपूर्ण मामले के लिए जब आपको कुछ भी उपयुक्त स्थापित करने की अनुमति नहीं है। यह और अधिक जटिल XML पर शायद विफल हो जाएगा:

function xmlpath()
{
  local expr="${1//\// }"
  local path=()
  local chunk tag data

  while IFS='' read -r -d '<' chunk; do
    IFS='>' read -r tag data <<< "$chunk"

    case "$tag" in
      '?'*) ;;
      '!–-'*) ;;
      '![CDATA['*) data="${tag:8:${#tag}-10}" ;;
      ?*'/') ;;
      '/'?*) unset path[${#path[@]}-1] ;;
      ?*) path+=("$tag") ;;
    esac

    [[ "${path[@]}" == "$expr" ]] && echo "$data"
  done
}

उपयोग:

bash-4.1$ xmlpath 'config/global/resources/default_setup/connection/host' < MagePsycho.xml
localhost

ज्ञात पहलु:

  • धीमा
  • केवल टैग नामों से खोज करता है
  • कोई चरित्र इकाई डिकोडिंग नहीं

2

का उपयोग करते हुए xmllint और --xpath विकल्प है, यह बहुत आसान है। आप बस यह कर सकते हैं:

XML_FILE=/path/to/file.xml

HOST=$(xmllint --xpath 'string(/config/global/resources/default_setup/connection/host)' $XML_FILE
USERNAME=$(xmllint --xpath 'string(/config/global/resources/default_setup/connection/username)' $XML_FILE
PASSWORD=$(xmllint --xpath 'string(/config/global/resources/default_setup/connection/password)' $XML_FILE 
DBNAME=$(xmllint --xpath 'string(/config/global/resources/default_setup/connection/dbname)' $XML_FILE

यदि आपको किसी तत्व की विशेषता प्राप्त करने की आवश्यकता है, तो XPath का उपयोग करना भी आसान है। कल्पना कीजिए कि आपके पास फाइल है:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="screensaver.turnoff"
       name="Turn Off"
       version="0.10.0"
       provider-name="Dag Wieërs">
  ..snip..
</addon>

आवश्यक शेल स्टेटमेंट होंगे:

VERSION=$(xmllint --xpath 'string(/addon/@version)' $ADDON_XML)
AUTHOR=$(xmllint --xpath 'string(/addon/@provider-name)' $ADDON_XML)

0

आप कई जटिल लिपियों को संभालने के लिए bash स्क्रिप्ट में php कमांड लाइन इंटरफेस कोडिंग का उपयोग कर सकते हैं जो वास्तव में कोडिंग की कई लाइनों पर फैले हुए हैं। सबसे पहले, PHP स्क्रिप्ट का उपयोग करके अपना समाधान बनाने की कोशिश करें, और फिर बाद में सीएलआई मोड का उपयोग करके मापदंडों को पास करें। इस प्रकार, आप XML पार्सर के शानदार उपयोगों पर नियंत्रण पा सकते हैं।

पर्यावरण को लगता है कि आप क्लाइंट मोड में ssh / शेल एक्सेस के माध्यम से PHP का उपयोग कर सकते हैं।

php -f yourxmlparser.php

अब, अपने php फ़ाइल के भीतर सभी चीजें करें। कमांड लाइन पैरामीटर्स का उपयोग कर सकते हैं।

आप अपनी शेल स्क्रिप्ट के बाकी हिस्सों को जारी रखने के लिए शेल वातावरण में मान भी लौटा सकते हैं।

और दूसरा तरीका उपयोग करना है। grep विकल्प xml फ़ाइल के भीतर आपके आवश्यक मूल्य से मेल खाता है, यदि आप अपनी xml फ़ाइल की संरचना के बारे में सुनिश्चित हैं जो समय के साथ नहीं बदलता है।


0

यह टिप्पणी केवल श / बश कमांड और विधियों का उपयोग करती है! /test.xml आपकी XML टाइप फ़ाइल है पहले प्रश्न पर ...

#!/bin/sh

cat /test.xml | while read line;do
[ "$(echo "$line" | grep "<host>")" ]&& echo "host: $(echo $line |  cut -f3 -d'[' | cut -f1 -d']')"
[ "$(echo "$line" | grep "<username>")" ]&& echo "username: $(echo $line |  cut -f3 -d'[' | cut -f1 -d']')"
[ "$(echo "$line" | grep "<password>")" ]&& echo "password: $(echo $line |  cut -f3 -d'[' | cut -f1 -d']')"
[ "$(echo "$line" | grep "<dbname")" ]&& echo "dbname: $(echo $line |  cut -f3 -d'[' | cut -f1 -d']')"
done

उत्पादन:

host: localhost
username: root
password: pass123
dbname: testdb

अगर आप इस विधि का उपयोग करने के लिए इस मान को लिखना चाहते हैं:

#!/bin/sh

cat /test.xml | while read line;do
[ "$(echo "$line" | grep "<host>")" ]&& echo "$line" |  cut -f3 -d'[' | cut -f1 -d']' > /config/global/resources/default_setup/connection/host
[ "$(echo "$line" | grep "<username>")" ]&& echo "$line" |  cut -f3 -d'[' | cut -f1 -d']' > /config/global/resources/default_setup/connection/username
[ "$(echo "$line" | grep "<password>")" ]&& echo "$line" |  cut -f3 -d'[' | cut -f1 -d']' > /config/global/resources/default_setup/connection/password
[ "$(echo "$line" | grep "<dbname")" ]&& echo "$line" |  cut -f3 -d'[' | cut -f1 -d']' > /config/global/resources/default_setup/connection/dbname
done

यह विधि केवल आपके मूल्यों को प्राप्त करने के लिए उपयोग की जाने वाली आपकी स्थानीय फ़ाइलों को अधिलेखित कर देगी (आपका डेटा आउटपुट फ़ाइलों से खो जाएगा)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.