格式化Web服务响应

9
我使用以下函数来获取Web服务响应:
private String getSoapResponse (String url, String host, String encoding, String soapAction, String soapRequest) throws MalformedURLException, IOException, Exception {         
    URL wsUrl = new URL(url);     
    URLConnection connection = wsUrl.openConnection();     
    HttpURLConnection httpConn = (HttpURLConnection)connection;     
    ByteArrayOutputStream bout = new ByteArrayOutputStream(); 

    byte[] buffer = new byte[soapRequest.length()];     
    buffer = soapRequest.getBytes();     
    bout.write(buffer);     
    byte[] b = bout.toByteArray();          

    httpConn.setRequestMethod("POST");
    httpConn.setRequestProperty("Host", host);

    if (encoding == null || encoding == "")
        encoding = UTF8;

    httpConn.setRequestProperty("Content-Type", "text/xml; charset=" + encoding);
    httpConn.setRequestProperty("Content-Length", String.valueOf(b.length));
    httpConn.setRequestProperty("SOAPAction", soapAction);

    httpConn.setDoOutput(true);
    httpConn.setDoInput(true);

    OutputStream out = httpConn.getOutputStream();
    out.write(b); 
    out.close();

    InputStreamReader is = new InputStreamReader(httpConn.getInputStream());
    StringBuilder sb = new StringBuilder();
    BufferedReader br = new BufferedReader(is);
    String read = br.readLine();

    while(read != null) {
        sb.append(read);
        read = br.readLine();
    }

    String response = decodeHtmlEntityCharacters(sb.toString());    

    return response = decodeHtmlEntityCharacters(response);
}

但是我对这段代码的问题在于它返回了很多特殊字符,使XML结构无效。
示例响应:

<PLANT>A565</PLANT>
          <PLANT>A567</PLANT>
          <PLANT>A585</PLANT>
          <PLANT>A921</PLANT>
          <PLANT>A938</PLANT>
        </PLANT_GROUP>
      </KPI_PLANT_GROUP_KEYWORD>
      <MSU_CUSTOMERS/>
    </DU>
    <DU> 

