xmlstarletを使用してXMLのフィールドをタグに変換できますか?

xmlstarletを使用してXMLのフィールドをタグに変換できますか?

たとえば、ラベルのフィールドをそのラベル内のラベルに変換したいとします。

<book name="Data Structure" price="250" pages="350"/>

到着

<book name="Data Structure"> 
<price>250</price>
<pages>350</pages>
</book>

xmlstarletLinuxコマンドラインでまたはを使用してこれを実行したいと思います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 xmlstarletor 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その後(yqYAMLパーサーラッパーの一部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

関連情報