如何解析可能有或没有命名空间的XML内容? [英] How do I parse XML content that may or may not have a namespace?

查看:275
本文介绍了如何解析可能有或没有命名空间的XML内容?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要解析一些我拥有XSD的XML内容。总的来说,这是直截了当的。但是,在一个特定情况下,XML有时包含XML命名空间,有时则不包含。此外,要求XML命名空间并不实际,因为提供的XML来自多个来源。所以我一直试图找到解决方法。

I need to parse some XML content for which I have the XSD. In general, this is straight-forward. However, in one particular case, the XML sometimes includes the XML namespace and sometimes it does not. Further, it is not really practical to require the XML namespace, as the supplied XML comes from multiple sources. So I'm stuck with trying to find a way around this.

如上所述,我有XML的XSD,我使用XJC(来自JAXB)来生成来自XSD的相应XML实体类。

As noted, I have the XSD for the XML and I have used XJC (from JAXB) to generate the corresponding XML entity classes from the XSD.

示例XML包括命名空间:

Sample XML including the namespace:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.w3.org/namespace/">
    <foo id="123>
        <bar>value</bar>
    </foo>
</root>

不包括命名空间的示例XML:

Sample XML excluding the namespace:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <foo id="123>
        <bar>value</bar>
    </foo>
</root>

如您所见,XML内容在结构上是相同的 - 唯一的区别是<$ c root 实体上的$ c> xmlxs 属性。

As you can see, the XML content is identical in structure - the only difference is the xmlxs attribute on the root entity.

我的代码如下:

URI uri = <URI of XML file>
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
Node node = builder.parse(uri.toString()); // Parsing succeeds, ie. the XML is valid.
JAXBContext context = JAXBContext.newInstance("com.example.xml");
Unmarshaller parser = context.createUnmarshaller();
// Next line succeeds or fails, depending on presence of namespace
Object object = parser.unmarshal(node);

XML总是被成功解析为节点。如果XML中存在 xmlns 属性,则整个过程正常完成,并且我收到 com.example.xml.Root <的实例/ code> class(使用XJC生成)。从那里我可以访问 Foo Bar 对象。

The XML is always successfully parsed into a Node. If the xmlns attribute is present in the XML, then the entire process completes normally and I receive an instance of a com.example.xml.Root class (which was generated using XJC). From there I can access the Foo and Bar objects.

如果 xmlns 属性不存在,则解组将失败,并出现以下异常:

If the xmlns attribute is absent, then the unmarshalling fails with the following exception:

javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"root").
    Expected elements are <{http://www.w3.org/namespace/}root>,
    <{http://www.w3.org/namespace/}foo>,
    <{http://www.w3.org/namespace/}bar>

我试过按声明类型进行非组合式处理,但成效有限。具体来说,解组完成没有错误。但是,生成的 Root 类不包含任何 Foo Bar 对象。

I tried unmarmshalling by declared type with limited success. Specifically, the unmarshalling completed without error. However, the resulting Root class did not contain any Foo or Bar objects.

此代码涉及将最后一行更改为:

The code for this involves changing the last line to:

Object object = parser.unmarshal(node, Root.class);

我尝试将namespace aware标志设置为 false ,但是失败并出现错误。

I tried unmarshalling with the "namespace aware" flag set to false, but this failed with an error.

我考虑过向节点添加命名空间如果没有,则在解组之前。然而,API似乎不允许这样做。

I've thought about adding a namespace to the node if it does not have one, prior to unmarshalling. However the API does not seem to permit this.

我的另一个想法是拥有两组生成的类,每种情况一个(即命名空间,没有命名空间) 。然而,这似乎是一个很大的问题。

Another thought I had was to have two sets of generated classes, one for each case (ie. namespace, no namespace). However this seems like too much of a kludge.

所以我被困了?有什么建议?或者我正在尝试做什么不可能?

So I'm stuck? Any suggestions? Or is what I'm trying to do impossible?

推荐答案

您可以使用XML过滤器。这是我的例子,删除它所在的ns。

You can do with an XML Filter. Here is my example for you, to remove the ns where it's present.

package testjaxb;

import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.sax.SAXSource;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.helpers.XMLReaderFactory;

public class MarshalWithFilter {

    public static void main(String[] args) throws Exception {
        String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<root xmlns=\"http://www.w3.org/namespace/\">\n"
                + "    <foo id=\"123\">\n"
                + "        <bar>value</bar>\n"
                + "    </foo>\n"
                + "</root>";

        String xmlStringWithoutNs = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                + "<root>\n"
                + "    <foo id=\"123\">\n"
                + "        <bar>value</bar>\n"
                + "    </foo>\n"
                + "</root>";

        Root r = (Root) unmarshal(xmlString);
        System.out.println("root.." + r.getFoo().getId());
        System.out.println("root.." + r.getFoo().getBar());
        r = (Root) unmarshal(xmlStringWithoutNs);
        System.out.println("root.." + r.getFoo().getId());
        System.out.println("root.." + r.getFoo().getBar());
    }

    private static Root unmarshal(String sampleXML) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        XMLReader reader = XMLReaderFactory.createXMLReader();
        IngoreNamespaceFilter nsFilter = new IngoreNamespaceFilter();
        nsFilter.setParent(reader);
        StringReader stringReader = new StringReader(sampleXML);
        InputSource is = new InputSource(stringReader);
        SAXSource source = new SAXSource(nsFilter, is);
        System.out.println("" + sampleXML);
        return (Root) unmarshaller.unmarshal(source);
    }
}

class IngoreNamespaceFilter extends XMLFilterImpl {

    public IngoreNamespaceFilter() {
        super();
    }

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
    }

    @Override
    public void startElement(String arg0, String arg1, String arg2,
            Attributes arg3) throws SAXException {

        super.startElement("", arg1, arg2, arg3); //Null uri
    }

    @Override
    public void endElement(String arg0, String arg1, String arg2)
            throws SAXException {

        super.endElement("", arg1, arg2); //null url
    }

    @Override
    public void startPrefixMapping(String prefix, String url)
            throws SAXException {
        //ignore namessopace

    }

}

以下是Pojos:


Root

Root



package testjaxb;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="root")
@XmlAccessorType(XmlAccessType.FIELD)
public class Root
{
    private Foo foo;


    public Foo getFoo ()
    {
        return foo;
    }

    public void setFoo (Foo foo)
    {
        this.foo = foo;
    }


}




Foo

Foo



package testjaxb;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;


@XmlAccessorType(XmlAccessType.FIELD)
public class Foo
{
    @XmlAttribute
    private String id;

    private String bar;

    public String getId ()
    {
        return id;
    }

    public void setId (String id)
    {
        this.id = id;
    }

    public String getBar ()
    {
        return bar;
    }

    public void setBar (String bar)
    {
        this.bar = bar;
    }


}

这篇关于如何解析可能有或没有命名空间的XML内容?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