Как заставить Axis 1.4 не генерировать несколько префиксов для одного и того же пространства имен XML?

Я получаю запросы SOAP от клиента, использующего библиотеки Axis 1.4. Запросы имеют следующий вид:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <PlaceOrderRequest xmlns="http://example.com/schema/order/request">
      <order>
        <ns1:requestParameter xmlns:ns1="http://example.com/schema/common/request">
          <ns1:orderingSystemWithDomain>
            <ns1:orderingSystem>Internet</ns1:orderingSystem>
            <ns1:domainSign>2</ns1:domainSign>
          </ns1:orderingSystemWithDomain>
        </ns1:requestParameter>
        <ns2:directDeliveryAddress ns2:addressType="0" ns2:index="1" 
                                   xmlns:ns2="http://example.com/schema/order/request">
          <ns3:address xmlns:ns3="http://example.com/schema/common/request">
            <ns4:zipcode xmlns:ns4="http://example.com/schema/common">12345</ns4:zipcode>
            <ns5:city xmlns:ns5="http://example.com/schema/common">City</ns5:city>
            <ns6:street xmlns:ns6="http://example.com/schema/common">Street</ns6:street>
            <ns7:houseNum xmlns:ns7="http://example.com/schema/common">1</ns7:houseNum>
            <ns8:country xmlns:ns8="http://example.com/schema/common">XX</ns8:country>
          </ns3:address>
[...]

Как видите, для одного и того же пространства имен определено несколько префиксов, например. пространство имен http://example.com/schema/common имеет префиксы ns4, ns5, ns6, ns7 и нс8. Некоторые длинные запросы определяют несколько сотен префиксов для одного и того же пространства имен.

Это вызывает проблему с XSLT-процессором Saxon, который я использую для преобразования запросов. Saxon ограничивает количество различных префиксов для одного и того же пространства имен до 255 и создает исключение, когда вы определяете больше префиксов.

Можно ли настроить Axis 1.4 для определения более разумных префиксов, чтобы для каждого пространства имен был только один префикс?


person Christian Berg    schedule 15.09.2008    source источник
comment
У меня точно такая же проблема. Буду внимательно следить за этой веткой.   -  person Ian McLaird    schedule 07.10.2008


Ответы (3)


У меня такая же проблема. На данный момент я работал над этим, написав расширение BasicHandler, а затем самостоятельно пройдя SOAPPart и переместив ссылку на пространство имен на родительский узел. Мне не нравится это решение, но, похоже, оно работает.

Я действительно надеюсь, что кто-нибудь придет и скажет нам, что мы должны делать.

ИЗМЕНИТЬ

Это слишком сложно, и, как я уже сказал, мне это совсем не нравится, но поехали. На самом деле я разбил функционал на несколько классов (это была не единственная манипуляция, которую нам нужно было проделать в этом проекте, поэтому были и другие реализации) Я очень надеюсь, что кто-нибудь сможет это исправить в ближайшее время. Это использует dom4j для обработки XML, проходящего через процесс SOAP, поэтому вам понадобится dom4j, чтобы заставить его работать.

public class XMLManipulationHandler extends BasicHandler {
    private static Log log = LogFactory.getLog(XMLManipulationHandler.class);
    private static List processingHandlers;

    public static void setProcessingHandlers(List handlers) {
        processingHandlers = handlers;
    }

    protected Document process(Document doc) {
        if (processingHandlers == null) {
            processingHandlers = new ArrayList();
            processingHandlers.add(new EmptyProcessingHandler());
        }
        log.trace(processingHandlers);
        treeWalk(doc.getRootElement());
        return doc;
    }

    protected void treeWalk(Element element) {
        for (int i = 0, size = element.nodeCount(); i < size; i++) {
            Node node = element.node(i);
            for (int handlerIndex = 0; handlerIndex < processingHandlers.size(); handlerIndex++) {
                ProcessingHandler handler = (ProcessingHandler) processingHandlers.get(handlerIndex);
                handler.process(node);
            }
            if (node instanceof Element) {
                treeWalk((Element) node);
            }
        }
    }

    public void invoke(MessageContext context) throws AxisFault {
        if (!context.getPastPivot()) {
            SOAPMessage message = context.getMessage();
            SOAPPart soapPart = message.getSOAPPart();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            try {
                message.writeTo(baos);
                baos.flush();
                baos.close();

                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                SAXReader saxReader = new SAXReader();
                Document doc = saxReader.read(bais);
                doc = process(doc);
                DocumentSource ds = new DocumentSource(doc);
                soapPart.setContent(ds);
                message.saveChanges();
            } catch (Exception e) {
                throw new AxisFault("Error Caught processing document in XMLManipulationHandler", e);
            }
        }
    }
}
public interface ProcessingHandler {
    public Node process(Node node);
}
public class NamespaceRemovalHandler implements ProcessingHandler {
    private static Log log = LogFactory.getLog(NamespaceRemovalHandler.class);
    private Namespace namespace;
    private String targetElement;
    private Set ignoreElements;

