使用.xml文件中的值更新.properties文件

时间:2017-11-21 11:27:45

标签: xml shell xmlstarlet

以下xmlstarlet命令:

./xmlstarlet-1.5.0/xml.exe fo --dropdtd $filename | ./xmlstarlet-1.5.0/xml.exe sel -t -m "//DOC//PTXT" -v "concat(./@ID,' ', .)"

返回多个结果,因为我的文件包含大量doc/ptxt。我需要对每个输出做一些事情,更明确地我需要对每个ptxt值做一些事情。如何循环浏览XMLstarlet的所有结果?

我的输出类似于:

my.id.one Text I need 
my.id.two Text I also need
my.id.three Surprisingly I need this text too

我需要的是让每个id-text对可能包含两个变量idtext,因为我有另一个包含id-value对的文件,我需要匹配那些对。

更新1:

我需要做的具体例子: 我有档案X.xml和档案Y.properties 文件X.xml具有以下结构:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE DOC SYSTEM "ts.dtd">
<?xml-stylesheet type="text/css" href="ts.css"?>
<DOC LOCALE="en-US"> 
    <PTXT ID="text.something">Open door</PTXT> 
    <PTXT ID="text.something.else">Open another door</PTXT>
    <PTXT ID="text.whatever">Close all</PTXT>
</DOC>

文件Y.properties具有以下结构:

text.something=Open window
text.something.else=Open another door

我期望的结果是Y.properties这个内容:

text.something=Open door
text.something.else=Open another door
text.whatever=Close all

待办事项:

  • 如果valueid的{​​{1}}与X.xmlvalue的{​​{1}}不同,key来自Y.properties value中的{1}}应该更新。
  • 如果keyY.properties的{​​{1}}与valueid的{​​{1}}相同,则无需执行任何操作
  • 如果X.xmlvalue的{​​{1}}在key中不在Y.properties,则应将idX.xml添加到key {1}}

我目前的shell代码是:

Y.properties

当前只从X.xml获取每个id /值并打印到std输出。 您可能怀疑value就在那里,因为我有多个X.xmlY.properties我必须执行此代码。

问题1: @janos我有以下问题,我真的不明白为什么。一切正常,但很少有人没有。例: X.xml:

for filename in C:/Temp/XLocation/*.xml; do
        ./xmlstarlet-1.5.0/xml.exe fo --dropdtd $filename | ./xmlstarlet-1.5.0/xml.exe sel -t -m "//DOC//PTXT" -v "concat(./@ID,' ', .)"
done

Y.properties:

for

我的输出是:

X.xml

请你帮助我,因为我真的不明白发生了什么。

问题2: 有以下输入: X.xml

Y.properties

和Y.properties

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE DOC SYSTEM "ts.dtd">
<?xml-stylesheet type="text/css" href="ts.css"?>
<DOC> 
<PTXT ID="a.b.c.d" CONTEXT="label"><NTI>Text</NTI></PTXT>
</DOC>

导致: out.properties

a.b.c.d=Text

而不是

a.b.c.d=
    Text=
=

1 个答案:

答案 0 :(得分:1)

首先生成与Y.properties中的格式匹配的数据:

xmlstarlet fo --dropdtd a.xml | \
  xmlstarlet sel -t -m "//DOC//PTXT" -v $'concat(@ID, "=", ., "\n")'

对于你的例子,这会产生:

text.something=Open door
text.something.else=Open another door
text.whatever=Close all

然后您可以使用Awk执行以下逻辑:

  • 使用上一个命令的输出作为第一个文件 -
  • 使用Y.properties作为第二个文件
  • 逐行处理,使用=作为分隔符,并使用简单的逻辑构建键值对的映射:如果键不在映射中,则添加键值对。 因为我们首先得到xmlstarlet输出的行, 上面的逻辑会将所有这些值添加到映射中。 当我们处理第二个文件(Y.properties)的行时, 其键已经在地图中的行将被忽略, 但是会添加新的键值对。

像这样:

xmlstarlet fo --dropdtd a.xml | \
  xmlstarlet sel -t -m "//DOC//PTXT" -v $'concat(@ID, "=", ., "\n")' | \
  awk -F= '!($1 in m) { m[$1] = $2 }
           END { for (key in m) { print key "=" m[key] } }' - Y.properties

您可以将输出重定向到所需的目标文件。

要对多个文件执行上述操作, 你可以将上面的代码包装在一个函数中, 有适当的参数。 例如:

mergeprops() {
    local filename=$1
    local propsfile=$2
    local out=$3

    xmlstarlet fo --dropdtd "$filename" | \
      xmlstarlet sel -t -m "//DOC//PTXT" -v $'concat(@ID, "=", ., "\n")' | \
      awk -F= '!($1 in m) { m[$1] = $2 }
               END { for (key in m) { print key "=" m[key] } }' - "$propsfile" | sed 's/\s*=\s*/=/g' > "$out"
}

for filename in /c/Temp/XLocation/*.xml; do
    mergeprops "$filename" Y.properties "$filename.out"
done

如果您需要更多帮助,请与我联系。