Как заставить Axis 1.4 не генерировать несколько префиксов для одного и того же пространства имен XML? - PullRequest
6 голосов
/ 15 сентября 2008

Я получаю 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 и ns8. Некоторые длинные запросы определяют несколько сотен префиксов для одного и того же пространства имен.

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

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

Ответы [ 3 ]

3 голосов
/ 07 октября 2008

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

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

EDIT

Это слишком сложно, и, как я уже сказал, мне это совсем не нравится, но мы здесь. Я фактически разбил функциональность на несколько классов (это была не единственная манипуляция, которую нам нужно было сделать в этом проекте, поэтому были и другие реализации) Я очень надеюсь, что кто-то сможет это исправить в ближайшее время. Он использует 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);
}
}

Нет гарантии и т. Д. И т. Д.

2 голосов
/ 13 апреля 2011

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

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 });
1 голос
/ 09 октября 2008

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

<globalConfiguration >
  <parameter name="enableNamespacePrefixOptimization" value="true"/>
...