格雷普

格雷普

我已经看过了,但找不到其他人和我有同样问题的人。

我有一个像这样的 xml 文件:

<ID>1</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>3</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>4</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>

基本上一大堆数据都在一行上,没有换行符。我需要提取特定 < ID> 标签(例如 < ID>2 )和下一个 </dateAccessed> 标签之间的信息(最好是原封不动地保存标签)。我有大约 50 个文件来检查特定 ID 和以下相关数据。我知道这不是标准,没有嵌套。

我最初尝试使用 grep 和 sed 来执行此操作,但我只是返回了整个文件,这对我来说似乎很奇怪。我不能将其视为文本文件吗?

编辑:

我没有意识到格式化程序删除了 < 和 > 中的文本,所以今天早上重新阅读我的问题后,我意识到它问的是完全不同的东西。 TL;DR 我需要 ID 标签之间的特定值和下一个结束 DateAccessed 标签之间的值。不在相同的开始和结束标记之间,即在 ID 和 /ID 之间

所以我可以得到类似这样的结果:

<ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>

答案1

正如评论中所指出的,您的数据不是格式良好的 XML,并且不完全清楚文档的结构是什么,例如,根据您的示例数据判断,看起来您没有嵌套元素 - 这真的是案件?

考虑到这一点,这里有一个 Python 脚本,它使用美丽汤4解析库来执行您想要的操作(即,它为给定的示例输入数据生成所需的输出数据):

#!/usr/bin/env python
# coding: ascii
"""extract.py

Extract everything between two XML tags
in a (possibly poorly formed) XML document."""

from bs4 import BeautifulSoup
import sys

# Set the opening tag name and value
opening_name = "ID"
opening_text = "2"

# Set the closing tag name
closing_name = "dateAccessed"

# Get the XML data from a file and instantiate a BeautifulSoup parser
# We add a root node because the input data is missing a root
with open(sys.argv[1], 'r') as xmlfile:
    xmldoc = "<root>" + xmlfile.read() + "</root>"
    soup = BeautifulSoup(xmldoc, 'xml')

# Iterate through the elements of the XML data and collect
# all of the elements inbetween the opening and closing tags
elements = []
match = False
for e in soup.find_all():
    if match is True:
        elements.append(str(e))
        if e.name==closing_name:
            break
    else:
        try:
            if e.name==opening_name and e.text==opening_text:
                match = True
                elements.append(str(e))
        except AttributeError:
            pass

# Output the results on a single line
print("".join(elements))

你可以像这样运行它:

python extract.py data.xml

对于您给定的示例数据:

<ID>1</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>3</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed><ID>4</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>

它产生以下输出:

<ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>

答案2

假设 XML 文档实际上有根标签(您的 XML 没有,因此格式不正确),那么您可以像这样使用 XMLstarlet:

xmlstarlet sel -t -m '//ID[. = 2]' \
    -c . -c './following-sibling::*[position()<5]' -nl file.xml

对于给定的数据(修改为<root>在开头和</root>结尾插入),这将返回

<ID>2</ID><data>asdf</data><data2>asdf</data2><dataX>asdf</dataX><dateAccessed>somedate</dateAccessed>

XMLstarlet 查询选择ID内容为2( -m '//ID[. = 2]') 的任何节点。对于这些节点中的每一个(给定数据中只有一个),它返回节点本身的副本 ( -c .) 以及以下五个兄弟节点的副本 ( -c './following-sibling::*[position()<5]'),通过插入换行符 ( -nl) 结束输出。

开始<root>和结束标签可以插入到文档本身中,或者传递给 XMLstarlet,如下所示:

{ echo '<root>'; cat file.xml; echo '</root>'; } |
xmlstarlet sel -t -m '//ID[. = 2]' \
    -c . -c './following-sibling::*[position()<5]' -nl

答案3

格雷普

grep -oE '<data>[^<]*</data>' yourxmlfile

重击

tag='data'
tL="<$tag>" tR="</$tag>"
xml=$(< yourxmlfile)
while case $xml in *"$tL"* ) :;; * ) break;; esac; do
  t1=${xml#*"$tL"} t2=${t1%%"$tR"*} xml=${t1#*"$tR"}
  echo "${tL}${t2}${tR}"
done

珀尔

perl -lne "print for/<$tag>.*?<\/$tag>/g" yourxmlfile

塞德

sed -e "
  s|<$tag>|\n&|
  s/.*\n//
  s|</$tag>|&\n|
  /\n/P;D
" yourxmlfile

输出

 <data>asdf</data>
 <data>asdf</data>
 <data>asdf</data>
 <data>asdf</data>

答案4

前提是 XML 没有换行符。为什么不尝试在 >< 之间插入 \n ,这将使 XML 成为标准格式

示例:- 我使用给定的 xml 创建了一个名为 stack 的文件。

下面是引入换行符的 sed 操作。

 cat stack|sed -e 's/></>\n</g'

<ID>2</ID>
<data>asdf</data>
<data2>asdf</data2>
<dataX>asdf</dataX>
<dateAccessed>somedate</dateAccessed>

现在您可以访问您想要的标签

相关内容