如何使用SAX解析器删除xml namesapce

时间:2017-07-07 11:14:09

标签: java xml saxparser

我需要使用SAX解析器进行xml转换,因为我需要从xml中删除命名空间。由于我们使用巨大的xml处理,我需要使用SAX解析器。

示例输入xml:

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
 xmlns:ns2="http://www.google.com/generation/type">
    <ns2:meta>
        <gender xmlns="" xmlns:ns5="http://www.google.com/generation">M</gender>
        <dateOfBirth xmlns="" xmlns:ns5="http://www.google.com/generation">1976-07-19</dateOfBirth>
        <ns2:languageRef>ENG</ns2:languageRef>
    </ns2:meta>
    <root>

在SAX解析器的帮助下,我需要以下输出。

       <root>
            <meta>
                <gender>M</gender>
                <dateOfBirth>1976-07-19</dateOfBirth>
                <languageRef>ENG</languageRef>
            </ns2:meta>
        <root>

提前致谢..

我试过的代码,

我尝试使用XMLFlterImpl,

XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) {

  @Override
  public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {

    if (qName.contains(":")) {
      String[] data = data = qName.split(":");


      super.startElement(uri, localName, data[1], atts);
    } else {
      super.startElement(uri, localName, qName, atts);
    }
  } 

这将删除元素名称前缀(名称空间),但不确定如何删除名称空间属性

4 个答案:

答案 0 :(得分:1)

修改

好的,根据@MichaelKay的评论指示,这是我更新的答案。

从标记中删除命名空间:

正如他的回答中所建议的,startElement应该""代替uri。那么 Ending tag?: 在您的问题中,我不明白为什么您希望ns2结束meta代码,特别是当您要为起始代码删除它时。 我假设您也希望将其删除以结束标记。因此,类似endElement也应该""代替uri

过滤XMLNS属性:

您可以创建新的AttributesImpl。然后浏览属性列表并检查QName是否以xmlns开头,如果没有将其添加到AttributesImpl并在startElement中将其用作:

super.startElement("", localName, data[1], aImpl);

另请注意,根据@MartinHonnen,是的属性&#39; uri也应该是&#34;&#34;并且qName也应该没有前缀和元素。但是如果你想保留属性&#39;这样的名字(我不认为你想要)你可以按原样保留atts.getQName(i)

还将Namespaces功能设置为false,如:

xf.setFeature("http://xml.org/sax/features/namespaces", false);

代码:

try {

   InputSource file = new InputSource("filterns.xml");

   XMLFilterImpl xf = new XMLFilterImpl(
           XMLReaderFactory.createXMLReader()) {
       @Override
       public void startElement(String uri, String localName,
           String qName, Attributes atts) throws SAXException {

               AttributesImpl aImpl = new AttributesImpl();

                int l = atts.getLength();
                for (int i = 0; i < l; i++) {

                    if (atts.getQName(i) != null
                            && atts.getQName(i).startsWith("xmlns")) {
                        continue;
                    } else {
                        String aQName = atts.getQName(i);
                        String[] s = aQName.split(":");
                        if (s.length > 1) {
                            aQName = s[1];
                        }

                        aImpl.addAttribute("",
                                atts.getLocalName(i), aQName,
                                atts.getType(i), atts.getValue(i));
                    }

                }

                String[] s = qName.split(":");
                if (s.length > 1) {
                    super.startElement("", localName, s[1], aImpl);
                } else {
                    super.startElement("", localName, qName, aImpl);
                }

       }

       @Override
       public void endElement(String uri, String localName,
              String qName) throws SAXException {

              String[] s = qName.split(":");
              if (s.length > 1) {
                 super.endElement("", localName, s[1]);
               } else {
                  super.endElement("", localName, qName);
                 }

       }

       @Override
       public void startPrefixMapping(String prefix, String uri) {
       }

   };

   xf.setFeature("http://xml.org/sax/features/namespaces", false);
   SAXSource src = new SAXSource(xf, file);

   StringWriter stringWriter = new StringWriter();
   TransformerFactory transformerFactory = TransformerFactory
           .newInstance();
   Transformer transformer = transformerFactory.newTransformer();
   transformer.setOutputProperty(OutputKeys.INDENT, "yes");
   transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"yes");
   transformer.transform(src, new StreamResult(stringWriter));

   String xml = stringWriter.toString();
   System.out.println(xml);

} catch (Exception e) {
   e.printStackTrace();
}

答案 1 :(得分:1)

在此代码中:

super.startElement(uri, localName, data[1], atts);

您将原始名称空间URI不变地传递给输出。你需要摆脱它,使用:

super.startElement("", localName, data[1], atts);

答案 2 :(得分:0)

通常尝试删除命名空间以执行“转换”,这表明对如何处理XML缺乏了解,但通常如果您使用SAX并希望更改已处理的XML,则可以实现过滤器https://docs.oracle.com/javase/8/docs/api/org/xml/sax/XMLFilter.html ,以https://docs.oracle.com/javase/8/docs/api/org/xml/sax/helpers/XMLFilterImpl.html作为基础clase开头,并覆盖您期望并希望删除名称空间的方法。

答案 3 :(得分:0)

这是可以使用VTD-XML完成的示例。如果有任何问题,请告诉我。

import com.ximpleware.*;
import java.io.*;
public class removeNS {

    public static void main(String[] args) throws VTDException, IOException{
        // TODO Auto-generated method stub
        VTDGen vg = new VTDGen();
        if (!vg.parseFile("d:\\xml\\ns.xml", true))
            return;
        VTDNav vn = vg.getNav();
        XMLModifier xm = new XMLModifier(vn);
        for (int i=0;i<vn.getTokenCount();i++){

            int t = vn.getTokenType(i);
            switch(t){

                case VTDGen.TOKEN_STARTING_TAG:
                    stripElementPrefix(i,vn,xm);
                    break;
                case VTDGen.TOKEN_ATTR_NAME:
                    stripAttrPrefix(i,vn,xm);
                    break;
                case VTDGen.TOKEN_ATTR_NS: 
                    xm.removeAttribute(i);
                default:
            }
        }
        xm.output("d:\\xml\\nsOut.xml");
    }

    public static void stripAttrPrefix(int i, VTDNav vn, XMLModifier xm) throws VTDException{
        //get the offset and length of localname part of starting tag
        int os1 = vn.getTokenOffset(i);
        int len = vn.getTokenLength(i);
        if ((len>>16)!=0){
            int temp1 = (0xffff & len) - (len>>16)-1;
            int temp2 = os1 + (temp1);
            xm.removeContent(temp1, temp2);
        }

        //int offset=
    }

    public static void stripElementPrefix(int i, VTDNav vn, XMLModifier xm) throws VTDException, UnsupportedEncodingException{
        //int os1 = vn.getTokenOffset(i)
        int os1 = vn.getTokenOffset(i);
        int len = vn.getTokenLength(i);
        if ((len>>16)!=0){
            int temp1 = (0xffff & len) - (len>>16)-1;
            int temp2 = os1 + (len>>16)+1;
            String s = vn.toRawString(temp2, temp1);
            System.out.println(s);
            vn.recoverNode(i);
            xm.updateElementName(s);
        }
    }

}