使用xmlstarlet提取XML值时如何为缺失元素返回对应空值
问题描述
我现在正在处理名为extract.BCBR.job.xml的XML文件,当前用如下xmlstarlet命令提取APPL_TYPE为"PS8"的JOB节点下,NAME属性为%%PS8-PROCESSES-J1-P2-PROCESSNAME的VARIABLE元素的VALUE属性值:
xmlstarlet sel -t -m '//JOB[@APPL_TYPE="PS8"]/VARIABLE[@NAME="%%PS8-PROCESSES-J1-P2-PROCESSNAME"]' -v './@VALUE' -n ~testhwa/extract.BCBR.job.xml >> /tmp/prcsname_2
该命令在目标元素存在时可以正常运行,但我的需求是:当匹配的JOB节点下不存在目标VARIABLE元素时,也向输出文件/tmp/prcsname_2返回空值(空行)。我后续会用for循环遍历该输出文件700余次,空值可以支撑后续的if-else条件判断逻辑。
示例输入
<?xml version='1.0' encoding='UTF-8' ?> <!-- XML Utils Details: version 9.0.0. Exported at 20210503-130101 by rfernan9 from server DEV --> <DEFTABLE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Folder.xsd"> <FOLDER DATACENTER="DEV" FOLDER_NAME="DVFINAL" LAST_UPLOAD="20101206223355UTC" PLATFORM="UNIX" REAL_FOLDER_ID="0" TYPE="1" USED_BY_CODE="0" VERSION="919"> <JOB APPLICATION="DVPeopleSoft_Finance" APPL_FORM="PEOPLESOFT" APPL_TYPE="PS8" APPL_VER="8" APR="1" AUG="1" AUTOARCH="0" CM_VER="6.1.01" CONFIRM="0" CREATED_BY="prichar3" CREATION_DATE="20101206" CREATION_TIME="163137" CREATION_USER="prichar3" CRITICAL="0" CYCLIC="0" CYCLIC_TOLERANCE="0" CYCLIC_TYPE="C" DAYSCAL="02/05/2009" DAYS_AND_OR="O" DEC="1" DESCRIPTION="origtasktype=Command, "Daily Close GL Reports "" FEB="1" IND_CYCLIC="T" INTERVAL="00001M" JAN="1" JOBISN="3" JOBNAME="PFD_GLR01DLY_PF_RPTBOOK-01A" JUL="1" JUN="1" MAR="1" MAXDAYS="0" MAXRERUN="0" MAXRUNS="0" MAXWAIT="0" MAY="1" MEMNAME="PFD_GLR01DLY_PF_RPTBOOK-01A" MULTY_AGENT="N" NODEID="FS90QAT1" NOV="1" OCT="1" PARENT_FOLDER="DVPeopleSoft_Finance" RETRO="0" RUN_AS="CONTROLM" SEP="1" SHIFT="Ignore Job" SHIFTNUM="+00" SUB_APPLICATION="PFD_GLR01DLY" SYSDB="0" TASKTYPE="Dummy" USE_INSTREAM_JCL="N" WEEKSCAL="03/05/2009"> <INCOND AND_OR="A" NAME="start_FS90QAT#PFD_GLR01DLY-OK" ODATE="ODAT"/> <OUTCOND NAME="FS90QAT#PFD_GLR01DLY_PF_RPTBOOK-01A-OK" ODATE="ODAT" SIGN="+"/> <VARIABLE NAME="%%PS8-CON_PROFILE" VALUE="QAT"/> <VARIABLE NAME="%%PS8-USERID" VALUE="CONTROLM"/> <VARIABLE NAME="%%PS8-RUNCONTROLID" VALUE="GLR01DLY1"/> <VARIABLE NAME="%%PS8-PRCSTYPE" VALUE="nVision-ReportBook"/> <VARIABLE NAME="%%PS8-PRCSNAME" VALUE="RPTBK01"/> <VARIABLE NAME="%%PS8-APOUT" VALUE="1"/> </JOB> <JOB APPLICATION="DVPeopleSoft_Finance" APPL_FORM="PEOPLESOFT" APPL_TYPE="PS8" APPL_VER="8" APR="1" AUG="1" AUTOARCH="0" CM_VER="6.1.01" CONFIRM="0" CREATED_BY="stamilar" CREATION_DATE="20131106" CREATION_TIME="110438" CREATION_USER="stamilar" CRITICAL="0" CYCLIC="0" CYCLIC_TOLERANCE="0" DAYS="ALL" DAYS_AND_OR="O" DEC="1" DESCRIPTION="origtasktype=Command, "Pcard paycycle USA"" FEB="1" INTERVAL="00001M" JAN="1" JOBISN="1" JOBNAME="PFD_SP01DLY_AP_PF_PC_USA" JUL="1" JUN="1" MAR="1" MAXDAYS="0" MAXRERUN="0" MAXRUNS="0" MAXWAIT="0" MAY="1" MEMLIB="Not in use for PeopleSoft jobs" MEMNAME="PFD_SP01DLY_AP_PF_PC_USA" MULTY_AGENT="N" NOV="1" OCT="1" PARENT_FOLDER="DVPeopleSoft_Finance_AP" RETRO="0" RUN_AS="BATCH" SEP="1" SHIFT="Ignore Job" SHIFTNUM="+00" SUB_APPLICATION="PFD_SP01DLY_AP_PF" SYSDB="0" TASKTYPE="Job" TIMEFROM="1900" USE_INSTREAM_JCL="N" WEEKDAYS="ALL"> <OUTCOND NAME="PFD_SP01DLY_AP_PF_PC_USA-OK" ODATE="ODAT" SIGN="+"/> <VARIABLE NAME="%%PS8-CON_PROFILE" VALUE="FS90QAT"/> <VARIABLE NAME="%%PS8-USERID" VALUE="BATCH"/> <VARIABLE NAME="%%PS8-RUNCONTROLID" VALUE="PC_USA"/> <VARIABLE NAME="%%PS8-SERVERNAME" VALUE="PSUNX"/> <VARIABLE NAME="%%PS8-PRCSTYPE" VALUE="PSJob"/> <VARIABLE NAME="%%PS8-APOUT" VALUE="1"/> <VARIABLE NAME="%%PS8-OUTDESTFORMAT" VALUE="HTM"/> <VARIABLE NAME="%%PS8-OUTDESTTYPE" VALUE="Web"/> <VARIABLE NAME="%%PS8-JOBNAME" VALUE="APPCJOB"/> <VARIABLE NAME="%%PS8-DESCRIPTION" VALUE="PayCycle Job"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P1-DESCRIPTION" VALUE="PayCycle Job"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P1-PROCESSNAME" VALUE="APPCJOB"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P1-PROCESSTYPE" VALUE="PSJob"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P2-DESCRIPTION" VALUE="Pay Cycle Process"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P2-PROCESSNAME" VALUE="AP_APY2015"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P2-PROCESSTYPE" VALUE="Application Engine"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P3-DESCRIPTION" VALUE="Pay Cycle Job Finalize"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P3-PROCESSNAME" VALUE="ZPV_FINALIZE"/> <VARIABLE NAME="%%PS8-PROCESSES-J1-P3-PROCESSTYPE" VALUE="Application Engine"/> </JOB>
期望输出
<空行> AP_APY2015
解决方案
xmlstarlet原生支持该需求,只需调整匹配逻辑即可实现。
修改后命令
xmlstarlet sel -t -m '//JOB[@APPL_TYPE="PS8"]' \ -v './VARIABLE[@NAME="%%PS8-PROCESSES-J1-P2-PROCESSNAME"]/@VALUE' \ -n ~testhwa/extract.BCBR.job.xml >> /tmp/prcsname_2
逻辑说明
- 原命令的匹配维度是VARIABLE节点,不存在目标VARIABLE的JOB会被直接过滤,无任何输出
- 调整后匹配维度改为所有
APPL_TYPE="PS8"的JOB节点,每个JOB都会触发一次输出逻辑:存在目标VARIABLE时输出其VALUE属性值,不存在时输出空字符串 - 末尾的
-n参数会为每一次输出追加换行,空字符串加换行就对应所需的空行
兼容性优化(可选)
如果使用的xmlstarlet版本较低,匹配为空时不输出空字符串,可以改用带显式判断的XPath表达式,逻辑更稳妥:
xmlstarlet sel -t -m '//JOB[@APPL_TYPE="PS8"]' \ -v 'if (./VARIABLE[@NAME="%%PS8-PROCESSES-J1-P2-PROCESSNAME"]) then ./VARIABLE[@NAME="%%PS8-PROCESSES-J1-P2-PROCESSNAME"]/@VALUE else ""' \ -n ~testhwa/extract.BCBR.job.xml >> /tmp/prcsname_2
内容的提问来源于stack exchange,提问作者sriram2207
相关产品推荐
相关产品推荐

