【问题标题】:Perl - Convert a nested XML format to Java with recursionPerl - 使用递归将嵌套的 XML 格式转换为 Java
【发布时间】:2017-01-11 13:30:55
【问题描述】:

我需要使用 Perl 将如下嵌套的 XML 格式转换为 Java:

<invoke name="name1" operation="operation1" displayName="Invoke1" id="6">
  <input>
    <parameter name="Value" variable="Value"/>
    <parameter name="ID" variable="ID"/>
  </input>
  <output>
    <parameter name="Return" variable="Return"/>
  </output>
</invoke>
<switch name="..." displayName="..." id="13">
    <case id="14">
        <condition expressionLanguage="..."><![CDATA[(c1)]]></condition>
    </case>
    <otherwise id="106">
        <switch name="..." displayName="..." id="15">
            <case id="16">
                <condition expressionLanguage="..."><![CDATA[(c2)]]></condition>
                <switch name="..." displayName="..." id="19">
                    <case id="20">
                        <condition expressionLanguage="..."><![CDATA[(c3) >0)]]></condition>
                    </case>
                    <otherwise id="106"> </otherwise>
                </switch>
            </case>
            <otherwise id="107">
                <switch name="..." displayName="..." id="33">
                    <case id="64">
                        <condition expressionLanguage="..."><![CDATA[(c4)]]></condition>
                    </case>
                    <otherwise id="108"> </otherwise>
                </switch>
            </otherwise>
        </switch>
    </otherwise>
</switch>

预期输出如下:

<invoke name="name1" operation="operation1" displayName="Invoke1" id="6">
  <input>
    <parameter name="Value" variable="Value"/>
    <parameter name="ID" variable="ID"/>
  </input>
  <output>
    <parameter name="Return" variable="Return"/>
  </output>
</invoke>
if(c1) {
}else{
    if(c2) {
        if(c3) {
        }else{
        }
    }else{
        if(c4) {
        }else{
        }
    }
}

我认为可以通过 4 个步骤来实现:

  1. 读取 XML 文件 -> 获取第一个 switch1 块 -> 转换为 if--else
  2. 获取 case1 块,否则获取 switch1 块的 1 块
  3. 从第 1 步为 case1 块和其他 1 块实现递归
  4. 读取 XML 文件的其余部分并从 s1 执行相同操作

在这种情况下,我实际上很难进行递归。一些 Perl 专家可以在这里帮助我吗?

【问题讨论】:

  • 您可以尝试编写一个函数process_switch,它采用XML 树节点(XML::TwigMojo::DOM 将是解析文件的好选择)和缩进级别。使用文件中的顶部 switch 元素调用它。获取节点的第一个 case 子节点。获取casecondition 子级并将其打印为"\t" x $indentation . if( COND ) {。如果case 具有switch 子元素,则使用$indentation+1 递归调用自己。关闭 if 块并对 otherwise 执行相同操作(如果存在)。
  • 您好 mbethke,感谢您花时间回答我的问题。我的看法和你一样,但难点是如果在 Case 块中有另一个 sub-otherwise 块,如何获得 else 块。你能帮我写一个示例 perl 代码来解决这个问题吗?

标签: java regex xml perl xml-parsing


【解决方案1】:

这是一个使用XML::Parser 的解决方案。我使用了Style =&gt; 'Subs',因为我感兴趣的唯一事件是caseotherwise 元素的开始和结束,以及非空白字符数据

数组@indent 每次我们下降到一个块时都会有另一个元素被推送到它上面,当块结束时最后一个元素被弹出。数组中最后一个元素的值是我们目前在这个级别看到的case 元素的数量。这允许我们为第一次之后的所有事件输出else if

我已将整个文本括在括号中,因为您的第三个 condition 元素包含 (c3) &gt;0,否则没有意义

我相信它已经足够清晰,您可以进行任何可能需要的调整

use strict;
use warnings 'all';

use XML::Parser;

my $parser = XML::Parser->new(
    Style    => 'Subs',
    Handlers => { Char  => \&handle_char },
);

my @indent = (0);

$parser->parse(*DATA);

sub indent {
    '    ' x $#indent;
}

sub case {

    print indent;
    print "else " if $indent[-1] > 0;
    print "if ( ";

    push @indent, 0;
}

sub case_ {

    pop @indent;

    ++$indent[-1];

    print indent, "}\n";
}

sub otherwise {

    print indent, "else {\n";

    push @indent, 0;
}

sub otherwise_ {

    pop @indent;
    print indent, "}\n";
}

sub handle_char {
    my ($expat, $string) = @_;

    print $string, " ) {\n" if $string =~ /\S/;
}


__DATA__
<root>
    <switch name="..." displayName="..." id="13">
        <case id="14">
          <condition expressionLanguage="..."><![CDATA[(c1)]]></condition>
        </case>
        <otherwise id="106">
          <switch name="..." displayName="..." id="15">
            <case id="16">
              <condition expressionLanguage="..."><![CDATA[(c2)]]></condition>
                <switch name="..." displayName="..." id="19">
                  <case id="20">
                    <condition expressionLanguage="..."><![CDATA[(c3) >0)]]></condition>
                  </case>
                  <otherwise id="106">
                  </otherwise>
                </switch>
            </case>
            <otherwise id="107">
                <switch name="..." displayName="..." id="33">
                  <case id="64">
                    <condition expressionLanguage="..."><![CDATA[(c4)]]></condition>
                  </case>
                  <otherwise id="108">
                  </otherwise>
                </switch>
            </otherwise>
          </switch>
        </otherwise>
      </switch>
</root>

输出

if ( (c1) ) {
}
else {
    if ( (c2) ) {
        if ( (c3) >0) ) {
        }
        else {
        }
    }
    else {
        if ( (c4) ) {
        }
        else {
        }
    }
}

【讨论】:

  • 您好 Borodin,感谢您花时间回答我的问题。如果我的问题不清楚,我很抱歉。实际上,我发布的 XML 输入只是一种格式,实际输入的 XML 文件更复杂,它包括其他相同的开关块和其他 XML 标记。所以,我需要一个子程序来获取基于标签的块以及@_输入和另一个子程序来分析得到的块并在此进行递归。
  • @Kamogawa:据我所知,我的回答解决了您的问题。为什么你认为它没有?你试过了吗?
  • 当我运行你的代码时,有一个问题是它只保留 [CDATA[....]] 中的数据,并删除除了 Switch 块之外的其他块类型。例如,在 Switch 块之前我有其他块:` `我要保留将此块转换为另一种格式。
  • 另外,对于if--else的条件,你能告诉我如何将条件(例如:C3 > 0)变成一个字符串来处理。提前谢谢!
  • @Kamogawa:所有这些都是全新的。您在原始问题中没有提及任何有关它的内容。我已经花了很长时间来解决您的问题,我不会再做任何事情了,尤其是因为您似乎根本没有自己做任何努力。
猜你喜欢
  • 1970-01-01
  • 2013-11-29
  • 1970-01-01
  • 1970-01-01
  • 2016-07-09
  • 2019-05-28
  • 1970-01-01
  • 2021-07-01
  • 1970-01-01
相关资源
最近更新 更多