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

Update .properties file with values from .xml file

以下 xmlstarlet 命令:

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

returns多个结果,因为我的文件包含很多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

待办事项:

我当前的shell代码是:

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

目前仅从 X.xml 获取每个 id/value 并打印到标准输出。 正如您可能怀疑的那样,for 在那里,因为我有多个 X.xmlY.properties,我必须在其上执行此代码。

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

<?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>

Y.properties:

a.b.c.d=Text

我的输出是:

a.b.c.d=
    Text=
=

你能帮帮我吗,我真的不明白发生了什么。

问题二: 具有以下输入: X.xml

my.id = \u00D6ffnen Express WebTools

和Y.properties

<PTXT ID="my.id" CONTEXT="">Öffnen <NTI>Express WebTools</NTI></PTXT> 

结果: out.properties

my.id=Öffnen Express WebTools
my.id=\u00D6ffnen Express WebTools

而不是

my.id=Öffnen Express WebTools

首先生成数据以匹配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= '!( in m) { m[] =  }
           END { for (key in m) { print key "=" m[key] } }' - Y.properties

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

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

mergeprops() {
    local filename=
    local propsfile=
    local out=

    xmlstarlet fo --dropdtd "$filename" | \
      xmlstarlet sel -t -m "//DOC//PTXT" -v $'concat(@ID, "=", ., "\n")' | \
      awk -F= '!( in m) { m[] =  }
               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

如果您需要更多帮助,请告诉我。