複数のファイルからXML属性を読み、以前より1.25倍大きい数字に置き換えてください。

複数のファイルからXML属性を読み、以前より1.25倍大きい数字に置き換えてください。

ワンクリックで複数のXMLファイルのすべての一致を変更するために使用できるbashスクリプトまたは同様のスクリプトを作成しようとしています。私は24個のXMLファイルを持っていますTorque="SOMENUMBER"。ゲーム内のすべてのモーターにトルクを25%追加するために、これを1.25倍の値に置き換えたいと思います。

(モードとゲームパッチがこれを無視して他の値をすばやく試すことができるので、これは便利です。)

数字を抽出して変数に入れるというアイデアが浮かび上がりましたがsed -n -e 's/Torque="\(.*\)"/\1/p' <filename.xml、どうやって正しい位置に入れるのか分からず、sed上記のコマンドは発生するすべてのトルクを一度に出力します。

xmlstarletは私がGoogleで検索したものに基づいてこれを行うことができますが、常にxmlファイルに複数のルート要素が含まれていると文句を言います。たぶん、すべてに一時タグを追加し、<root_temp><\root_temp>xmlstarletが魔法を機能させ、タグを再度削除してファイルを保存する必要がありますか? Bash スクリプトを開始してから数年が経ちました。 Python、cppでもやりたいです。新しい言語の基本を学びたい。 xDは関係ありません。

XMLの例:

<_templates>
    <Engine>
        <RUScoutModernEngine BrakesDelay="0.5" />
    </Engine>
</_templates>
<EngineVariants>
    <Engine
        _template="RUScoutModernEngine"
        CriticalDamageThreshold="0.7"
        DamageCapacity="120"
        DamagedConsumptionModifier="1.2"
        EngineResponsiveness="0.35"
        FuelConsumption="1.5"
        Name="ru_scout_modern_engine_0"
        Torque="70000"
        DamagedMinTorqueMultiplier="1.0"
        DamagedMaxTorqueMultiplier="0.6"
        MaxDeltaAngVel="0.01"
    >
        <GameData
            Price="1900"
            UnlockByExploration="false"
            UnlockByRank="1"
        >
            <UiDesc
                PLACE="HOLDER"
            />
        </GameData>
    </Engine>
    <Engine
        BLA="BLA"
        Torque="80000"
        BLA="BLA"
    >
        <GameData
            Price="5500"
            UnlockByExploration="true"
            UnlockByRank="1"
        >
            <UiDesc
                PLACE="HOLDER"
            />
        </GameData>
    </Engine>
    <Engine
        BLA="BLA"
        Torque="76000"
        BLA="BLA"
    >
        <GameData
            BLA="BLA"
        >
            <UiDesc/>
        </GameData>
    </Engine>
</EngineVariants>

答え1

破損したXMLの周りに偽のルートノードを追加するのは非常に簡単で、変更されたXMLを使用するのも簡単で、修正後に追加されたルートノード(および追加されたルートノード)xmlstarletを削除することもそれほど難しくありません。<?xml version="1.0"?>xmlstarlet

{ echo '<root>'; cat file.xml; echo '</root>'; }  |
xmlstarlet ed -u '//Engine/@Torque' -x '. * 1.25' |
sed '1d; 2d; $d'

明らかに、これはこのビットによって生成されたXMLが{ ...; }実際によく構成されたXML文書であると仮定します(例文書に重複する属性があります)。


上記と同じですがxq(周囲のXMLパーサーの一部としてjq使用可能です)を使用します。yqhttps://kislyuk.github.io/yq/):

{ echo '<root>'; cat file.xml; echo '</root>'; }  |
xq -x '.root.EngineVariants.Engine[]."@Torque" |= ( tonumber * 1.25)' |
sed '1d; $d'

出力にはxq含まれていません<?xml version="1.0"?>


*.xmlxmlstarlet上記のコードのバリエーションを例として、名前が一致するディレクトリ内のすべてのファイルに対してこの操作を繰り返します。

tmpfile=$(mktemp)

for pathname in ./*.xml; do
    cp "$pathname" "$tmpfile" &&
    { echo '<root>'; cat "$tmpfile"; echo '</root>'; } |
    xmlstarlet ed -u '//Engine/@Torque' -x '. * 1.25'  |
    sed '1d; 2d; $d' >"$pathname"
done

rm -f "$tmpfile"

一致するファイルは上からその場所で編集されます。欲しいかもしれませんコピーまず、ファイルです!

答え2

XMLフラグメント(複数のルートノードを持つファイル)は管理するのが非常に難しく、それを直接許可するツールはほとんどありません。ラップ要素を「手動で」追加するのも良い考えです。

https://stackoverflow.com/questions/23571941/making-use-of-an-xml-file-with-more-than-one-root-element/23574398#23574398

フォーマットされた文書がある場合は、xmlstarletまたはSaxon's Gizmo(https://saxonica.com/documentation10/index.html#!gizmo)は単なる「利己主義の陳述」でなければなりません。ギズモでは

update //@Torque with .*1.25

答え3

一時ルートノードを使用してオプションを実装して機能させ、提案されているようにGizmoを使用して問題を解決しました。後でこの問題を偶然発見する人のためにここに私の解決策があります。

私はJavaバージョンをダウンロードしましたサクソンホームエディション、"Saxon"というサブフォルダに解凍し、次のスクリプトを正常に使用しました。

#!/bin/bash

#remove script and generate it with the following lines (that way I only need
#to include my one .sh file)
rm -f script
echo update //@Torque with .*1.25>script
echo save temp_updated.xml method=xml indent=yes>>script

#we do the following to all xml files in the subfolder "classes/engines/"
for filename in classes/engines/*.xml
do
    #cleanup in case they got leftover, which is important for Gizmo,
    #otherwise I get a thousand "Overwrite File" prompts, which is
    #not conducive to automating the process.
    rm -f temp.xml
    rm -f temp_updated.xml

    #make a new temp file, starting with the temporary root element,
    #append the original file and close the root element
    echo "<xml_temp>">temp.xml
    cat $filename>>temp.xml
    echo "</xml_temp>">>temp.xml

    #call Saxon with the correct codepath, start the Gizmo subroutine or whatever
    #take the temporary file as input and "script" as the commands to be executed
    java -cp "Saxon/saxon-he-10.5.jar:Saxon/jline-2.14.6.jar" net.sf.saxon.Gizmo -s:temp.xml -q:script
    #sed -i for inplace editing of the file
    #the first expression '$d' removes the last line (the closing temp root tag)
    #the second impression removes the first line (Gizmo tags on some kind of xml info
    #and the second line, which contains the starting temp root tag
    sed -i -e '$d' -e 1,2d temp_updated.xml

    #I force overwrite the old file with the new and improved xml
    cp -f temp_updated.xml $filename
    #...and clean up after myself
    rm -f temp.xml
    rm -f temp_updated.xml
    rm -f script
done

関連情報