XML属性値をクリーンアップする方法

XML属性値をクリーンアップする方法

次のXMLがあります。

<string name="foo-bar">"bar-bar -bar"</string>
<string name="asdf_qwe-rty" translatable="false">"Lorem ipsum"</string>

これで、属性に文字をname含めることはできません。-_

<string name="foo_bar">"bar-bar -bar"</string>
<string name="asdf_qwe_rty" translatable="false">"Lorem ipsum"</string>

を使ってどうすればいいですかsed

答え1

XML文書の形式が正しいと仮定すると、次のようにしてすべてのノード属性ですべてのxmlstarlet文字の発生を置き換えることができます。-namestring_

$ xmlstarlet ed -u '//string/@name' -x 'translate(.,"-","_")' file.xml
<?xml version="1.0"?>
<root>
  <string name="foo_bar">"bar-bar -bar"</string>
  <string name="asdf_qwe_rty" translatable="false">"Lorem ipsum"</string>
  <string name="_test1_">name="-test1-"</string>
  <!-- <string name="-test2-">name="-test2-"</string> -->
</root>

root(ドキュメント形式をうまく作るためにここにラッパーノードを追加し、ノード値やコメント内容に影響を与えないことを示すためにいくつかの追加事例を追加しました)。

このxmlstarlet式はXPath式を使用してすべての関連属性を見つけ、各属性値に//string/@node単純な変換を適用します。出力は標準出力に書き込まれます。-_

答え2

sedベースのソリューション(または適切なXML解析を実行しない他のソリューション)は、特定の割合の極端な場合に失敗します。たとえば、@Pitelのソリューションは次のとおりです。

(a) 開いているタグではなく、コメントやテキストにあっても、名前属性のように見える項目を置き換えます。

firstname(b) または名前付き属性の内容も変更します。lastname

(c) 等号の周囲にスペースがある場合、属性が見つかりません。

したがって、1回限りの一時使用には十分ですが、本番ワークフローに含めないでください。本番品質の資料が必要な場合は、XSLT変換を使用してください。難しくありません:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
  <xsl:mode on-no-match="shallow-copy"/>
  <xsl:template match="@name">
    <xsl:attribute name="name" select="translate(., '-', '_')"/>
  </xsl:template>
</xsl:transform>

答え3

sed -r ':a; s/(name="[^-"]*)-/\1_/; ta'

関連情報