Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在使用SAX进行解析时保留未绑定到对象的XML节点_Java_Android_Xml_Sax - Fatal编程技术网

Java 如何在使用SAX进行解析时保留未绑定到对象的XML节点

Java 如何在使用SAX进行解析时保留未绑定到对象的XML节点,java,android,xml,sax,Java,Android,Xml,Sax,我正在开发一款android应用程序,它与蓝牙摄像头接口。对于存储在相机上的每个剪辑,我们将有关剪辑的一些字段(其中一些用户可以更改)存储在XML文件中 目前,此应用程序是唯一一个将xml数据写入设备的应用程序,但将来,桌面应用程序或iphone应用程序也可能在此处写入数据。我不想假设另一个应用程序也不能有额外的字段(特别是如果他们有一个新版本的应用程序,其中添加了这个版本还不支持的新字段) 所以我要防止的是,我们在另一个应用程序中向这个XML文件添加新字段,然后用户使用android应用程序,

我正在开发一款android应用程序,它与蓝牙摄像头接口。对于存储在相机上的每个剪辑,我们将有关剪辑的一些字段(其中一些用户可以更改)存储在XML文件中

目前,此应用程序是唯一一个将xml数据写入设备的应用程序,但将来,桌面应用程序或iphone应用程序也可能在此处写入数据。我不想假设另一个应用程序也不能有额外的字段(特别是如果他们有一个新版本的应用程序,其中添加了这个版本还不支持的新字段)

所以我要防止的是,我们在另一个应用程序中向这个XML文件添加新字段,然后用户使用android应用程序,它会清除其他字段,因为它不知道这些字段

让我们举一个假设的例子:

<data>
  <title>My Title</title>
  <date>12/24/2012</date>
  <category>Blah</category>
</data>
因此,我使用SAX解析数据并将其存储到片段中。 我只需将字符存储在StringBuilder中,并在到达title、category和date的结束元素时将其写出

我意识到,当我将这些数据写回设备时,如果原始文档中有任何其他标记,它们将不会被写入,因为我只写出我知道的字段

这让我觉得也许SAX是错误的选择,也许我应该使用DOM或其他更容易写出最初存在的任何其他元素的东西

或者,我想我的Clip类可能包含某种通用XML类型(可能是DOM)的ArrayList,在startTag中,我检查元素是否不是预定义的标记之一,如果是,在到达该标记的末尾之前,我存储整个结构(但存储在什么中?)。。然后在写回时,我只需遍历所有附加的标记,并将它们写入xml文件(当然还有我知道的字段)

这是众所周知的解决方案的常见问题吗

--更新日期:2012年5月22日--

我没有提到在实际的xml根节点(实际上称为注释)中,我们使用的版本号已设置为1。短期内我要做的是要求我的应用程序支持的版本号>=xml数据的版本号。如果xml是一个更大的数字,我将尝试解析以便读回,但将拒绝对模型进行任何保存。我仍然对如何实现这一点的任何工作示例感兴趣

顺便说一句,我想到了另一个很简单的解决方案。我想我可以使用XPATH查找我知道的节点,并在数据更新时替换这些节点的内容。然而,我运行了一些基准测试,当xml被解析到内存中时,解析xml的开销是荒谬的。仅仅是解析操作而不进行任何查找就导致性能比SAX差20倍。。一般来说,使用xpath进行解析的速度要慢30-50倍,考虑到我在列表视图中解析它们,这是非常糟糕的。 因此,我的想法是保持SAX将节点解析为Clip,但将整个XML存储在Clip类的一个变量中(记住,这个XML很短,小于2kb)。然后,当我要写回数据时,我可以使用XPATH替换掉我知道的原始XML中的节点


但仍然对其他解决方案感兴趣。我可能不会接受一个解决方案,除非它包含了一些代码示例。

如果你没有绑定到一个特定的XML模式,你应该考虑这样做:

<data>
    <element id="title">
        myTitle
    </element>
    <element id="date">
         18/05/2012
    </element>
    ...
</data>

我的头衔
18/05/2012
...
然后将所有这些元素存储在单个ArrayList中。
这样,您就不会丢失信息,而且您仍然可以选择要显示的元素-编辑-等等。

