JAXB:XML 문서를 언마샬링하는 동안 네임스페이스를 무시하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/277502

문제

내 스키마는 네임스페이스를 지정하지만 문서는 그렇지 않습니다.JAXB 언마샬링(XML -> 객체) 중에 네임스페이스를 무시하는 가장 간단한 방법은 무엇입니까?

즉, 나는

<foo><bar></bar></foo>

대신에,

<foo xmlns="http://tempuri.org/"><bar></bar></foo>
도움이 되었습니까?

해결책

나는 당신이해야한다고 믿습니다 네임 스페이스를 추가하십시오 예를 들어, XML 문서에 색소폰 필터.

그것의 의미는:

  • JAXB가 얻을 수 있기 전에 SAX 이벤트를 가로채는 새로운 클래스로 Contenthandler 인터페이스를 정의하십시오.
  • 컨텐츠 핸들러를 설정하는 xmlreader를 정의하십시오

그런 다음 두 사람을 함께 연결하십시오.

public static Object unmarshallWithFilter(Unmarshaller unmarshaller,
java.io.File source) throws FileNotFoundException, JAXBException 
{
    FileReader fr = null;
    try {
        fr = new FileReader(source);
        XMLReader reader = new NamespaceFilterXMLReader();
        InputSource is = new InputSource(fr);
        SAXSource ss = new SAXSource(reader, is);
        return unmarshaller.unmarshal(ss);
    } catch (SAXException e) {
        //not technically a jaxb exception, but close enough
        throw new JAXBException(e);
    } catch (ParserConfigurationException e) {
        //not technically a jaxb exception, but close enough
        throw new JAXBException(e);
    } finally {
        FileUtil.close(fr); //replace with this some safe close method you have
    }
}

다른 팁

다음은 누군가가 자신의 필터를 구현하는 번거 로움을 겪고 싶지 않은 경우 Voncs 솔루션의 확장/편집입니다. 또한 네임 스페이스가없는 JAXB 요소를 출력하는 방법을 보여줍니다. 이것은 색소폰 필터를 사용하여 모두 이루어집니다.

필터 구현 :

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import org.xml.sax.helpers.XMLFilterImpl;

public class NamespaceFilter extends XMLFilterImpl {

    private String usedNamespaceUri;
    private boolean addNamespace;

    //State variable
    private boolean addedNamespace = false;

    public NamespaceFilter(String namespaceUri,
            boolean addNamespace) {
        super();

        if (addNamespace)
            this.usedNamespaceUri = namespaceUri;
        else 
            this.usedNamespaceUri = "";
        this.addNamespace = addNamespace;
    }



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



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

        super.startElement(this.usedNamespaceUri, arg1, arg2, arg3);
    }

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

        super.endElement(this.usedNamespaceUri, arg1, arg2);
    }

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


        if (addNamespace) {
            this.startControlledPrefixMapping();
        } else {
            //Remove the namespace, i.e. don´t call startPrefixMapping for parent!
        }

    }

    private void startControlledPrefixMapping() throws SAXException {

        if (this.addNamespace && !this.addedNamespace) {
            //We should add namespace since it is set and has not yet been done.
            super.startPrefixMapping("", this.usedNamespaceUri);

            //Make sure we dont do it twice
            this.addedNamespace = true;
        }
    }

}

이 필터는 네임 스페이스가없는 경우 네임 스페이스를 추가 할 수 있도록 설계되었습니다.

new NamespaceFilter("http://www.example.com/namespaceurl", true);

그리고 현재 네임 스페이스를 제거하려면 :

new NamespaceFilter(null, false);

필터는 구문 분석 중에 다음과 같이 사용할 수 있습니다.

//Prepare JAXB objects
JAXBContext jc = JAXBContext.newInstance("jaxb.package");
Unmarshaller u = jc.createUnmarshaller();

//Create an XMLReader to use with our filter
XMLReader reader = XMLReaderFactory.createXMLReader();

//Create the filter (to add namespace) and set the xmlReader as its parent.
NamespaceFilter inFilter = new NamespaceFilter("http://www.example.com/namespaceurl", true);
inFilter.setParent(reader);

//Prepare the input, in this case a java.io.File (output)
InputSource is = new InputSource(new FileInputStream(output));

//Create a SAXSource specifying the filter
SAXSource source = new SAXSource(inFilter, is);

