たとえば、ラベルのフィールドをそのラベル内のラベルに変換したいとします。
<book name="Data Structure" price="250" pages="350"/>
到着
<book name="Data Structure">
<price>250</price>
<pages>350</pages>
</book>
xmlstarlet
Linuxコマンドラインでまたはを使用してこれを実行したいと思いますsed
。
答え1
process.xsl
:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="//book">
<xsl:element name="book">
<xsl:apply-templates select="./@*"/>
</xsl:element>
</xsl:template>
<xsl:template match="book/@*">
<xsl:if test="name() = 'name'">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:if>
<xsl:if test="name() != 'name'">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
input.xml
:
<book name="Data Structure" price="250" pages="350"/>
注文する:
xsltproc process.xsl input.xml
出力:
<?xml version="1.0"?>
<book name="Data Structure">
<price>250</price>
<pages>350</pages>
</book>
答え2
質問に「use xmlstarlet
or sed
」という内容があることはわかっていますが、これらのツールの1つを使用するには多くの入力が必要です(そして次を使用してsed
修正)。どの構造化された文書形式はお勧めできません。)これを容易にするための別のXML認識ツールがあります。
次のXML文書を想定します。
<root>
<book name="Data Structure 1" price="250" pages="350"/>
<book name="Data Structure 2" price="350" pages="250"/>
<book name="Data Structure 3" price="450" pages="150"/>
</root>
xq
その後(yq
YAMLパーサーラッパーの一部jq
)を使用できます。https://kislyuk.github.io/yq/)欲しいものを表現するには、表現を使用してくださいjq
。
このxq
ツールは、サンプルのXML文書を同等のJSON文書に解析します。
{
"root": {
"book": [
{
"@name": "Data Structure 1",
"@price": "250",
"@pages": "350"
},
{
"@name": "Data Structure 2",
"@price": "350",
"@pages": "250"
},
{
"@name": "Data Structure 3",
"@price": "450",
"@pages": "150"
}
]
}
}
次の式を適用して配列を繰り返し、それ以外の.root.book[]
キーから最初の文字を削除して各JSON要素のキーを変更します。名前に省略形を持つキーはXMLの属性に対応しているため、削除すると、キーはノードの属性ではなくXMLノードに切り替わります。@
@name
@
@
xq -x '.root.book[] |= (with_entries(select(.key != "@name").key |= ltrimstr("@")))' file.xml
上記のサンプルファイルを使用すると、次のものが生成されます。
<root>
<book name="Data Structure 1">
<price>250</price>
<pages>350</pages>
</book>
<book name="Data Structure 2">
<price>350</price>
<pages>250</pages>
</book>
<book name="Data Structure 3">
<price>450</price>
<pages>150</pages>
</book>
</root>
XML文書が実際に単一ノードである場合
<book name="Data Structure" price="250" pages="350"/>
その後、使用
xq -x '.book |= (with_entries(select(.key != "@name").key|=ltrimstr("@")))' file.xml
.book
これは上記と同じ式ですが、配列の要素ではなく最上位セクションにのみ適用されます.root.book[]
。
答え3
使用しないでくださいsed
。作業に適したツールではありません。
私はPerlを直接使用します:
#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new( 'pretty_print' => 'indented_a' );
$twig->parsefile ( 'your_file.xml' );
foreach my $thing ( $twig -> root -> children ) {
my $newthing = $twig -> root -> insert_new_elt($thing->tag);
foreach my $key ( keys %{$thing -> atts()} ) {
$newthing -> insert_new_elt($key, $thing -> att($key));
}
$thing -> delete;
}
$twig->print;
出力:
<root>
<book>
<pages>350</pages>
<name>Data Structure</name>
<price>250</price>
</book>
</root>
(匿名)ハッシュを使用しているので、これは非常に簡単ですatt()
。プロパティを選択するには、もう少し作業を行う必要があります。必要な属性を定義する必要があります。維持する name
これを親要素の属性として挿入します。
以下をmap
使用すると、少し頭が痛くなることがあります。
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use XML::Twig;
my %keep_att = ( name => 1 );
my $twig = XML::Twig->new( 'pretty_print' => 'indented_a' );
$twig->parse( \*DATA );
foreach my $thing ( $twig->root->children ) {
my $newthing = $twig->root->insert_new_elt( $thing->tag,
{ map { $_ => $thing->att($_) } keys %keep_att } );
foreach my $key ( keys %{ $thing->atts() } ) {
next if $keep_att{$key};
$newthing->insert_new_elt( $key, $thing->att($key) );
}
$thing->delete;
}
$twig->print;
__DATA__
<root>
<book name="Data Structure" price="250" pages="350"/>
</root>
これで以下が生成されます。
<root>
<book name="Data Structure">
<price>250</price>
<pages>350</pages>
</book>
</root>
これでmap
、デフォルトで保持したい属性を分離し、新しい要素に再挿入し、維持したい要素が発生します。いいえそれらを守って子供たちにしたいです。
このような:
foreach my $thing ( $twig->root->children ) {
my %attributes = %{$thing->atts()};
my %new_children;
foreach my $attr ( keys %attributes ) {
if ( $keep_att{$attr} ) {
#leave it in %attributes;
}
else {
$new_children{$attr} = $attributes{$attr};
delete $attributes{$attr}
}
}
print Dumper \%attributes;
print Dumper \%new_children;
my $newthing = $twig->root->insert_new_elt( $thing->tag,
{ %attributes } );
foreach my $key ( keys %new_children ) {
$newthing->insert_new_elt( $key, $new_children{$key} );
}
$thing->delete;
}
答え4
Linuxコマンドラインでまたはを使用して
xmlstarlet
これを実行したいと思います。sed
1.6.1および入力XMLファイルを使用して、xmlstarlet
次のコマンドは目的の出力を生成します。
xmlstarlet edit --omit-decl --var T 'book' \
-s '$T' -t elem -n 'price' -u '$prev' -x 'string(../@price)' -d '$T/@price' \
-s '$T' -t elem -n 'pages' -u '$prev' -x 'string(../@pages)' -d '$T/@pages' \
file.xml
どこ
- この変数には、変換する要素のノードセットが含まれています
T
。入力のルート要素にsが含まれている場合、book
入力ファイルbook
(または*
)の単一要素を使用すると、最初にすべて選択されます。book
*/book
//book
(//book)[1]
-s
/--subnode
()サブノードを各要素の属性として含む()という要素を作成します。-t elem
-n
$T
-u
/相対XPath式を使用して、新しく作成された各要素()に--update
値を挿入します()。$prev
-x
-d
/変換後に--delete
各要素の属性を削除します。$T
xmlstarlet edit
コードは、便利な$prev
(別名)ノードを使用して、最新$xstar:prev
の
-i
/ --insert
、-a
/--append
または-s
/オプションで--subnode
生成されたノードを参照できます。$prev
はい
ドキュメント/xmlstarlet.txtそしてソースコード
例/ed-backref*。
name
たとえば、スクリプトジェネレータの場合、重複を排除するためにすべてのs(除外)のプロパティ名を一覧表示するには、次のように言うことができますbook
。
xmlstarlet select -t \
-m '//book/@*[name() != "name"]' -v 'name()' -n \
file.xml |
awk '!seen[$1]++'
xmlstarlet
または、EXSLTサポート以外のツールを使用しないでください。動的:地図
機能:
xmlstarlet select -t \
--var T='//book/@*[name() != "name"]' \
-m 'set:distinct(dyn:map($T,"name()"))' -v . -n \
file.xml