我有一个像这样的平面文件:
File:
# Environment
Application.Env~DEV
# Identity
Application.ID~999
# Name
Application.Name~appname
像这样的XML:
<name>Application/Env</name>
<value>XXX</value>
<name>Application/ID</name>
<value>000</value>
<name>Application/Name</name>
<value>AAA</value>
我正在寻找一个脚本(awk,sed等)来读取平面文件,并将xml中<value>
标签中的所有数据替换为〜{{1后标签匹配〜之前的数据。最终生成的XML将如下所示:
<name>
感谢您的帮助!
答案 0 :(得分:4)
使用XMLStarlet,看起来如下所示:
#!/bin/bash
# usage: [script] [flatfile-name] <in.xml >out.xml
flatfile=$1
# store an array of variables, and an array of edit commands
xml_vars=( )
xml_cmd=( )
count=0
while read -r line; do
[[ $line = *"~"* ]] || continue
key=${line%%"~"*} # put everything before the ~ into key
key=${key//"."/"/"} # change "."s to "/"s in key
val=${line#*"~"} # put everything after the ~ into val
# assign key to an XMLStarlet variable to avoid practices that can lead to injection
xml_vars+=( --var "var$count" "'$key'" )
# update the first value following a matching name
xml_cmd+=( -u "//name[.=\$var${count}]/following-sibling::value[1]" \
-v "$val" )
# increment the counter used to assign variable names
(( ++count ))
done <"$flatfile"
if (( ${#xml_cmd[@]} )); then
xmlstarlet ed "${xml_vars[@]}" "${xml_cmd[@]}"
else
cat # no edits to do
fi
这将运行如下命令:
xmlstarlet ed \
--var var0 "Application/Env" \
--var var2 "Application/ID" \
--var var3 "Application/Name" \
-u '//name[.=$var0]/following-sibling::value[1]' -v 'DEV' \
-u '//name[.=$var1]/following-sibling::value[1]' -v '999' \
-u '//name[.=$var2]/following-sibling::value[1]' -v 'appname'
...将名称Application/Env
后的第一个值替换为DEV
,名称Application/ID
后的第一个值替换为999
,第一个值替换为Application/Name
后的第一个值使用appname
命名//name[.="Application/Name"]/following-sibling::value[1]
。
稍微偏执的方法可能会生成像Application.Foo"or 1=1 or .="~bar
这样的查询;作为安全措施,正在遵循带外变量。如果输入文件包含:
//name[.="Application/Foo" or 1=1 or .=""]/following-sibling::value[1]
...而得到的XPath是
1=1
由于bar
始终为true,因此会匹配每个名称,从而将文件中的每个值更改为var a, b, c, d;
var uva, uvb, uvc, uvd;
var uvs = this.faceVertexUvs[ 0 ];
for ( i = 0; i < stacks; i ++ ) {
for ( j = 0; j < slices; j ++ ) {
a = i * sliceCount + j;
b = i * sliceCount + j + 1;
c = ( i + 1 ) * sliceCount + j + 1;
d = ( i + 1 ) * sliceCount + j;
uva = new THREE.Vector2( j / slices, i / stacks );
uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks );
uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks );
uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks );
faces.push( new THREE.Face3( a, b, d ) );
uvs.push( [ uva, uvb, uvd ] );
faces.push( new THREE.Face3( b, c, d ) );
uvs.push( [ uvb.clone(), uvc, uvd.clone() ] );
}
}
。< / p>
不幸的是,XMLStarlet的实现并没有有效地防范这种情况;但是,使用绑定变量使得成为可能以便实现提供这样的预防措施,因此在此背景下未来的发布可能是安全的。
答案 1 :(得分:1)
使用Perl和XML::XSH2,XML::LibXML的包装:
#!/usr/bin/perl
use warnings;
use strict;
use XML::XSH2;
open my $IN, '<', 'flatfile' or die $!;
$XML::XSH2::Map::replace = { map { chomp; split /~/ } grep /~/, <$IN> };
xsh << 'end.';
open 1.xml ;
for //name {
set following-sibling::value[1]
xsh:lookup('replace', xsh:subst(., '/', '.')) ;
}
save :b ;
end.
我将XML打包到<root>
标记中以使其格式良好。