【问题标题】:Regular expression for converting SGML to XML用于将 SGML 转换为 XML 的正则表达式
【发布时间】:2018-02-08 23:07:01
【问题描述】:

我正在通过this 链接将 sgml 内容转换为 xml 内容。 使用sgmlString.replaceAll("<(([^<>]+?)>)([^<>]+?)(?=<(?!\\1))", "<$1$3</$2>");正则表达式我几乎接近预期的结果,但是对于以下文件,当有多个同名的并行标签没有关闭时,它只关闭最后一个标签的标签。

输入:

<SEC-HEADER>0001104659-17-052330.hdr.sgml : 20170817
    <ACCEPTANCE-DATETIME>20170817060417
    <ACCESSION-NUMBER>0001104659-17-052330
    <TYPE>8-K
    <PUBLIC-DOCUMENT-COUNT>4
    <PERIOD>20170816
    <ITEMS>7.01
    <ITEMS>8.16
    <FILING-DATE>20170817
    <DATE-OF-FILING-DATE-CHANGE>20170817
    <FILER>
        bye bye see you!
    </FILER>
</SEC-HEADER>

输出:(注意只有一个ITEMS标签的关闭和两个FILER的关闭,不是预期的)

  <SEC-HEADER>0001104659-17-052330.hdr.sgml : 20170817
     <ACCEPTANCE-DATETIME>20170817060417</ACCEPTANCE-DATETIME>
     <ACCESSION-NUMBER>0001104659-17-052330</ACCESSION-NUMBER>
     <TYPE>8-K</TYPE>
     <PUBLIC-DOCUMENT-COUNT>4</PUBLIC-DOCUMENT-COUNT>
     <PERIOD>20170816</PERIOD>
     <ITEMS>7.01<ITEMS>8.16</ITEMS>
     <FILING-DATE>20170817</FILING-DATE>
     <DATE-OF-FILING-DATE-CHANGE>20170817</DATE-OF-FILING-DATE-CHANGE>
     <FILER>bye bye see you!</FILER></FILER>
</SEC-HEADER>

预期:

  <SEC-HEADER>0001104659-17-052330.hdr.sgml : 20170817
         <ACCEPTANCE-DATETIME>20170817060417</ACCEPTANCE-DATETIME>
         <ACCESSION-NUMBER>0001104659-17-052330</ACCESSION-NUMBER>
         <TYPE>8-K</TYPE>
         <PUBLIC-DOCUMENT-COUNT>4</PUBLIC-DOCUMENT-COUNT>
         <PERIOD>20170816</PERIOD>
         <ITEMS>7.01</ITEMS>
         <ITEMS>8.16</ITEMS>
         <FILING-DATE>20170817</FILING-DATE>
         <DATE-OF-FILING-DATE-CHANGE>20170817</DATE-OF-FILING-DATE-CHANGE>
         <FILER>bye bye see you!</FILER>
    </SEC-HEADER>

我需要您对以下问题的建议/指导:

  1. 因为我读的正则表达式很慢,所以使用正则表达式获取结束标签以使其成为 xml 格式是一种好方法吗?
  2. 我有很多文件要处理(最多 18000 行/标签),有没有更好的方法来实现它?
  3. 如何通过改变正则表达式得到预期的结果(我的EL真的很弱)

