2016-01-21 2 views
7

Прежде чем начать: Я знаю, что дочерний узел наследует пространство имен от родительского узла, и именно поэтому возникает моя проблема. К сожалению, веб-сервис, который я отправляю своим XML, не принимает дочерний узел без пространства имен и, поскольку он является государственным органом, изменение их части маловероятно.Разбор XML, не поддерживающего дублированные пространства имен в родительском узле и дочернем узле

Это, как говорится, я использую Spring-WS, чтобы сделать связь между моим приложением и веб-сервиса, поэтому в той или иной каркас использует трансформатор для разбора мой полезной нагрузки источника для полезной нагрузки Результат фреймворка:

transformer.transform(Source, Result); 

До это преобразование происходит, мой XML имеет эти два узла, как следует здесь:

<enviNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> 
    <NFe xmlns="http://www.portalfiscal.inf.br/nfe"> 

После преобразования, второе пространство имен удаляются (как я уже говорил, я знаю причину):

<enviNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="3.10"> 
    <NFe> 

Я также знаю, что я могу использовать маршаллеров для достижения того же результата и написания кода синтаксического анализа. Использование этого подхода также вполне приемлемо, но я не знаю другого способа добиться того же (преобразование javax.xml.transform.Source в javax.xml.transform.Result) с использованием другого подхода, кроме указанного выше.

У меня есть два вопроса, то:

1 - Могу ли я избежать поведения я, имеющий с подходом по умолчанию (без использования marshallers)?

2 - Есть ли другой инструмент, который бы сделал одно и то же преобразование?

+0

Вы управляете вызовом 'transformer.transform (Source, Result)', т. Е. Можете ли вы передавать разные объекты Source или Result, если хотите? – wero

+0

Нет, у меня нет контроля над этим. Результат исходит из весны-ws. –

ответ

1

У меня была такая же проблема. К сожалению (или нет) WebServiceTemplate с реализацией SOAPMessageFactory (например, SaajSoapMessageFactory) сделает все возможное, чтобы гарантировать, что вы отправляете правильно сформированный XML в качестве запроса, связывая вас с Transformers from Source to Result, в том числе никогда не позволяйте вам повторять «xmlns «у детей, когда вы уже сделали это у родителей. У вас есть несколько элегантных вариантов, чтобы попробовать - что не значит, что они самые простые. Вы можете работать на уровне XML, используя интерфейс javax.xml.ws.Service и Dispatch, что довольно просто, если вам не нужна аутентификация SSL. Проверьте эти ссылки из (первой одна написана в Pt-BR):

http://www.guj.com.br/t/nfe-v2-00-veja-como-consumir-o-ws/297304

https://alesaudate.wordpress.com/2010/08/09/how-to-dynamically-select-a-certificate-alias-when-invoking-web-services/

Также вы можете попробовать другое сообщение фабрику, такие как DomPoxMessageFactory. Эта ссылка может быть полезна:

http://forum.spring.io/forum/spring-projects/web-services/128221-webservicetemplate-get-it-to-stop-adding-soap-envelope

Однако, если изменение структуры вашего проекта не вариант (который был мой случай), у меня есть обходной путь для вас. Да, обходной путь, но как только цель вебсервис IS ОЖИДАЕТ искаженный XML, Я прощаю себя: D

Я только что создал абстракции HttpComponentsMessageSender и HttpComponentsConnection классов, вторые один экземпляр через первую свой метод CreateConnection (Uri Uri) ,Так что я могу создать свой WebServiceTemplate так:

WebServiceTemplate wst = new WebServiceTemplate(new SaajSoapMessageFactory()); 
wst.setMessageSender(new CustomHttpComponentsMessageSender()); 

К сожалению, вам нужно ответить метод createConnecion к новой абстракции только для создания экземпляра пользовательского соединения. Как я уже сказал, это обходной путь!

@Override 
public WebServiceConnection createConnection(URI uri) throws IOException { 
    HttpPost httpPost = new HttpPost(uri); 
    if (isAcceptGzipEncoding()) { 
     httpPost.addHeader(HttpTransportConstants.HEADER_ACCEPT_ENCODING, 
       HttpTransportConstants.CONTENT_ENCODING_GZIP); 
    } 
    HttpContext httpContext = createContext(uri); 
    return new CustomHttpComponentsConnection(getHttpClient(), httpPost, httpContext); 
} 

