XStream:如何在编组的 XML 中隐藏 2 个不必要的父节点?

Posted

技术标签:

【中文标题】XStream:如何在编组的 XML 中隐藏 2 个不必要的父节点?【英文标题】:XStream: how can I hide 2 unnecessary parent nodes in marshaled XML? 【发布时间】:2014-01-03 06:43:10 【问题描述】:

在一个单元测试项目中,我需要一些帮助来弄清楚如何在编组的 XML 中隐藏 2 个不必要的父节点?谁能帮我弄清楚怎么做?

我的marshalled output 看起来像这样:

<suite>
  <suiteName>Suite 1</suiteName>
  <sauceURL>http://username-string:access-key-string@ondemand.saucelabs.com:80/wd/hub</sauceURL>
  <tests>
    <test>
      <rowArgs>
        <arg>
          <enabled type="java.lang.Boolean">true</enabled>
        </arg>
        <arg>
          <testname type="java.lang.String">Test 1</testname>
        </arg>
        <arg>
          <environment type="java.lang.String">portal1</environment>
        </arg>
        <arg>
          <testlocale type="java.lang.String">Grid</testlocale>
        </arg>
        <arg>
          <browser type="java.lang.String">Firefox</browser>
        </arg>
        <arg>
          <url type="java.lang.String">http://google.com</url>
        </arg>
      </rowArgs>
    </test>
            ...

但我想隐藏不必要的“rowArgs”和“arg”标签,以便其余节点立即位于测试节点下。我该怎么做?

你可以see my code HERE, if it helps你来帮助我。我怀疑我需要编写自己的变压器?与此同时,我会进行那个实验。

【问题讨论】:

【参考方案1】:

确实,您将需要一个自定义转换器,因为它是您不想显示的两个嵌套集合,并且这些对象可能具有其他将被序列化的子元素。

XStream 没有直接涵盖这种情况,但可以使用自定义转换器轻松修复。

您可以在包含所有这些修改的git clone of your project 中找到所有这些。但由于所有内容都应该在这里可见,我随后解释了问题的关键部分,包括一些代码示例。

我为您的项目实现了这样的转换器。进行转换的代码是这样的:

  @Override
  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) 
    TestRow test = (TestRow)source;
    for (TestArguments arg : test.getArguments()) 
      for (ArgObject val : arg.getAllTestArguments()) 
        writer.startNode(val.getKey());
        writer.addAttribute("type", val.getType());
        writer.setValue(val.getVal());
        writer.endNode();

      
    
  

  @Override
  public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) 
    TestArguments testargs = new TestArguments();
    while (reader.hasMoreChildren()) 
      reader.moveDown();
      String typeval = reader.getAttribute("type");
      if (typeval.isEmpty()) 
        typeval = "null";
      
      testargs.getAllTestArguments().add(new ArgObject(reader.getNodeName(), typeval, reader.getValue()));
      reader.moveUp();
    
    TestRow result = new TestRow(testargs);
    return result;
  

这将使用您在ArgConverter 中定义的平面节点结构将所有 ArgObject 序列化为 xml。反序列化会根据这些数据创建对象。

您的源代码中有两个错误阻止了反序列化:

XStream 反序列化无法识别所有别名注释。您的根元素 SuiteData(别名为套件)存在问题。为此,我在您的 XMLDataHelper 中为 XStream 对象添加了一个别名,例如 xStream.alias("suite", SuiteData.class);。 如果您创建一个带有默认构造函数的TestArguments 实例(因为您必须通过反序列化),您调用reset 将您的argsWrapper 成员分配给null,这使得添加参数变得非常不可能。我修复了在重置方法中重新初始化该成员变量的问题 (argsWrapper = new ArrayList&lt;ArgObject&gt;();)。

据我了解您的代码,这可以按预期进行序列化/反序列化。我写了一个小测试程序来强制这个过程,它似乎产生了相同的结果:

public class XMLDataHelperTest 

  public static void main(String[] args) 
    File file = new File(System.getProperty("user.dir"), "test.xml");
    if (file.isFile()) 
      assertTrue(file.delete());
    

    // write it once
    XMLDataHelper helper = new XMLDataHelper(file.getAbsolutePath());

    // read it once
    helper = new XMLDataHelper(file.getAbsolutePath());
    System.out.println(file);
  

【讨论】:

是的,它看起来有效。我更新了我的回购。我只需要在 TestArguments 类的 set 方法中修复我的解组中的一个小错误。谢谢。

以上是关于XStream:如何在编组的 XML 中隐藏 2 个不必要的父节点?的主要内容,如果未能解决你的问题,请参考以下文章

在java中编组时如何更改xml元素名称

如何将对象序列化为 CSV 文件?

xStream 问题 - 如何反序列化多个对象

如何从map [string] interface {}编组XML?

XStream将XML转换为JAVA对象快速指南

如何在 XStream 中禁用不必要的转义?