为了解决这个问题,我使用以下方法,并将整个响应传递给它,以替换所有特殊字符为它对应的标点符号。
private final static Hashtable htmlEntitiesTable = new Hashtable();
static {
    htmlEntitiesTable.put("&","&");
    htmlEntitiesTable.put(""","\"");
    htmlEntitiesTable.put("&lt;","<");
    htmlEntitiesTable.put("&gt;",">");  
}

private String decodeHtmlEntityCharacters(String inputString) throws Exception {
    Enumeration en = htmlEntitiesTable.keys();

    while(en.hasMoreElements()){
        String key = (String)en.nextElement();
        String val = (String)htmlEntitiesTable.get(key);

        inputString = inputString.replaceAll(key, val);
    }

    return inputString;
}

但又出现了另一个问题。如果响应包含该段落&lt;VALUE&gt;&lt; 0.5 &lt;/VALUE&lt;,并且如果将其评估为方法,输出结果将是:

<VALUE>< 0.5</VALUE>

这会使XML的结构再次无效。数据是正确和有效的"<0.5",但使它在VALUE元素中使用会导致XML结构出现问题。

请问如何处理这个问题?也许我获取或构建响应的方式可以改进。有更好的方法来调用和获取Web服务的响应吗?

如何处理包含"<"或">"的元素?


所以你需要一种方法来检测'<'是数据还是语法? - Cruncher
我建议在VALUE上设置一个属性。根据您需要的是小于/大于,将属性设置为1或0(或-1、0、1表示<、=、>)。 - Cruncher
为什么不正确地对<进行编码? - Brian Agnew
@BrianAgnew 首先它已经正确编码,与其余的xml一起。然后当他解码其余的xml时,他会对其进行解码。问题在于他需要区分不同的"<"。 - Cruncher
1
@Cruncher 嗯,它似乎一开始就没有被正确编码。如果是这样,实际的 XML 结构不会被编码,只有数据会被编码。或者你看到了我们没看到的东西? - eis
6个回答

3

你使用SOAP的方式是错误的。

尤其是,你不需要以下这行代码:

     String response = decodeHtmlEntityCharacters(sb.toString());    

只需返回 sb.toString()。而且,不要使用字符串方法来解析检索到的字符串,应该使用 XML 解析器或完整的 SOAP 栈...

3

1

大于号(>)或小于号(<)字符是否总是出现在值的开头?那么您可以使用正则表达式来处理后面跟着数字(或点)的情况,其中包括 &gt; 或 &lt;。

示例代码,假设其中使用的替换字符串不会出现在 XML 中的其他位置:

private String decodeHtmlEntityCharacters(String inputString) throws Exception {
    Enumeration en = htmlEntitiesTable.keys();

    // Replaces &gt; or &lt; followed by dot or digit (while keeping the dot/digit)
    inputString = inputString.replaceAll("&gt;(\\.?\\d)", "Valuegreaterthan$1");
    inputString = inputString.replaceAll("&lt;(\\.?\\d)", "Valuelesserthan$1");

    while(en.hasMoreElements()){
        String key = (String)en.nextElement();
        String val = (String)htmlEntitiesTable.get(key);

        inputString = inputString.replaceAll(key, val);
    }

    inputString = inputString.replaceAll("Valuelesserthan", "&lt;");
    inputString = inputString.replaceAll("Valuegreaterthan", "&gt;");

    return inputString;
}

请注意,最合适的答案(也更容易)是在发送方正确编码XML(顺便说一下,这也会使我的解决方案无法工作)。

“>”和“<”符号通常可以在值的开头找到。接下来的数据通常是数字。例如: <VALUE><0.5</VALUE>关于正则表达式,是否有构建它的工具?我不熟悉正则表达式。 - yonan2236
String.replaceAll() 的第一个参数是一个正则表达式。顺便问一下,"<VALUE></VALUE>" 是否会出现(即空值)? - Piovezan
不,如果一个元素没有内容,标签就会是<VALUE/> - yonan2236
好的。为了确保,您需要将哪些编码为&gt;&lt;,是属于XML元素的封闭字符还是属于值的字符? - Piovezan
是的,但是您指的是值所属的“<”(例如<50),对吗?与不应编码的XML元素封闭字符相对立,对吗? - Piovezan
返回仅包含值的“<”。 - yonan2236

0

应对所有情况可能有些困难,但您可以通过添加一些规则来覆盖最常见的情况,例如假设任何后面跟着空格的小于号是数据,以及在大于号前面有空格的情况下需要再次编码。

private final static Hashtable htmlEntitiesTable = new Hashtable();
static {
    htmlEntitiesTable.put("&amp;","&");
    htmlEntitiesTable.put("&quot;","\"");
    htmlEntitiesTable.put("&lt;","<");
    htmlEntitiesTable.put("&gt;",">");  
}

private String decodeHtmlEntityCharacters(String inputString) throws Exception {
    Enumeration en = htmlEntitiesTable.keys();

    while(en.hasMoreElements()){
        String key = (String)en.nextElement();
        String val = (String)htmlEntitiesTable.get(key);

        inputString = inputString.replaceAll(key, val);
    }

    inputString = inputString.replaceAll("< ","&lt; ");       
    inputString = inputString.replaceAll(" >"," &gt;");       

    return inputString;
}

0

'>' 在 XML 中不需要转义,所以在这方面你不应该有问题。关于 '<',下面是几个我能想到的选项:

  1. 对包含特殊字符的文本,可以在 Web 响应中使用 CDATA。
  2. 通过倒序重写文本。例如,如果是 x < 2,则改为 2 > x。除非是 CDATA 的一部分,否则 '>' 不需要转义。
  3. 在 XML 响应中使用另一个属性或元素来表示 '<' 或 '>'。
  4. 使用正则表达式查找以 '<' 开头、后跟一个字符串并以闭合标签的 '<' 结尾的序列,并将其替换为某些代码或某些值,以便稍后进行解释和替换。

此外,您不需要执行以下操作:

String response = decodeHtmlEntityCharacters(sb.toString()); 

在处理文本中的'<'符号后,您应该能够解析XML。

您可以使用this网站测试正则表达式。


0
为什么不对你的XML进行序列化呢?这比你现在做的要容易得多。
例如:
var ser = new XmlSerializer(typeof(MyXMLObject));
using (var reader = XmlReader.Create("http.....xml"))
{
     MyXMLObject _myobj = (response)ser.Deserialize(reader);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接