title: Problem with conversion of org.dom4j.Document to org.w3c.dom.Document and XML Signature
body: <p>I have some classes that already use <a href="http://dom4j.sourceforge.net/" rel="nofollow">DOM4J</a> to read XML files and provide
  getter methods to the data. Now, I need to add the possibility of checking XML digital
  signatures. </p>
  
  <p>Using org.w3c.dom and following <a href="http://java.sun.com/developer/technicalArticles/xml/dig_signature_api/" rel="nofollow">http://java.sun.com/developer/technicalArticles/xml/dig_signature_api/</a>
  everything works correctly.</p>
  
  <p>So, I try to use DOMWriter to convert from org.dom4j.Document to
  org.w3c.dom.Document, but after this the signature validation doesn't work. I think it
  happens because DOMWiter is changing the XML tree (as doc4.asXML() seems to show).</p>
  
  <p>I try to find something to set in order to mantain the integrity of the document, but 
  DOMWriter don't have such methods.</p>
  
  <p>Below is the code demonstrating the asymmetric conversion. </p>
  
  <p>The file used for tests is <a href="http://www.robertodiasduarte.com.br/files/nfe/131090007910044_v1.10-procNFe.xml" rel="nofollow">http://www.robertodiasduarte.com.br/files/nfe/131090007910044_v1.10-procNFe.xml</a></p>
  
  <p>Does someone know reasons/workarounds to this?</p>
  
  <p>Thanks (and sorry my poor english).</p>
  
  <pre><code>package testevalidanfe;
  
  import java.io.File;
  import java.io.FileWriter;
  import java.io.PrintWriter;
  import javax.swing.JOptionPane;
  import javax.xml.crypto.dsig.XMLSignature;
  import javax.xml.crypto.dsig.XMLSignatureFactory;
  import javax.xml.crypto.dsig.dom.DOMValidateContext;
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerFactory;
  import javax.xml.transform.dom.DOMSource;
  import javax.xml.transform.stream.StreamResult;
  import org.dom4j.io.XMLWriter;
  import org.w3c.dom.Document;
  import org.w3c.dom.Node;
  
  public class Testevalidanfe {
  
      public static void main(String[] args) throws Exception {
          DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
          dbf.setNamespaceAware(true);
          DocumentBuilder db = dbf.newDocumentBuilder();
          Document d = db.parse("exemplo-nfe.xml");
  
          Node no = d.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
  
          DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), no);
          XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
          XMLSignature signature = fac.unmarshalXMLSignature(valContext);
  
          JOptionPane.showMessageDialog(null, "Validation using org.w3c.dom: " + signature.validate(valContext));
          org.dom4j.io.DOMReader domreader = new org.dom4j.io.DOMReader();
          org.dom4j.Document doc4 = domreader.read(d);
          org.dom4j.io.DOMWriter domwriter = new org.dom4j.io.DOMWriter();
          d = domwriter.write(doc4);
  
          String after = doc4.asXML();
  
          PrintWriter writer = new PrintWriter(new File("after-convertion.xml"));
          writer.print(after);
          writer.close();
  
          no = d.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
  
          valContext = new DOMValidateContext(new X509KeySelector(), no);
          fac = XMLSignatureFactory.getInstance("DOM");
          signature = fac.unmarshalXMLSignature(valContext);
  
          JOptionPane.showMessageDialog(null, "Validation after convert: " + signature.validate(valContext));
      }
  }
  
  package testevalidanfe;
  
  import java.security.Key;
  import java.security.PublicKey;
  import java.security.cert.X509Certificate;
  import java.util.Iterator;
  import javax.xml.crypto.AlgorithmMethod;
  import javax.xml.crypto.KeySelector;
  import javax.xml.crypto.KeySelectorException;
  import javax.xml.crypto.KeySelectorResult;
  import javax.xml.crypto.XMLCryptoContext;
  import javax.xml.crypto.XMLStructure;
  import javax.xml.crypto.dsig.SignatureMethod;
  import javax.xml.crypto.dsig.keyinfo.KeyInfo;
  import javax.xml.crypto.dsig.keyinfo.X509Data;
  
  public class X509KeySelector extends KeySelector {
      public KeySelectorResult select(KeyInfo keyInfo,
                                  KeySelector.Purpose purpose,
                                  AlgorithmMethod method,
                                  XMLCryptoContext context)
      throws KeySelectorException {
          Iterator ki = keyInfo.getContent().iterator();
          while (ki.hasNext()) {
              XMLStructure info = (XMLStructure) ki.next();
              if (!(info instanceof X509Data))
                  continue;
              X509Data x509Data = (X509Data) info;
              Iterator xi = x509Data.getContent().iterator();
              while (xi.hasNext()) {
                  Object o = xi.next();
                  if (!(o instanceof X509Certificate))
                      continue;
                  final PublicKey key = ((X509Certificate)o).getPublicKey();
                  if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
                      return new KeySelectorResult() {
                          public Key getKey() { return key; }
                      };
                  }
             }
         }
         throw new KeySelectorException("No key found!");
      }
  
      static boolean algEquals(String algURI, String algName) {
          if ((algName.equalsIgnoreCase("DSA") &amp;&amp;
              algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) ||
              (algName.equalsIgnoreCase("RSA") &amp;&amp;
              algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1))) {
              return true;
          } else {
              return false;
          }
      }
  }
  </code></pre>
  
  <p>For example, if the original XML starts with:</p>
  
  <pre><code>&lt;nfeProc versao="1.10" xmlns="http://www.portalfiscal.inf.br/nfe"&gt;
  &lt;NFe xmlns="http://www.portalfiscal.inf.br/nfe"&gt;
  &lt;infNFe Id="NFe31090807301671000131550010001000216008030809" versao="1.10" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
  ...
  </code></pre>
  
  <p>doc4.asXML() return this:</p>
  
  <pre><code>&lt;nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.10"&gt;
  &lt;NFe&gt;
  &lt;infNFe xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Id="NFe31090807301671000131550010001000216008030809" versao="1.10"&gt;
  ...
  </code></pre>