MathJax

MathJax-2

MathJax-3

Google Code Prettify

置頂入手筆記

EnterproseDB Quickstart — 快速入門筆記

由於考慮採用 EnterpriseDB 或是直接用 PostgreSQL 的人,通常需要一些入手的資料。這邊紀錄便提供相關快速上手的簡單筆記 ~ 這篇筆記以 資料庫安裝完畢後的快速使用 為目標,基本紀錄登入使用的範例:

2024年1月5日 星期五

XML 設定檔的指令編輯取代小抄

對於設定檔,越來越不喜歡手工用 vi / vim 指令調整。
而是傾向先預備好,並代替成對等 sed 指令做編輯取代。
對於普通規格設定檔(等號填寫內容),這種替代搭配 regex 很合用。
但對於半結構化的檔案:XML、JSON、YAML,sed 的替代錯誤的風險會便很高。
這邊筆記的是針對 XML 的指令式編輯取代的標準手法。

半結構化格式的設定檔困擾的是,修飾符號很多,以及不能單純使用 regex 編輯取代,因為更多狀況是要用搜尋條件批配上游/下游/左右鄰兵,來鎖定要編輯的內容。
對於搜尋條件的語法,XML 稱作 XPath,JSON 稱作 JSON Path。
另外還有樣板描述(metadata),XML 的稱作 XSLT,而 JSON 的則是 JSON Schema。

對於 XML,可以用 XPath 處理的指令就是 xmllint 與 xmlstarlet 兩種指令。
xmllint 指令在 RHEL 系列可以直接透過 yum/dnf 指令安裝,而 xmlstarlet 也能以 yum/dnf 安裝,但需要從 EPEL Repo 取得。

這邊筆記的是 xmllint,平常比較容易快速取得。在 RHEL 系列應該只要從 OS 預設 Repo 裝 libxml2 套件即可。
bash-5.1# dnf provides xmllint
Last metadata expiration check: 2:26:00 ago on Fri 05 Jan 2024 04:14:09 AM UTC.
libxml2-2.9.13-1.el9.i686 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-1.el9.x86_64 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-2.el9.i686 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-2.el9.x86_64 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-3.el9.i686 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-3.el9.x86_64 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-4.el9.i686 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-4.el9.x86_64 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-5.el9.i686 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-5.el9.x86_64 : Library providing XML and HTML support
Repo        : @System
Matched from:
Filename    : /usr/bin/xmllint

libxml2-2.9.13-5.el9.x86_64 : Library providing XML and HTML support
Repo        : baseos
Matched from:
Filename    : /usr/bin/xmllint

bash-5.1# dnf install -y libxml2
...略

幾個要緊的 XPath 資訊(其他還有一些,可以後續再去了解)
  • XPath 類比 Linux 目錄路徑,將巢狀的 XML 用路徑表示指向具體位置
  • XML 的值藏在 tag 之間,以及 tag 的角括號內。角括號內藏的稱作 attribute
  • XML tag 通常成對,中間夾一個值,可以直接以路徑指到底找到
  • XML attribute 屬於 key/value 形式,能以 @ 記號抓 key 以顯示 value

xmllint 通常是用於「顯示」XPath 查詢的指令,不過 xmllint 特別提供互動式查找&編輯取代,因此利用 xmllint 代替 sed 對 XML 編輯的方式,就是以互動模式搭配 shell 的 heredoc 內容導向,把互動模式中的「指令」透過 pipe 塞給 xmllint 執行。

以下為兩個範例
  1. 一個 Log4J2 的原始 XML 設定檔
    這個範例是要簡單替換一個 attribute 的值,這個也適用變更 tag 路徑的值
    https://github.com/pentaho/pentaho-kettle/blob/master/assemblies/core/static/src/main/resources-standard/classes/log4j2.xml
  2. 一個 Tomcat 的 META-INF/context.xml 設定檔(算是 Tomcat webapps 的資料庫連線設定檔)
    這個會搭配條件,透過 XPath 的 start-with() 函數定位,在替換對應的 attribute 的值
    https://github.com/pentaho/pentaho-platform/blob/master/assemblies/pentaho-war/src/main/resources/datasources/postgresql/context.xml
  3. 修正 Maven 編譯的 pom.xml 設定檔
    這邊有 XML namespace 要指定,只用 XPath 會找不到
    https://github.com/strimzi/mirror-maker-2-extensions/blob/1.1.0/pom.xml

第一個範例:

抓檔案下來後,首先先熟悉一下 XPath 路徑表示
bash-5.1$ curl https://raw.githubusercontent.com/pentaho/pentaho-kettle/10.1.0.0-175/assemblies/core/static/src/main/resources-standard/classes/log4j2.xml -o log4j2.xml
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4636  100  4636    0     0   8681      0 --:--:-- --:--:-- --:--:--  8697
bash-5.1$ xmllint --xpath '/Configuration/Appenders/RollingFile' ./log4j2.xml
<RollingFile name="pdi-execution-appender" fileName="logs/pdi.log" filePattern="logs/pdi.%d{yyyy-MM-dd}.log">
            <PatternLayout>
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p <%t> %m%n</Pattern>
            </PatternLayout>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <DefaultRolloverStrategy/>
        </RollingFile>
