【问题标题】:XMLStarlet: Printing one line per item, while using datum from parent elementXMLStarlet:每个项目打印一行,同时使用来自父元素的数据
【发布时间】:2017-02-15 22:38:24
【问题描述】:

我有以这种方式格式化的 XML 数据:

<XML>
    <Waveforms Time="01/01/2009 3:00:02 AM">
        <WaveformData Channel="I">1, 2, 3, 4, 5, 6 </WaveformData>
        <WaveformData Channel="II">9, 8, 7, 6, 5, 4 </WaveformData>
    </Waveforms>
    <Waveforms Time="01/01/2009 3:00:04 AM">
        <WaveformData Channel="I">1, 2, 3, 4, 5, 6 </WaveformData>
        <WaveformData Channel="II">9, 8, 7, 6, 5, 4 </WaveformData>
    </Waveforms>
</XML>

我正在尝试使用 xmlstarlet 将此数据解析为文本文件(逗号分隔)。所需的输出如下所示:

Time Attribute, Channel Attribute, Data
01/01/2009 3:00:02 AM, I, 1, 2, 3, 4, 5, 6
01/01/2009 3:00:02 AM, II, 9, 8, 7, 6, 5, 4
01/01/2009 3:00:02 AM, I, 1, 2, 3, 4, 5, 6
01/01/2009 3:00:02 AM, II, 9, 8, 7, 6, 5, 4

我能想到的最好的是:

 xmlstarlet sel -T -t -m //XML/Waveforms -v @Time -o "," -m Waves -v WaveformData/@Channel -o "," -v WaveformData -o "," -b -n testwave2.xml > testwave.txt

结果如下:

 01/01/2009 3:00:02 AM, I, 1, 2, 3, 4, 5, 6, II, 9, 8, 7, 6, 5, 4
 01/01/2009 3:00:04 AM, I, 1, 2, 3, 4, 5, 6, II, 9, 8, 7, 6, 5, 4

很清楚如何为每个 Waveforms 打印一行,但如果我想包含其父级的 time 属性,则不知道如何为每个 WaveformData 打印一行。这可以做到吗?或者,我是否应该解决并做一些切片和粘贴以在后端修复它?

【问题讨论】:

  • 这个问题中建议的命令行和这个问题中的测试数据实际上并不能一起工作。也许被省略的Waves 有问题?
  • ...目前,我担心我生成的任何答案都不会对您的实际数据起作用。
  • 看来我粘贴了我用来生成上面输出的代码的衍生版本。我认为唯一的区别是 -m 波已被删除,但要到明天才能检查。真正的问题只是如何获得时间来解析每组波形数据。
  • 实际数据是上面的格式,xmlstarlet代码有点偏。
  • 旁白://XML 要求解析器在文档中搜索 XML 元素。除非您知道需要这样做,否则请使用/XML

标签: xml bash parsing xpath xmlstarlet


【解决方案1】:

搜索 WaveformData - 给定,因为它是您想要的每行 - 并在树中向上遍历以找到您的时间元素。

$ xmlstarlet sel -T -t -m /XML/Waveforms/WaveformData \
     -v ../@Time -o "," \
     -v @Channel -o "," \
     -v . -n <in.xml
01/01/2009 3:00:02 AM,I,1, 2, 3, 4, 5, 6 
01/01/2009 3:00:02 AM,II,9, 8, 7, 6, 5, 4 
01/01/2009 3:00:04 AM,I,1, 2, 3, 4, 5, 6 
01/01/2009 3:00:04 AM,II,9, 8, 7, 6, 5, 4 

或者,如果您知道每个 Waveforms 将恰好有两个 WaveformData 子节点,您可以执行以下操作:

$ xmlstarlet sel -T -t -m /XML/Waveforms \
    -v ./@Time -o ",I,"  -v './WaveformData[@Channel="I"]' -n \
    -v ./@Time -o ",II," -v './WaveformData[@Channel="II"]' -n <in.xml
01/01/2009 3:00:02 AM,I,1, 2, 3, 4, 5, 6
01/01/2009 3:00:02 AM,II,9, 8, 7, 6, 5, 4
01/01/2009 3:00:04 AM,I,1, 2, 3, 4, 5, 6
01/01/2009 3:00:04 AM,II,9, 8, 7, 6, 5, 4

【讨论】:

  • 谢谢 - 我明天会测试一下!
  • . 的目的是什么?在第三个 -v?? 之后
  • @TomFogarty - 这是当前上下文;在这种情况下WaveformData.
  • 感谢 Charles - 很好的解决方案。
  • 感谢丹尼尔的回答
【解决方案2】:

为了稍微改变 Charles Duffy 的回答,您可以使用 concat() 函数稍微简化一下,并使用初始模板来提供 CSV 标头:

$ xmlstarlet sel \
    -t -o 'Time Attribute, Channel Attribute, Data' -n \
    -t -m '//Waveforms/WaveformData' \
       -v 'concat(../@Time, ", ", @Channel, ", ", text())' -n \
  waveforms.xml
Time Attribute, Channel Attribute, Data
01/01/2009 3:00:02 AM, I, 1, 2, 3, 4, 5, 6
01/01/2009 3:00:02 AM, II, 9, 8, 7, 6, 5, 4
01/01/2009 3:00:04 AM, I, 1, 2, 3, 4, 5, 6
01/01/2009 3:00:04 AM, II, 9, 8, 7, 6, 5, 4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 2019-04-15
    相关资源
    最近更新 更多