- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在使用 VTD-XML 并且正在提取 XML 文档的子元素,我需要检索父 XML 根元素的所有命名空间声明。我目前正在通过以下方式检索所有命名空间声明:
AutoPilot ap = new AutoPilot( vNav );
int tokenCount = vNav.getTokenCount();
String token = null;
String nsPrefix = null;
String nsUri = null;
for ( int i = 0; i < tokenCount; i++ ) {
token = vNav.toNormalizedString( i );
if ( vNav.startsWith( i, "xmlns:" ) ) {
nsPrefix = token.substring( token.indexOf( ":" ) + 1 );
nsUrl = vNav.toNormalizedString( i + 1 );
ap.declareXPathNameSpace( nsPrefix, nsUrl );
}// if
}// for
这为我提供了整个文档的所有 namespace 声明,但是,有没有一种方法可以检索 ONE 元素的 namespace 声明?
最佳答案
这是我在大型 XML 处理过程中使用的类。
一些注意事项:
<elem />
是 <elem xmlns="x" />
的 sibling 他们有不同的命名空间代码:
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import javax.xml.namespace.QName;
import org.springframework.util.xml.SimpleNamespaceContext;
import com.ximpleware.NavException;
import com.ximpleware.VTDNav;
public class VtdXmlCurrentState
{
/* Stack of QName.toString()s for the elements of processed XML - each is a full path */
private Deque<String> qnames = new LinkedList<String>();
/* Stack of QName.toString()s for the elements - each is a single path element and doesn't contain "/" */
private Deque<QName> names = new LinkedList<QName>();
// current depth in input document, starting from -1
private int currentDepth = -1;
// stack of namespace contexts increased during xml depth-first VTD navigation */
private Deque<SimpleNamespaceContext> namespaces = new LinkedList<SimpleNamespaceContext>();
// a flag for optimizing the case when there are many sibling elements without any xmlns declarations
// the case:
// <el />
// <el />
// ...
// it allows to effectively manage the stack and properly handles the following case:
// <el xmlns="x" />
// <el />
// in which the second element should use NSContext from parent and not a copy of sibling's NSContext
private boolean lastNSContextsDifferent = false;
/**
*
*/
public VtdXmlCurrentState()
{
// first a context without any mapping
this.namespaces.push(new SimpleNamespaceContext());
// first QName is "/"
this.qnames.push("/");
this.names.push(null);
}
/**
* Name of the current element
* @return
*/
public QName currentElementName()
{
return this.names.peek();
}
/**
* Returns parent and current path for VTDNav
*
* @param nav
* @return
* @throws NavException
*/
public String[] currentXPath(VTDNav nav) throws NavException
{
// we don't check the end - autopilot handles that
int depth = nav.getCurrentDepth();
int idx = nav.getCurrentIndex();
this.handleNamespaces(nav, depth);
// determining current XPath
// name of the current element (optimization, because we're that the token is START_ELEMENT)
String elName = nav.toRawString(nav.getTokenOffset(idx), nav.getTokenLength(idx) & 0xffff);
QName qName = null;
if (elName.contains(":")) {
String[] qname = elName.split(":");
qName = new QName(this.namespaces.peek().getNamespaceURI(qname[0]), qname[1]);
} else {
qName = new QName(this.namespaces.peek().getNamespaceURI(""), elName);
}
// full name of the current element
StringBuilder sb = new StringBuilder(1024);
String fullName = null;
for (int i = 0; i <= this.currentDepth - depth; i++) {
this.qnames.pop();
this.names.pop();
}
fullName = sb.append(this.qnames.peek()).append(qName.toString()).append("/").toString();
String parentName = this.qnames.peek();
this.qnames.push(fullName);
this.names.push(qName);
this.currentDepth = depth;
return new String[] { parentName, fullName };
}
/**
* Handling element's namespaces - if there are any xmlns[:x], we must create new NSContext
*
* @param nav
* @param depth
* @throws NavException
*/
private void handleNamespaces(VTDNav nav, int depth) throws NavException
{
// are there any ns declarations?
Map<String, String> _namespaces = null;
int index = nav.getCurrentIndex() + 1;
int total = nav.getTokenCount();
while (index < total) {
int type = nav.getTokenType(index);
while (type == VTDNav.TOKEN_ATTR_NAME) {
// quickly skip non-xmlns attrs
index += 2;
type = nav.getTokenType(index);
}
if (type == VTDNav.TOKEN_ATTR_NS) {
String prefix = nav.toString(index).substring(5);
if (prefix.length() > 0)
prefix = prefix.substring(1);
String namespace = nav.toString(index + 1);
if (_namespaces == null)
_namespaces = new HashMap<String, String>();
_namespaces.put(prefix, namespace);
} else if (type == VTDNav.TOKEN_ATTR_VAL) {
} else {
break;
}
index++;
}
if (_namespaces != null) {
// first remove (if necessary) previous contexts from the stack - even if new element is at the same level
// (not descendant - it's sibiling), remove old, push new
for (int i = 0; i <= this.currentDepth - depth; i++)
this.namespaces.pop();
// for this element there's xmlns declaration - this element has different namespace context
// and it will be valid till the next descendant with xmlns
// previous context
SimpleNamespaceContext snc = this.namespaces.peek();
// new ...
SimpleNamespaceContext newSnc = new SimpleNamespaceContext();
// ... to which we'll copy previous declarations
for (Iterator<?> prefixes = snc.getBoundPrefixes(); prefixes.hasNext();) {
String pfx = (String)prefixes.next();
newSnc.bindNamespaceUri(pfx, snc.getNamespaceURI(pfx));
}
newSnc.bindNamespaceUri("", snc.getNamespaceURI(""));
// adding (overwriting!) new namespace mappings
newSnc.setBindings(_namespaces);
this.namespaces.push(newSnc);
this.lastNSContextsDifferent = true;
} else {
// current element doesn't define new namespaces - it gets them from parent element
// optimization - no new namesaces, the same level - we don't do anything!
// we only do something if we got a level up - we have to pop some ns contexts
for (int i = 0; i < this.currentDepth - depth; i++)
this.namespaces.pop();
if (this.currentDepth > depth) {
// we went up and popped() too much ns contexts - we duplicate the most recent
this.namespaces.push(this.namespaces.peek());
} else if (this.currentDepth < depth) {
// we went down - just copy
this.namespaces.push(this.namespaces.peek());
} else {
// the same level
if (this.lastNSContextsDifferent) {
this.namespaces.pop();
this.namespaces.push(this.namespaces.peek());
}
}
this.lastNSContextsDifferent = false;
}
}
}
输入 XML:
<?xml version="1.0" encoding="UTF-8"?>
<set id="#1" xmlns="urn:test:1.0">
<documents xmlns="urn:test:1.0">
<doc xmlns="urn:test:1.1" />
<doc />
<doc xmlns="urn:test:1.2" />
</documents>
<documents />
<documents xmlns="" />
</set>
使用类:
byte[] doc = FileCopyUtils.copyToByteArray(super.createResource("dom03.xml").getInputStream());
VTDGen vtd = new VTDGen();
vtd.setDoc(doc);
vtd.parse(true);
VTDNav nav = vtd.getNav();
AutoPilot ap = new AutoPilot();
ap.bind(nav);
ap.selectElementNS("*", "*");
VtdXmlCurrentState cxp = new VtdXmlCurrentState();
ap.iterate();
assertEquals("/{urn:test:1.0}set/", cxp.currentXPath(nav)[1]);
ap.iterate();
assertEquals("/{urn:test:1.0}set/{urn:test:1.0}documents/", cxp.currentXPath(nav)[1]);
ap.iterate();
assertEquals("/{urn:test:1.0}set/{urn:test:1.0}documents/{urn:test:1.1}doc/", cxp.currentXPath(nav)[1]);
ap.iterate();
assertEquals("/{urn:test:1.0}set/{urn:test:1.0}documents/{urn:test:1.0}doc/", cxp.currentXPath(nav)[1]);
ap.iterate();
assertEquals("/{urn:test:1.0}set/{urn:test:1.0}documents/{urn:test:1.2}doc/", cxp.currentXPath(nav)[1]);
ap.iterate();
assertEquals("/{urn:test:1.0}set/{urn:test:1.0}documents/", cxp.currentXPath(nav)[1]);
ap.iterate();
assertEquals("/{urn:test:1.0}set/documents/", cxp.currentXPath(nav)[1]);
assertFalse(ap.iterate());
关于java - 如何使用 VTD-XML 获取 ONE 元素的所有命名空间声明?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8619208/
因为如果线程安全,我可以在整个应用程序中仅使用VTDGen的一个实例。 现在,我为每个请求实例化一个新的VTDGen,我正在考虑将其设置为static,以便仅对其进行一次初始化。 最佳答案 线程安全到
问题是有些 xml 文件在 xml 中没有可用的 header 信息。解析 xml 文件时,vtd-xml 默认使用 utf-8 并抛出异常,提示无法解析文档。 (xml 编码是 8859-2,但没有
使用Java 2.11版本。我正在基于 CD Catalog 数据绑定(bind)示例构建 xml 绑定(bind)组件。我有一个相当复杂但相当小的文档,大约 2000 字节。而且 AutoPilot
我有巨大的 xml,因此我有很多 xpath 来从 xml 中提取条目。所以我尝试生成多个线程,以便每个 xpath 可以在不同的线程中进行评估。但是我收到以下错误是可以给出一个公平想法的代码片段,为
我用java实现了VTD-Parser,它成功地轻松解析了大约500 MB的XML文件,并且能够在Excel中写入。我理解DOM解析器首先创建树节点结构然后获取数据,而SAX是基于事件的解析器。但是是
我在使用 vtd-xml 库(版本 2.11)时遇到编码问题。 @Test public void test() throws Exception { final String
在VTDNav docs我看到了获取 attrubites 的值、获取元素的文本值的方法,但我真的找不到,如何获取当前元素的标签名称? 最佳答案 vn.toRawString(vn.getCurren
我正在尝试解析以下 XML 并创建与主要元素相对应的 Java 对象: wood 12 ... someone 200
我决定使用 VTD-Xml 来解析一个非常大的文件。它工作得很好,但在解析过程中,可以进行验证检查,必须使用已验证字段(行和列)的位置进行记录。我找不到任何方法来使用 VTD 至少获取元素的行号。而且
我正在处理平均 18 MB 的 XML,其中 XPaths 大量使用谓词。我尝试分析处理过程(预热 JVM),平均处理时间为 20 秒。我想知道是否有使它更快的技术?比如避免使用谓词? 最佳答案 如果
嘿,我正在尝试使用 VTD-XML 来解析作为字符串提供给它的 XML,但我找不到如何去做。任何帮助将不胜感激。 http://vtd-xml.sourceforge.net 最佳答案 VTD-XML
我在尝试通过 getElementFragmentNs 提取元素时遇到问题。 这里是示例测试: @Test public void shouldNotShadowNamespaceAn
我正在尝试使用 VTD-XML 从父元素中删除一组子元素。 不幸的是,删除元素后,它会留下被删除元素先前占用的新行。 VTD-XML 作者 here 撰写的有关 VTD-XML 的文章的读者也观察到了
我有以下 XML 片段,我想使用 Ximpleware/VTD-XML 从中剥离属性并输出为新的 XML。来源: 目标: 我知道我可以使用 removeAttrib
我有一个 xpath 查询,我可以获得所有属性及其各自的值 但现在我想知道这些属性属于哪个元素? 这是我的 xml:
这个问题已经有答案了: Compile Error: Cannot Find Symbol (2 个回答) 已关闭 7 年前。 我不是 Java 程序员,但需要编写 Java 程序来解析大型(400m
使用 VTD-XML 解析器我该怎么做? 1 2 3 1 2
我有一个 XML block ,如下所示,其中包含 3 个 AttachmentBinary 元素(尽管为了可读性而被截断): 219 /9j/4UK8RXhpZgAAS
给定属性的 xpath 和新值,我希望将属性值更新为新值。 我按照这里的例子:http://vtd-xml.sourceforge.net/codeSample/cs7.html并提出以下内容: au
我有一个像这样的 XML: 1 2 3 4 是否可以使用 Java 和 VT
我是一名优秀的程序员,十分优秀!