bash-5.1$ xmllint --xpath '/Configuration/Appenders/RollingFile/@fileName' ./log4j2.xml
 fileName="logs/pdi.log"
bash-5.1$ 
bash-5.1$ xmllint --xpath 'string(//Configuration/Appenders/RollingFile/@fileName)' ./log4j2.xml
logs/pdi.log
bash-5.1$ 
接著是進入互動式 shell 操作確認,這個模式底下,就能夠編輯檔案&存檔了。
bash-5.1$ xmllint --shell ./log4j2.xml
/ > help
        base         display XML base of the node
        setbase URI  change the XML base of the node
        bye          leave shell
        cat [node]   display node or current node
        cd [path]    change directory to path or to root
        dir [path]   dumps information about the node (namespace, attributes, content)
        du [path]    show the structure of the subtree under path or the current node
        exit         leave shell
        help         display this help
        free         display memory usage
        load [name]  load a new document with name
        ls [path]    list contents of path or the current directory
        set xml_fragment replace the current node content with the fragment parsed in context
        xpath expr   evaluate the XPath expression in that context and print the result
        setns nsreg  register a namespace to a prefix in the XPath evaluation context
                     format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)
        setrootns    register all namespace found on the root element
                     the default namespace if any uses 'defaultns' prefix
        pwd          display current working directory
        whereis      display absolute path of [path] or current working directory
        quit         leave shell
        save [name]  save this document to name or the original name
        write [name] write the current node to the filename
        validate     check the document for errors
        relaxng rng  validate the document against the Relax-NG schemas
        grep string  search for a string in the subtree
/ > cd //Configuration/Appenders/RollingFile/@fileName
fileName > cat
 fileName="logs/pdi.log"
fileName > set "/tmp/pdi.log"
fileName > cat
 fileName=""/tmp/pdi.log""
fileName > set /tmp/pdi.log
fileName > cat
 fileName="/tmp/pdi.log"
fileName > 
fileName > quit
bash-5.1$ 
最後把上面操作做成 heredoc,以 pipe 的方式執行
bash-5.1$ export KETTLE_HOME=/opt/pentaho/
bash-5.1$ xmllint --shell ./log4j2.xml << EOF
cd //Configuration/Appenders/RollingFile/@fileName
set $KETTLE_HOME/logs/pdi.log
save
EOF
bash-5.1$ 

第二個範例:

這個其實跟上一個差不了多少,不過這邊以類比 where 條件的方式(starts-with 函數),定位所在的 XML 節點,以正確替換內容。
抓檔案下來後,就直接用互動式 shell 了~互動式 shell 可以預覽編輯,跟 vim 一樣,不要儲存就不會生效。不過我這邊還是儲存一下~
因為這份 XML 的樣貌是典型的相似內容疊在一起的狀況,這邊保留一點碰壁的操作。
bash-5.1$ curl https://raw.githubusercontent.com/pentaho/pentaho-platform/10.1.0.0-175/assemblies/pentaho-war/src/main/resources/datasources/postgresql/context.xml -o context.xml
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1350  100  1350    0     0   2132      0 --:--:-- --:--:-- --:--:--  2132
bash-5.1$ 
bash-5.1$ xmllint --shell ./context.xml
/ > cd //Context/Resource
//Context/Resource is a 3 Node Set
/ > 
/ > cd //Context/Resource[start-with(@name, "jdbc/Hibernate")]/username
xmlXPathCompOpEval: function start-with not found
XPath error : Unregistered function
//Context/Resource[start-with(@name, "jdbc/Hibernate")]/username: no such node
/ > 
/ > cd //Context/Resource[starts-with(@name, "jdbc/Hibernate")]/username
//Context/Resource[starts-with(@name, "jdbc/Hibernate")]/username is a 0 Node Set
/ > 
/ > cd //Context/Resource[starts-with(@name, "jdbc/Hibernate")]/@username
username > cat
 username="hibuser"
username > cd //Context/Resource[starts-with(@name, "jdbc/Hibernate")]/@password
password > cat
 password="password"
password > 
password > set Encrypted 2XXXXXXX86aa7f2e4bb18XXXXXX9dbdde
password > cat
 password="Encrypted 2XXXXXXX86aa7f2e4bb18XXXXXX9dbdde"
