【问题标题】:Jumping between XML tags在 XML 标记之间跳转
【发布时间】:2009-09-18 09:00:50
【问题描述】:

这是 SAX 中的一个疑问。 我想处理 XML 文件中的子标签,前提是它与父标签匹配。 例如:

<version>
    <parent tag-1>
       <tag 1>
       <tag 2>
     </parent tag-1 >
     <parent tag-2>
       <tag 1>
       <tag 2>
     </parent tag-2>
</version>

在上面的代码中,我想先匹配父标签(即父标签-1或父标签``-2,根据用户输入),然后才处理它下面的子标签。 这可以在 SAX 解析器中完成吗,请记住 SAX 对 DOM 的控制有限,而且我是 SAX 和 Java 的新手?如果是这样,请您引用相应的方法吗? TIA

【问题讨论】:

  • 请修复您的 XML,这是无效的。

标签: java xml sax


【解决方案1】:

当然,记住父标签就可以轻松完成。

一般来说,在解析xml标签时,人们使用stack来跟踪这些标签的family map。您的情况可以使用以下代码轻松解决:

Stack<Tag> tagStack = new Stack<Tag>();

public void startElement(String uri, String localName, String qName,
        Attributes attributes)
     if(localName.toLowerCase().equals("parent")){
          tagStack.push(new ParentTag());
     }else if(localName.toLowerCase().equals("tag")){
          if(tagStack.peek() instanceof ParentTag){
               //do your things here only when the parent tag is "parent"
          }
     }
}
public void endElement(String uri, String localName, String qName)
        throws SAXException{
     if(localName.toLowerCase().equals("parent")){
          tagStack.pop();
     }
}

或者你可以通过更新标签名来简单地记住你在哪个标签中:

String tagName = null;
public void startElement(String uri, String localName, String qName,
        Attributes attributes)
     if(localName.toLowerCase().equals("parent")){
          tagName = "parent";
     }else if(localName.toLowerCase().equals("tag")){
          if(tagName!= null && tagName.equals("parent")){
               //do your things here only when the parent tag is "parent"
          }
     }
}
public void endElement(String uri, String localName, String qName)
        throws SAXException{
     tagName = null;
}

但我更喜欢堆栈方式,因为它会跟踪你所有的祖先标签。

【讨论】:

  • @chen:这仍然需要遍历整个 xml 文件,不是吗?我可以搜索和匹配父标签,只有在匹配发生时才处理子标签?
  • 好吧。一旦您启动 Sax,它就已经准备好扫描整个文档。但是,如果您将代码放入我提供给您的任何示例中,一旦执行触及您的代码,它们就会运行。换句话说,当你的 sax 结束时,你想让你的代码做的任何事情都已经完成了。
  • 好的。所以 SAX 没有提供跳转到标签的方法,是吗?
  • 不是我所知道的。 Sax 沿着文档走,触发 startElement、endElement 和其他预定义的方法来完成任务。这是一个非常好的教程:developerlife.com/tutorials/?p=29#50616
  • 还有其他解析器提供跳转标签的方法吗?
【解决方案2】:

无论如何,如果您出于性能原因考虑这样做,SAX 会假脱机处理整个文档。

但是,从代码美观的角度来看,您可以让 SAX 解析器不返回不匹配的子代,方法是使用 XMLFilter 连接它。您可能仍然需要自己编写逻辑 - 类似于 Wing C. Chen's post 中提供的内容 - 但您可以将其抽象为过滤器实现,而不是将其放在应用程序逻辑中。

这将使您更轻松地重用过滤逻辑,并且可能使您的应用程序代码更简洁且更易于遵循。

【讨论】:

    【解决方案3】:

    @Wing C. Chen 提出的解决方案非常不错,但在您的情况下,我不会使用堆栈。

    解析 XML 时堆栈的用例

    堆栈和 XML 的一个常见用例是,例如,在使用您自己的词法分析器(即具有容错能力的手工制作的 XML 解析器)时验证 XML 标记是否平衡。

    一个具体的例子是为 Eclipse IDE 构建 XML 文档的大纲。

    何时使用 SAX、Pull 解析器等

    • 解析大型 XML 文件时的内存效率

    • 您无需在文档中来回导航。

    但是,使用 SAX 解析复杂文档可能会变得乏味,尤其是如果您想根据某些条件对节点应用操作。

    何时使用类似 API 的 DOM

    • 您希望轻松访问节点

    • 您想随时在文档中来回导航

    • 与开发时间/可读性/维护相比,速度不是主要要求

    我的建议

    如果您没有庞大的 XML,请使用类似 DOM 的 API 并使用 XPath 选择节点。 我个人更喜欢 Dom4J,但我不介意 JDom 甚至支持 XPath 的 Xpp3 等其他 API。

    【讨论】:

    • 这很有帮助,但我想我不需要保存任何内容,因此打算继续使用 SAX 解析器。感谢您的加入。
    【解决方案4】:

    SAX 解析器将在您的实现中调用一个方法,每次它遇到一个标记。如果您想要根据父级的不同行为,则必须将其保存到变量中。

    【讨论】:

      【解决方案5】:

      如果你想跳转到特定的标签,那么你需要使用 DOM 解析器。这会将整个文档读入内存,然后提供访问树的特定节点的各种方法,例如按名称请求标签,然后请求该标签的子节点。

      因此,如果您不限于 SAX,那么我会推荐 DOM。我认为在 DOM 上使用 SAX 的主要原因是 DOM 需要更多内存,因为一次加载整个文档。

      【讨论】:

      • 它实际上是一个 200 行长的 XML 文件。由于任何解析器都必须至少经过一次,我只需要匹配一个子标签并获取它的属性,我想我会去的领先于 SAX。感谢您的光临!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-25
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多