【问题标题】:How to grab text content wrapped in CDATA tag from a piece of XML JAVA如何从一段 XML JAVA 中获取包含在 CDATA 标记中的文本内容
【发布时间】:2016-02-05 22:46:35
【问题描述】:

我有以下 XML:

<?xml version="1.0"?>
<doOrchestration xmlns="http://comResponse.engine/response">
    <response uuid="86db9b58-312b-4cbb-8aa5-df3663884291">
        <headers>
            <header name="Content-Type">application/xml</header>
            <header name="Server">local-C++</header>
        </headers>
        <responseCode>200</responseCode>
        <content><![CDATA[<explanation></explanation>]]></content>
    </response>
</doOrchestration>

我想从内容节点中解析出如下文本:

&lt;![CDATA[&lt;explanation&gt;&lt;/explanation&gt;]]&gt;

注意这里的内容是用 CDATA 标签包裹的。如何使用任何方法在 Java 中完成此操作。

这是我的代码:

@Test
public void testGetDoOrchResponse() throws IOException {
    String path = "/Users/haddad/Git/Tools/ContentUtils/src/test/resources/testdata/doOrch_testfiles/doOrch_response.xml";
    File f = new File(path);
    String response = FileUtils.readFileToString(f);

    String content = getDoOrchResponse(response, "content");
    System.out.println("Content: "+content);
}

// 输出:内容:空白

static String getDoOrchResponse(String xml, String tagFragment) throws FileNotFoundException { 

    String content = new String();
    try {
        Document doc = getDocumentXML(xml);
        NodeList nlNodeExplanationList = doc.getElementsByTagName("response"); 
        for(int i=0;i<nlNodeExplanationList.getLength();i++) {
            Node explanationNode = nlNodeExplanationList.item(i); 

            List<String> titleList = getTextValuesByTagName((Element)explanationNode, tagFragment);
            content = titleList.get(0);
        }
    } 
    catch (IOException e) {
        e.printStackTrace();
    }
    return content;
}



static List<String> getTextValuesByTagName(Element element, String tagName) {
    NodeList nodeList = element.getElementsByTagName(tagName);
    ArrayList<String> list = new ArrayList<String>();
    for (int i = 0; i < nodeList.getLength(); i++) {

        String textValue = getTextValue(nodeList.item(i));

        if(textValue.equalsIgnoreCase("") ) {
            textValue = "blank";
        }
        list.add(textValue);
    }
    return list;
}

static String getTextValue(Node node) {
    StringBuffer textValue = new StringBuffer();
    int length = node.getChildNodes().getLength();
    for (int i = 0; i < length; i ++) {
        Node c = node.getChildNodes().item(i);
        if (c.getNodeType() == Node.TEXT_NODE) {
            textValue.append(c.getNodeValue());
        }
    }
    return textValue.toString().trim();
}


static Document getDocumentXML(String xml) throws FileNotFoundException {

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db;
    Document doc = null;

    try {
        db = dbf.newDocumentBuilder();
        doc = db.parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8"))));
        doc.getDocumentElement().normalize();
    } 
    catch (ParserConfigurationException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (SAXException e) {
        e.printStackTrace();
    }
    return doc;
}

我做错了什么?为什么我得到空白作为输出?我只是没看到...

【问题讨论】:

  • 如果你真的想返回&lt;![CDATA[&lt;explanation&gt;&lt;/explanation&gt;]]&gt;那么你需要用LSSerializer序列化content元素的子节点。但是由于 CDATA 部分是避免转义标记的语法糖,因此人们通常希望将 content 元素的内容作为字符串读出,并使用 getTextContent() 给出该字符串,无论内部存在 CDATA 部分还是普通文本节点。
  • 你能给我看一下序列化的例子吗,对不起我是菜鸟

标签: java xml xpath xml-parsing


【解决方案1】:

如果要提取Element 节点的内容,请使用getTextContent() 方法。如果您确实需要或想要 CDATA 部分标记,那么您需要使用 LSSerializer 或类似名称来序列化该节点:

        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        docFactory.setNamespaceAware(true);
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();   

        Document doc = docBuilder.parse(new File("doc1.xml"));

        Element content = (Element)doc.getElementsByTagNameNS("http://comResponse.engine/response", "content").item(0);
        if (content != null)
        {
            System.out.println(content.getTextContent());
            LSSerializer ser = ((DOMImplementationLS)doc.getImplementation()).createLSSerializer();
            if (content.getFirstChild() != null)
            {
              System.out.println(ser.writeToString(content.getFirstChild()));
            }

        }

这就是理论,对我来说,Java JRE 1.8 输出 &lt;![CDATA[&lt;explanation&gt;&lt;/explanation&gt; 没有 CDATA 部分的结束标记,看起来 LSSerializer 无法与单个 CDATA 部分节点正常工作。

【讨论】:

  • 我其实并不关心 CDATA,我的想法是在获得 CDATA 后正则表达式输出 。如果有更好的方法可以直接从 XML 中获取 ,那就更好了。我该怎么做?
  • 在那个元素节点上调用getTextContent(),如图所示,你会得到一个带有&lt;explanation&gt;&lt;/explanation&gt;的字符串。
  • 谢谢,在元素节点上调用 getTextContent 效果很好!
  • 你用 6 行代码完成了我试图用超过 20 行代码完成的工作
猜你喜欢
  • 2013-11-08
  • 1970-01-01
  • 2012-05-15
  • 2011-11-29
  • 2017-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多