【问题标题】:Extracting data between two tags in HTML file提取 HTML 文件中两个标签之间的数据
【发布时间】:2011-07-05 11:56:05
【问题描述】:

我的系统上保存了一个 HUUUGE HTML 文件,其中包含来自产品目录的数据。数据的结构使得每个产品记录的名称都在两个标签 (name) 和 (/name) 之间。

每个产品最多有 3 个属性:名称、产品 ID 和颜色,但并非所有产品都具有所有这些属性。

如何在不混淆产品属性的情况下为每个产品提取这些数据?该文件也是 50 兆字节!

代码示例 ....

<name>'hat'</name>
blah blah blah
<prodId>'1829493'</prodId>
blah blah blah
<color>'cyan'</color>

blah blah 
blah blah blah
blah blah blah

<name>'shirt'</name>
blah blah blahblah blah blah
<prodId>'193'</prodId>

<name>'dress'</name>
blah blah blah
blah blah blah
<prodId>'18'</prodId>
<color>'dark purple'</color>

【问题讨论】:

  • 发布一些代码。如果输入数据的格式足够好,也许有一个简单的答案。
  • 看起来像是在读取 xml 文档。您可以尝试稍微更改 xmlread 帮助页面 (mathworks.com/help/techdoc/ref/xmlread.html) 中作为示例提供的函数。
  • @Kerrek SB 我添加了一个示例代码“块”。
  • @Bob:嗯,在这种受限情况下,如果您保证格式与示例中的完全相同,您可能会使用正则表达式来提取三个字段。 sedawk 之类的东西应该让您编写一个命令来将数据转换为您需要的任何格式。
  • name/prodId/color 标签是否包含在另一个元素中,例如&lt;item&gt;

标签: html xml matlab extract large-files


【解决方案1】:

大小为 50 MB 的文件不会太大,您不能直接将其内容作为字符串加载到 MATLAB 中,您可以使用函数 FILEREAD

strContents = fileread('yourfile.html');

假设你有上面的文件格式,你可以用函数REGEXP解析内容(使用named token capture):

expr = '<(?<tag>name|prodId|color)>''([^<>]+)''</\k<tag>>';
tokens = regexp(strContents,expr,'tokens');
tokens = vertcat(tokens{:});

使用您的示例文件内容的token 的内容将是:

tokens = 

    'name'      'hat'        
    'prodId'    '1829493'    
    'color'     'cyan'       
    'name'      'shirt'      
    'prodId'    '193'        
    'name'      'dress'      
    'prodId'    '18'         
    'color'     'dark purple'

然后,您可能想要解析生成的 N×2 元胞数组并将内容放在具有字段 'name''prodId''color'structure array 中。困难在于并非每个条目都会包含所有三个字段。假设每个'name' 后面会跟着'prodId''color'both(按'prodId' 的顺序然后'color'),那么以下代码应该适合您:

s = struct('name',[],'prodId',[],'color',[]);  %# Initialize structure
nTokens = size(tokens,1);                      %# Get number of tokens
nameIndex = find(strcmp(tokens(:,1),'name'));  %# Find indices of 'name'
[s(1:numel(nameIndex)).name] = deal(tokens{nameIndex,2});  %# Fill 'name' field

%# Find and fill 'prodId' that follows a 'name':
index = strcmp(tokens(min(nameIndex+1,nTokens),1),'prodId');
[s(index).prodId] = deal(tokens{nameIndex(index)+1,2});

%# Find and fill 'color' that follows a 'name':
index = strcmp(tokens(min(nameIndex+1,nTokens),1),'color');
[s(index).color] = deal(tokens{nameIndex(index)+1,2});

%# Find and fill 'color' that follows a 'prodId':
index = strcmp(tokens(min(nameIndex+2,nTokens),1),'color');
[s(index).color] = deal(tokens{min(nameIndex(index)+2,nTokens),2});

使用您的示例文件内容的s 的内容将是:

>> s(1)

      name: 'hat'
    prodId: '1829493'
     color: 'cyan'

>> s(2)

      name: 'shirt'
    prodId: '193'
     color: []

>> s(3)

      name: 'dress'
    prodId: '18'
     color: 'dark purple'

【讨论】:

  • +1 很好地使用了正则表达式,虽然它让我想起了这一点:codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html
  • @Amro:我能说什么,我喜欢危险地生活。 ;)
  • 这是一个很棒的解决方案——正是我所追求的。但是,我的“标签”示例是对事实的抽象。代码对标签对的含义是否可能更加灵活。这对标签可以是两个字符串吗?将一对标签存储在一个结构中?在上面的代码中,我们假设标签对中的第二个是前一个,其中包含一个“/”。而不是 ,它可能是
  • @Bob M.:这很容易解释。如果格式为&lt;XXX&gt;&lt;endofXXX&gt;,只需将匹配表达式的最后一部分设为&lt;endof\k&lt;tag&gt;&gt;。如果您可以将&lt;/XXX&gt;&lt;endofXXX&gt; 作为第二个标签,则将其用于匹配表达式的最后一部分:&lt;(?:/|endof)\k&lt;tag&gt;&gt;
  • @gnovice :再次感谢。我得到的是如果第一个标签是 而另一个是 呢? ...在某些情况下,我的标签没有像我想要的那样“很好地”定义。
【解决方案2】:

有两种方法可以解决此类问题:使用正则表达式进行字符串操作(如 gnovice 所建议的那样)或解析文件(或两者的混合)。如果你的文件结构很好,解析通常是最好的;正则表达式胜过凌乱的文件。

这是解析解决方案。

首先下载xmliotools,然后在您的文件上调用xml_read。您的示例并非完全可重现,因此这里有两个不同版本的数据。

将此保存到test1.xml

<?xml version="1.0" encoding="utf-8"?>
<root>
<name>'hat'</name>
<prodId>'1829493'</prodId>
<color>'cyan'</color>
<name>'dress'</name>
<prodId>'18'</prodId>
<color>'dark purple'</color>
</root>

将此保存到test2.xml

<?xml version="1.0" encoding="utf-8"?>
<root>
<item>
<name>'hat'</name>
<prodId>'1829493'</prodId>
<color>'cyan'</color>
</item>
<item>
<name>'dress'</name>
<prodId>'18'</prodId>
<color>'dark purple'</color>
</item>
</root>

现在比较

x1 = xml_read('test1.xml')
x2 = xml_read('test2.xml')

【讨论】:

  • 谢谢 Richie,我将尝试这两种方法,看看速度比较如何。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-26
  • 2018-03-16
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
相关资源
最近更新 更多