//Do unmarshalling
Object myJaxbObject = u.unmarshal(source);

이 필터를 사용하여 JAXB 객체에서 XML을 출력하려면 아래 코드를 살펴보십시오.

//Prepare JAXB objects
JAXBContext jc = JAXBContext.newInstance("jaxb.package");
Marshaller m = jc.createMarshaller();

//Define an output file
File output = new File("test.xml");

//Create a filter that will remove the xmlns attribute      
NamespaceFilter outFilter = new NamespaceFilter(null, false);

//Do some formatting, this is obviously optional and may effect performance
OutputFormat format = new OutputFormat();
format.setIndent(true);
format.setNewlines(true);

//Create a new org.dom4j.io.XMLWriter that will serve as the 
//ContentHandler for our filter.
XMLWriter writer = new XMLWriter(new FileOutputStream(output), format);

//Attach the writer to the filter       
outFilter.setContentHandler(writer);

//Tell JAXB to marshall to the filter which in turn will call the writer
m.marshal(myJaxbObject, outFilter);

이것은 내가 하루를 보냈고 거의 두 번 포기한 이후로 누군가를 도울 것입니다.)

XMLFilter 솔루션에 문제가있는 문제가 있으므로 XMLStreamReader가 네임 스페이스를 무시하도록 만들었습니다.

class XMLReaderWithoutNamespace extends StreamReaderDelegate {
    public XMLReaderWithoutNamespace(XMLStreamReader reader) {
      super(reader);
    }
    @Override
    public String getAttributeNamespace(int arg0) {
      return "";
    }
    @Override
    public String getNamespaceURI() {
      return "";
    }
}

InputStream is = new FileInputStream(name);
XMLStreamReader xsr = XMLInputFactory.newFactory().createXMLStreamReader(is);
XMLReaderWithoutNamespace xr = new XMLReaderWithoutNamespace(xsr);
Unmarshaller um = jc.createUnmarshaller();
Object res = um.unmarshal(xr);

내 상황에서는 많은 네임 스페이스가 있으며 일부 디버그 후에 다른 솔루션이 네임 스페이스 피틀 클래스를 변경하는 것만으로도 찾습니다. 내 상황 (단지 끊임없이)이 작동합니다.

 import javax.xml.namespace.QName;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.XMLFilterImpl;
 import com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector;

 public class NamespaceFilter extends XMLFilterImpl {
    private SAXConnector saxConnector;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
        if(saxConnector != null) {
            Collection<QName> expected = saxConnector.getContext().getCurrentExpectedElements();
            for(QName expectedQname : expected) {
                if(localName.equals(expectedQname.getLocalPart())) {
                    super.startElement(expectedQname.getNamespaceURI(), localName, qName, atts);
                    return;
                }
            }
        }
        super.startElement(uri, localName, qName, atts);
    }

    @Override
    public void setContentHandler(ContentHandler handler) {
        super.setContentHandler(handler);
        if(handler instanceof SAXConnector) {
            saxConnector = (SAXConnector) handler;
        }
    }
}

JAXB에 공급하기 전에 XML 문서에 기본 네임스페이스를 추가하는 또 다른 방법은 다음을 사용하는 것입니다. JDom:

  1. XML을 문서로 구문 분석
  2. 모든 요소를 ​​반복하고 네임스페이스를 설정합니다.
  3. JDOMSource를 사용하여 언마샬링

이와 같이:

public class XMLObjectFactory {
    private static Namespace DEFAULT_NS = Namespace.getNamespace("http://tempuri.org/");

    public static Object createObject(InputStream in) {
        try {
            SAXBuilder sb = new SAXBuilder(false);
            Document doc = sb.build(in);
            setNamespace(doc.getRootElement(), DEFAULT_NS, true);
            Source src = new JDOMSource(doc);
            JAXBContext context = JAXBContext.newInstance("org.tempuri");
            Unmarshaller unmarshaller = context.createUnmarshaller();
            JAXBElement root = unmarshaller.unmarshal(src);
            return root.getValue();
        } catch (Exception e) {
            throw new RuntimeException("Failed to create Object", e);
        }
    }

    private static void setNamespace(Element elem, Namespace ns, boolean recurse) {
        elem.setNamespace(ns);
        if (recurse) {
            for (Object o : elem.getChildren()) {
                setNamespace((Element) o, ns, recurse);
            }
        }
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top