password > 
password > save
password > quit
bash-5.1$ 
bash-5.1$ cat ./context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/pentaho" docbase="webapps/pentaho/">
    <Resource name="jdbc/Hibernate" auth="Container" type="javax.sql.DataSource" factory="org.pentaho.di.core.database.util.DecryptingDataSourceFactory" maxActive="20" minIdle="0" maxIdle="5" initialSize="0" maxWait="10000" username="hibuser" password="Encrypted 2XXXXXXX86aa7f2e4bb18XXXXXX9dbdde" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/hibernate" validationQuery="select 1" jdbcInterceptors="ConnectionState" defaultAutoCommit="true"/>
    <Resource name="jdbc/Quartz" auth="Container" type="javax.sql.DataSource" factory="org.pentaho.di.core.database.util.DecryptingDataSourceFactory" maxActive="20" minIdle="0" maxIdle="5" initialSize="0" maxWait="10000" username="pentaho_user" password="password" testOnBorrow="true" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/quartz" validationQuery="select 1"/>
    <Resource name="jdbc/jackrabbit" auth="Container" type="javax.sql.DataSource" factory="org.pentaho.di.core.database.util.DecryptingDataSourceFactory" maxActive="20" minIdle="0" maxIdle="5" initialSize="0" maxWait="10000" username="jcr_user" password="password" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/jackrabbit" validationQuery="select 1" jdbcInterceptors="ConnectionState" defaultAutoCommit="true"/>
</Context>
bash-5.1$ 
一樣,可以把上面的指令操作匯總成 script,以 heredoc 執行
bash-5.1$ xmllint --shell $KETTLE_HOME/pentaho-server/tomcat/webapps/pentaho/META-INF/context.xml << EOSHL
cd //Context/Resource[starts-with(@name, "jdbc/Quartz")]/@username
set Encrypted 2XXXXXXX86aa7f2e4bb18XXXXXX9dbdde
cd //Context/Resource[starts-with(@name, "jdbc/jackrabbit")]/@username
set Encrypted 2XXXXXXX86aa7f2e4bb18XXXXXX9dbdde
save
quit
EOSHL
bash-5.1$ 

第三個範例:

通常 Maven 有相依性,會寫在 pom.xml 檔案內,有時會希望更新相依性。
這邊的操作範例要把 Apache Kafka 版本更正。
bash-5.1$ xmllint --xpath "/*[local-name()='project' and namespace-uri()='http://maven.apache.org/POM/4.0.0']/*[local-name()='groupId']" ./mirror-maker-2-extensions-1.1.0/pom.xml
<groupId>io.strimzi</groupId>
bash-5.1$ 
bash-5.1$ xmllint --xpath "/*[local-name()='project' and namespace-uri()='http://maven.apache.org/POM/4.0.0']/*[local-name()='dependencies']/*[local-name()='dependency']/*[local-name()='groupId']" ./mirror-maker-2-extensions-1.1.0/pom.xml
<groupId>org.apache.kafka</groupId>
<groupId>org.apache.kafka</groupId>
<groupId>org.slf4j</groupId>
bash-5.1$ xmllint --shell pom.xml << EOCMD
setns ns=http://maven.apache.org/POM/4.0.0
cat /ns:project/ns:dependencies/ns:dependency/ns:groupId/text()
EOCMD
/ > / >  -------
org.apache.kafka
 -------
org.apache.kafka
 -------
org.slf4j
/ > bash-5.1$ 
bash-5.1$ xmllint --shell ./mirror-maker-2-extensions-1.1.0/pom.xml << EOCMD
setns ns=http://maven.apache.org/POM/4.0.0
cat /ns:project/ns:dependencies/ns:dependency/ns:groupId       
EOCMD
/ > / >  -------
<groupId>org.apache.kafka</groupId>
 -------
<groupId>org.apache.kafka</groupId>
 -------
<groupId>org.slf4j</groupId>
/ > bash-5.1$ 
bash-5.1$ 
bash-5.1$ xmllint --shell ./mirror-maker-2-extensions-1.1.0/pom.xml << EOCMD
setns ns=http://maven.apache.org/POM/4.0.0
cat /ns:project/ns:properties/ns:kafka.version
quit
EOCMD
/ > / >  -------
<kafka.version>3.0.0</kafka.version>
/ > bash-5.1$ 
bash-5.1$ 
bash-5.1$ xmllint --shell ./mirror-maker-2-extensions-1.1.0/pom.xml << EOCMD
setns ns=http://maven.apache.org/POM/4.0.0
cd /ns:project/ns:properties/ns:kafka.version
set 2.6.0
cd /ns:project/ns:properties/ns:maven.compiler.version
set 3.6.2
cd /ns:project/ns:properties/ns:maven.compiler.source
set 11
cd /ns:project/ns:properties/ns:maven.compiler.target
set 11
save
quit
EOCMD
/ > / > kafka.version > kafka.version > maven.compiler.version > maven.compiler.version > maven.compiler.source > maven.compiler.source > maven.compiler.target > maven.compiler.target > maven.compiler.target > bash-5.1$ 
bash-5.1$ 
bash-5.1$ xmllint --shell ./mirror-maker-2-extensions-1.1.0/pom.xml << EOCMD
setns ns=http://maven.apache.org/POM/4.0.0
cat /ns:project/ns:properties/ns:kafka.version
quit
EOCMD
/ > / >  -------
<kafka.version>2.6.0</kafka.version>
/ > bash-5.1$ 
bash-5.1$ 


有了這個對比 sed 的手法,湊小抄就更便利了~
之後在看看 jq 如何對 JSON 達成相似的處理~

參考資料
類比 where 條件的方式(starts-with 函數)
XPath 語法
JSON 的對等指令 jq 也有 startwith() 語法

沒有留言:

張貼留言