2017-01-29 14 views
3

私の希望する出力を得るための最後の部分を理解できないようです。次awk二重引用符区切り文字

<Stats> 
    <RecNum>45435</RecNum> 
    <Date>2016/12/31</Date> 
    <DayofWeek>6</DayofWeek> 
    <Time>16:35</Time> 
    <Dir>Closing</Dir> 
    <Class>2</Class> 
    <SpeedSpan>1</SpeedSpan> 
    <TimeSpan>1</TimeSpan> 
    <Bucket Speed="34" Count="1"/> 
    <Bucket Speed="35" Count="0"/> 
    <Bucket Speed="36" Count="1"/> 
</Stats> 

は、私は、日付、時間と速度を印刷したい場合はカウント= 1::

2016/12/31 16:35 34 
2016/12/31 16:35 36 

私が持っている最も近い

私は次のような多くのエントリを持つファイルを持っています来る次のようである:私を与える

$ awk -F'[ <>]' 'BEGIN {d="d";t="t";} /<Date>/ {d=$3;} /<Time>/ {t=$3;} /Count="1"/ {print d "\t" t "\t" $3;}' speed.xml 

2016/12/31 16:35 Speed="34" 
2016/12/31 16:35 Speed="36" 

私は多くの異なる反復を試みましたが、言葉のないスピード番号を得ることはできません。 "フィールドセパレータとして使用しようとしましたが、決して期待どおりに動作しないようです"

awkの解決策を見つけたいと思っていましたが、そうでない場合はいつもPythonプログラムを使用して不要な文字を取り除きます。

+1

チェックアウト:[サブ(正規表現、置換)](https://www.gnu.org /software/gawk/manual/html_node/String-Functions.html) –

答えて

4

Jose Ricardo Bustos M.'s helpful XSLT-based answerStephen Rauch's helpful Python-based answerが好ましい:あなたは、Linux/Unixのいくつかの種類を使用している場合は、XSLT-1.0プロセッサxsltprocを使用して、このような(より多くのをあります)なぜなら彼らはより柔軟で堅牢な適切なXML解析を採用しているからです。

awk -v OFS='\t' -F'[<>]' ' 
    /<Date>/ {d=$3} 
    /<Time>/ {t=$3} 
    /Count="1"/ { 
    split($0, flds, "\"") 
    print d, t, flds[2] 
    } 
' speed.xml 

split($2, flds, "\"")"によって注目ラインを分割し、2

また、インデックスによって"Speed"属性値を抽出できるカスタム配列flds、中に結果を格納します。

はあなたのawkコマンドを修正するには-v OFS='\t'の使用に注意してください。出力フィールドセパレータをタブに設定すると、出力フィールドを列挙する(,)より簡単なprint文が有効になり、awkを暗黙的にOFSで区切ります。


付け足し:フィールド区切り文字のセットに"を加えることも働いているであろう:

awk -v OFS='\t' -F'["<>]' ' 
    /<Date>/ {d=$3} 
    /<Time>/ {t=$3} 
    /Count="1"/ { print d, t, $3 } 
' file 
+2

ありがとうございました。これはまさに私が望んでいたものです。 私はPythonでそれをやったことがあり、おそらくXSLTを使うことを学ぶべきであることは知っていますが、非常に特定のユースケースのためです。 – brettd0g

+0

@ brettd0g:それが助けられたと聞いて嬉しく思っています。ちょうど私にはもっと簡単な解決策がありました。私の更新を見てください( 'split()'技法は一般的に便利です)。 – mklement0

+1

あなたの単純な解決策も私のために働いていました。 二重引用符をフィールド区切り記号に追加するのに何度も試みましたが、それは私にとってはうまくいかないでしょう。あなたの仕事。ありがとう。 – brettd0g

2

あなたが言及したのでパイソン:使用

import xml.dom.minidom 

# Open XML document using minidom parser 
DOMTree = xml.dom.minidom.parseString('<X>' + my_xml + '</X>') 
collection = DOMTree.documentElement 
for record in collection.getElementsByTagName("Stats"): 
    date = record.getElementsByTagName('Date')[0].childNodes[0].data 
    time = record.getElementsByTagName('Time')[0].childNodes[0].data 
    buckets = record.getElementsByTagName('Bucket') 
    for bucket in buckets: 
     x = bucket.getAttribute('Count') 
     if int(bucket.getAttribute('Count')) != 0: 
      print('%s\t%s\t%s' % (date, time, bucket.getAttribute('Speed'))) 

データ:

my_xml = """ 
    <Stats> 
     <RecNum>45435</RecNum> 
     <Date>2016/12/31</Date> 
     <DayofWeek>6</DayofWeek> 
     <Time>16:35</Time> 
     <Dir>Closing</Dir> 
     <Class>2</Class> 
     <SpeedSpan>1</SpeedSpan> 
     <TimeSpan>1</TimeSpan> 
     <Bucket Speed="34" Count="1"/> 
     <Bucket Speed="35" Count="0"/> 
     <Bucket Speed="36" Count="1"/> 
    </Stats> 
""" 

プリント:

2016/12/31 16:35 34 
2016/12/31 16:35 36 
3

私はawkが好きなものの、私は(XSLTを使用すると、任意のテキスト形式にXMLドキュメントを変換することができます)、これを行うためにxsltを使用することをお勧めします。 xslt w3schools

file.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="text" omit-xml-declaration="yes"/> 
    <xsl:template match="/"> 
     <xsl:for-each select="Stats/Bucket[@Count='1']"> 
      <xsl:value-of select="../Date"/> 
      <xsl:text>&#x9;</xsl:text> 
      <xsl:value-of select="../Time"/> 
      <xsl:text>&#x9;</xsl:text> 
      <xsl:value-of select="@Speed" /> 
      <xsl:text>&#xa;</xsl:text> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

それを実行します。

xsltproc file.xsl file.xml 

あなたが得る、

2016/12/31 16:35 34 
2016/12/31 16:35 36 
関連する問題