如果您想保留尚未“使用”的节点,您可以说SAX可能不是最佳选择。您仍然可以使用某种类型的“sax存储”来保存sax事件并重放它们(有一些类似的实现),但是基于对象模型的API将更易于使用:您可以轻松地保留完整的对象模型并只更新“您的”节点


当然,你可以使用DOM,它是<强> 标准,但是你也可以考虑一些替代方案,它可以更容易地访问你将在任意数据模型中使用的特定节点。其中,JDOM()和XOM()是很有意思的候选对象。

以下是您可以使用的方法:

  • 当您使用SAX阅读文档时,您可以记录所有事件。您可以记录它们,并将它们进一步冒泡到SAX阅读器的下一个级别。基本上,您将两层SAX读取器(使用)堆叠在一起—一层将记录和中继,另一层是当前创建对象的SAX处理程序
  • 当您准备将修改写回磁盘时,您将触发记录的SAX事件,该事件与写入器一起分层,将覆盖您所更改的值/节点
  • 我花了一些时间研究这个想法,它成功了。它基本上归结为
    XMLFilter
    s的正确链接。下面是您的代码执行类似操作的方式:

    final SAXParserFactory factory = SAXParserFactory.newInstance();
    final SAXParser parser = factory.newSAXParser();
    
    final RecorderProxy recorder = new RecorderProxy(parser.getXMLReader());
    final ClipHolder clipHolder = new ClipHolder(recorder);
    
    clipHolder.parse(new InputSource(new StringReader(srcXml)));
    
    assertTrue(recorder.hasRecordingToReplay());
    
    final Clip clip = clipHolder.getClip();
    assertNotNull(clip);
    assertEquals(clip.title, "My Title");
    assertEquals(clip.category, "Blah!");
    assertEquals(clip.date, Clip.DATE_FORMAT.parse("12/24/2012"));
    
    clip.title = "My Title Updated";
    clip.category = "Something else";
    
    final ClipSerializer serializer = new ClipSerializer(recorder);
    serializer.setClip(clip);
    
    final TransformerFactory xsltFactory = TransformerFactory.newInstance();
    final Transformer t = xsltFactory.newTransformer();
    final StringWriter outXmlBuffer = new StringWriter();
    
    t.transform(new SAXSource(serializer, 
                new InputSource()), new StreamResult(outXmlBuffer));
    
    assertEquals(targetXml, outXmlBuffer.getBuffer().toString());
    
    重要的方面是:

    • 您的语法是围绕SAX解析器进行的
    • 您的
      片段
      解析器()被包裹在记录器周围
    • 解析XML时,记录器将记录所有内容,而您的
      ClipHolder
      将只查看它所知道的内容
    • 然后你做你需要做的一切
    • 然后将数据包绕在记录器上(基本上将其重新映射到自身上)
    • 然后,您使用序列化程序,它将负责提供记录的事件(委托给父对象,并将
      self
      注册为
      ContentHandler
      ),并覆盖它对
      clip
      对象的说明

    final SAXParserFactory factory = SAXParserFactory.newInstance(); final SAXParser parser = factory.newSAXParser(); final RecorderProxy recorder = new RecorderProxy(parser.getXMLReader()); final ClipHolder clipHolder = new ClipHolder(recorder); clipHolder.parse(new InputSource(new StringReader(srcXml))); assertTrue(recorder.hasRecordingToReplay()); final Clip clip = clipHolder.getClip(); assertNotNull(clip); assertEquals(clip.title, "My Title"); assertEquals(clip.category, "Blah!"); assertEquals(clip.date, Clip.DATE_FORMAT.parse("12/24/2012")); clip.title = "My Title Updated"; clip.category = "Something else"; final ClipSerializer serializer = new ClipSerializer(recorder); serializer.setClip(clip); final TransformerFactory xsltFactory = TransformerFactory.newInstance(); final Transformer t = xsltFactory.newTransformer(); final StringWriter outXmlBuffer = new StringWriter(); t.transform(new SAXSource(serializer, new InputSource()), new StreamResult(outXmlBuffer)); assertEquals(targetXml, outXmlBuffer.getBuffer().toString());