【问题讨论】:

  • 我是否可以建议您考虑使用 XSLT,据我了解,它可能非常适合这个 XML 转换问题?我认为在这里使用正则表达式会引起问题,尤其是嵌套标签。
  • 我不知道 XSLT 以及如何使用它。您能否提供一些指南/工作示例的链接或参考它的东西。感谢您的快速回复。
  • @TimBiegeleisen XSLT 不会因为任何还没有形成良好的东西而失败吗?
  • 我对 sgml 没有经验,但是这 (?!\\1) 不应该是 (?!\\\1) 以便 a) 转义的 `\` b) 对第一个匹配的引用吗?
  • @Yunnosch 我对 sgml 和正则表达式也没有经验,我尝试了你的建议。它解决了ITEMS标签相关问题,但输出中仍然有两个FILER关闭。

标签: java regex xml sgml


【解决方案1】:

虽然它可能适用于手头的 SGML,但通常使用正则表达式匹配/替换是一种将 SGML 转换为 XML 的糟糕方法,因为 SGML 具有标记省略/标记推断、属性名称和值省略(如在 HTML 中),以及 SGML 的 XML 配置文件中没有的其他简短形式和功能。

但是我可以完全推荐专用的osx SGML 到 XML 转换程序。其来源可从http://openjade.sourceforge.net/ 获得。如果您使用的是 Debian/Ubuntu,则可以通过 sudo apt-get install opensp 安装它,如果您使用的是 Mac OS(使用必须首先安装的 MacPorts),则可以通过 sudo port install opensp(但不知道 MacBrew 的等价物) .

【讨论】:

    【解决方案2】:

    我在 perl 中有一个解决方案。 它是基于&lt;SEC-HEADER&gt;的特殊处理,并入。

    Perl 代码:

    use strict;
    use warnings;
    
    my $Input ='';
    while(<>)
    {
        $Input.=$_;
    }
    
    $Input =~ s/<((?!SEC-HEADER)([^\/<>]+?)>)([^<>]+?)(\s*?)(?=<[^\/])/<$1$3<\/$2>$4/g;
    print $Input;
    

    为了将它翻译成你的工具(我无法测试并且不得不猜测它的语法),我建议尝试:

    sgmlString.replaceAll("<((?!SEC-HEADER)([^\/<>]+?)>)([^<>]+?)(\s*?)(?=<[^\/])", "<$1$3<\/$2>$4");
    

    抱歉,您必须自己修正一些特定于工具的错误,可能是通过反复尝试。
    使用我的 perl 版本,我得到了以下输出,我希望它足够接近,它只是不会吃掉 &lt;FILER&gt; 内的空白。

    输出:

    <SEC-HEADER>0001104659-17-052330.hdr.sgml : 20170817
        <ACCEPTANCE-DATETIME>20170817060417</ACCEPTANCE-DATETIME>
        <ACCESSION-NUMBER>0001104659-17-052330</ACCESSION-NUMBER>
        <TYPE>8-K</TYPE>
        <PUBLIC-DOCUMENT-COUNT>4</PUBLIC-DOCUMENT-COUNT>
        <PERIOD>20170816</PERIOD>
        <ITEMS>7.01</ITEMS>
        <ITEMS>8.16</ITEMS>
        <FILING-DATE>20170817</FILING-DATE>
        <DATE-OF-FILING-DATE-CHANGE>20170817</DATE-OF-FILING-DATE-CHANGE>
        <FILER>
            bye bye see you!
        </FILER>
    </SEC-HEADER>
    

    详情:

    • 使用与实际找到的标签名称的否定匹配而不是\1
    • / 而不是 \
    • 在一开始,期待一个非/
    • 忽略特殊标记名SEC-HEADER,因为您已隐式允许
    • 捕获一些空白并使用它来正确缩进和换行

    如果你确实想吃掉空格,这里有一个 (perl) 替换来做到这一点:

    $Input =~ s/<(?!\/)([^<>]+)>\s*([^<>]+[^\s<>])\s*<\/\1>/<$1>$2<\/$1>/g;
    

    您的工具的猜测版本
    (再次,对于小错误,请自行润色):

    sgmlString.replaceAll("<(?!\/)([^<>]+)>\s*([^<>]+[^\s<>])\s*<\/\1>", "<$1>$2<\/$1>");
    

    输出(在第一个代码之后应用):

    <SEC-HEADER>0001104659-17-052330.hdr.sgml : 20170817
        <ACCEPTANCE-DATETIME>20170817060417</ACCEPTANCE-DATETIME>
        <ACCESSION-NUMBER>0001104659-17-052330</ACCESSION-NUMBER>
        <TYPE>8-K</TYPE>
        <PUBLIC-DOCUMENT-COUNT>4</PUBLIC-DOCUMENT-COUNT>
        <PERIOD>20170816</PERIOD>
        <ITEMS>7.01</ITEMS>
        <ITEMS>8.16</ITEMS>
        <FILING-DATE>20170817</FILING-DATE>
        <DATE-OF-FILING-DATE-CHANGE>20170817</DATE-OF-FILING-DATE-CHANGE>
        <FILER>bye bye see you!</FILER>
    </SEC-HEADER>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-18
      • 1970-01-01
      • 2010-10-18
      • 2011-10-02
      • 2016-04-02
      • 1970-01-01
      • 2019-05-11
      • 2014-11-08
      相关资源
      最近更新 更多