    public NamespaceRemovalHandler() {
        ignoreElements = new HashSet();
    }

    public Node process(Node node) {
        if (node instanceof Element) {
            Element element = (Element) node;
            if (element.isRootElement()) {
                // Evidently, we never actually see the root node when we're called from
                // SOAP...
            } else {
                if (element.getName().equals(targetElement)) {
                    log.trace("Found the target Element.  Adding requested namespace");
                    Namespace already = element.getNamespaceForURI(namespace.getURI());
                    if (already == null) {
                        element.add(namespace);
                    }
                } else if (!ignoreElements.contains(element.getName())) {
                    Namespace target = element.getNamespaceForURI(namespace.getURI());
                    if (target != null) {
                        element.remove(target);
                        element.setQName(new QName(element.getName(), namespace));
                    }
                }

                Attribute type = element.attribute("type");
                if (type != null) {
                    log.trace("Replacing type information: " + type.getText());
                    String typeText = type.getText();
                    typeText = typeText.replaceAll("ns[0-9]+", namespace.getPrefix());
                    type.setText(typeText);
                }
            }
        }

        return node;
    }

    public Namespace getNamespace() {
        return namespace;
    }

    public void setNamespace(Namespace namespace) {
        this.namespace = namespace;
    }

    /**
     * @return the targetElement
     */
    public String getTargetElement() {
        return targetElement;
    }

    /**
     * @param targetElement the targetElement to set
     */
    public void setTargetElement(String targetElement) {
        this.targetElement = targetElement;
    }

    /**
     * @return the ignoreElements
     */
    public Set getIgnoreElements() {
        return ignoreElements;
    }

    /**
     * @param ignoreElements the ignoreElements to set
     */
    public void setIgnoreElements(Set ignoreElements) {
        this.ignoreElements = ignoreElements;
    }

    public void addIgnoreElement(String element) {
        this.ignoreElements.add(element);
    }
}

Без гарантии и тд и тп.

person Ian McLaird    schedule 07.10.2008

Для запроса я использую это для удаления типов пространств имен:

String endpoint = "http://localhost:5555/yourService";

// Parameter to be send
Integer secuencial = new Integer(11);  // 0011

// Make the call
Service  service = new Service();

Call call = (Call) service.createCall();

// Disable sending Multirefs
call.setOption( org.apache.axis.AxisEngine.PROP_DOMULTIREFS, new java.lang.Boolean( false) ); 

// Disable sending xsi:type
call.setOption(org.apache.axis.AxisEngine.PROP_SEND_XSI, new java.lang.Boolean( false));  

// XML with new line
call.setOption(org.apache.axis.AxisEngine.PROP_DISABLE_PRETTY_XML, new java.lang.Boolean( false)); 

// Other Options. You will not need them
call.setOption(org.apache.axis.AxisEngine.PROP_ENABLE_NAMESPACE_PREFIX_OPTIMIZATION, new java.lang.Boolean( true)); 
call.setOption(org.apache.axis.AxisEngine.PROP_DOTNET_SOAPENC_FIX, new java.lang.Boolean( true));

call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setSOAPActionURI("http://YourActionUrl");//Optional

// Opertion Name
//call.setOperationName( "YourMethod" );
call.setOperationName(new javax.xml.namespace.QName("http://yourUrl", "YourMethod"));      

// Do not send encoding style
call.setEncodingStyle(null);

// Do not send xmlns in the xml nodes
call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);

/////// Configuration of namespaces
org.apache.axis.description.OperationDesc oper;
org.apache.axis.description.ParameterDesc param;
oper = new org.apache.axis.description.OperationDesc();
oper.setName("InsertaTran");
param = new org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("http://yourUrl", "secuencial"), org.apache.axis.description.ParameterDesc.IN, new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "int"), int.class, false, false);
oper.addParameter(param);

oper.setReturnType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "int"));
oper.setReturnClass(int.class);
oper.setReturnQName(new javax.xml.namespace.QName("http://yourUrl", "yourReturnMethod"));
oper.setStyle(org.apache.axis.constants.Style.WRAPPED);
oper.setUse(org.apache.axis.constants.Use.LITERAL);

call.setOperation(oper);

Integer ret = (Integer) call.invoke( new java.lang.Object [] 
            { secuencial });
person Pica Creations    schedule 13.04.2011

Измените wsdd вашего клиента, чтобы установить enableNamespacePrefixOptimization на true

<globalConfiguration >
  <parameter name="enableNamespacePrefixOptimization" value="true"/>
person Stephen Denne    schedule 09.10.2008
comment
Это где-нибудь задокументировано? Мне нужен хороший список того, что я могу сделать для настройки клиента, желательно без чтения фактического исходного кода. - person Ian McLaird; 10.10.2008
comment
Я нашел этот параметр, просматривая старый проект. Это работает? - person Stephen Denne; 10.10.2008