Сообщение эффективно послан внутри метода onSendAfterWrite (WebServiceMessage сообщение) класса HttpComponentsConnection Я абстрагируясь от. Удивительно, что параметр «сообщение» не используется внутри метода. Он существует только для правил наследования. И хорошие новости: это защищенный метод. Недостатком, опять же, является то, что мне нужно скопировать почти весь класс, чтобы изменить только этот метод, как только поля не будут иметь видимой видимости, и структура будет нужна им при обработке ответов. Таким образом, я выложу весь мой класс вниз:

public class CustomHttpComponentsConnection extends HttpComponentsConnection { 

    private final HttpClient httpClient; 

    private final HttpPost httpPost; 

    private final HttpContext httpContext; 

    private HttpResponse httpResponse; 

    private ByteArrayOutputStream requestBuffer; 

    protected CustomHttpComponentsConnection(HttpClient httpClient, HttpPost httpPost, HttpContext httpContext) { 
     super(httpClient, httpPost, httpContext); 

     Assert.notNull(httpClient, "httpClient must not be null"); 
     Assert.notNull(httpPost, "httpPost must not be null"); 
     this.httpClient = httpClient; 
     this.httpPost = httpPost; 
     this.httpContext = httpContext; 
    } 

    public HttpResponse getHttpResponse() { 
    return httpResponse; 
    } 

    public HttpPost getHttpPost() { 
     return httpPost; 
    } 

    @Override 
    protected OutputStream getRequestOutputStream() throws IOException { 
     return requestBuffer; 
    } 

    @Override 
    protected void onSendBeforeWrite(WebServiceMessage message) throws IOException { 
     requestBuffer = new ByteArrayOutputStream(); 
    } 

    @Override 
    protected void onSendAfterWrite(WebServiceMessage message) throws IOException { 

     OutputStream out = getRequestOutputStream(); 

     String str = out.toString(); 

     str = str.replaceAll("<NFe>", "<NFe xmlns=\"http://www.portalfiscal.inf.br/nfe\">"); 
     ByteArrayOutputStream bs = new ByteArrayOutputStream(); 
     bs.write(str.getBytes()); 

     getHttpPost().setEntity(new ByteArrayEntity(bs.toByteArray())); 

     requestBuffer = null; 
     if (httpContext != null) { 
      httpResponse = httpClient.execute(httpPost, httpContext); 
     } 
     else { 
      httpResponse = httpClient.execute(httpPost); 
     } 
    } 

    @Override 
    protected int getResponseCode() throws IOException { 
     return httpResponse.getStatusLine().getStatusCode(); 
    } 

    @Override 
    protected String getResponseMessage() throws IOException { 
     return httpResponse.getStatusLine().getReasonPhrase(); 
    } 

    @Override 
    protected long getResponseContentLength() throws IOException { 
     HttpEntity entity = httpResponse.getEntity(); 
     if (entity != null) { 
      return entity.getContentLength(); 
     } 
     return 0; 
    } 

    @Override 
    protected InputStream getRawResponseInputStream() throws IOException { 
     HttpEntity entity = httpResponse.getEntity(); 
     if (entity != null) { 
      return entity.getContent(); 
     } 
     throw new IllegalStateException("Response has no enclosing response entity, cannot create input stream"); 
    } 

    @Override 
    public Iterator<String> getResponseHeaderNames() throws IOException { 
     Header[] headers = httpResponse.getAllHeaders(); 
     String[] names = new String[headers.length]; 
     for (int i = 0; i < headers.length; i++) { 
      names[i] = headers[i].getName(); 
     } 
     return Arrays.asList(names).iterator(); 
    } 

    @Override 
    public Iterator<String> getResponseHeaders(String name) throws IOException { 
     Header[] headers = httpResponse.getHeaders(name); 
     String[] values = new String[headers.length]; 
     for (int i = 0; i < headers.length; i++) { 
      values[i] = headers[i].getValue(); 
     } 
     return Arrays.asList(values).iterator(); 
    } 

Опять же, это самый простой способ я нашел, когда изменение структуры проекта не вариант. Надеюсь это поможет.

+0

Человек, ты спас мне жизнь! Это получилось просто отлично. Благодаря! –

0

Я не думаю, что для вашего преобразования существует какой-либо другой подход. Как вы знаете, маршаллеры - лучшая практика для использования в этих сценариях. Лучше использовать JAXB.

Смежные вопросы