Using Xpath With Default Namespace in C# for Canonicalisation

元气小坏坏 提交于 2019-12-24 14:21:49

问题


I'm trying to apply the C14N transform to some generated XML. It appears I can't use LINQ to retrieve the nodes to perform the canonicalisation so I have to go 'old school' with the DOM but I think I'm falling foul of the default namespace.

Here is a sample of my code.

static void Main(string[] args)
{
    XmlDocument xDoc = new XmlDocument();

    // Load some test xml
    string path = @"..\..\TestFiles\Test_1.xml";
    if (File.Exists(path) == true)
    { 
        xDoc.PreserveWhitespace = true;
        using (FileStream fs = new FileStream(path, FileMode.Open))
        {
            xDoc.Load(fs);
        }
    }

    //Instantiate an XmlNamespaceManager object. 
    System.Xml.XmlNamespaceManager xmlnsManager = new System.Xml.XmlNamespaceManager(xDoc.NameTable);

    //Add the namespaces used in books.xml to the XmlNamespaceManager.
    xmlnsManager.AddNamespace("", "http://www.myApps.co.uk/");

    // Create a list of nodes to have the Canonical treatment
        //Execute the XPath query using the SelectNodes method of the XmlDocument.
        //Supply the XmlNamespaceManager as the nsmgr parameter.
        //The matching nodes will be returned as an XmlNodeList.
    XmlNodeList nodeList = xDoc.SelectNodes("/ApplicationsBatch/Applications|/ApplicationsBatch/Applications//*", xmlnsManager);

    // Perform the C14N transform on the data
    XmlDsigC14NTransform transform = new XmlDsigC14NTransform();

    transform.LoadInput(nodeList);
    MemoryStream ms = (MemoryStream)transform.GetOutput(typeof(Stream));

    File.WriteAllBytes(@"..\..\TestFiles\ModifiedTest_1", ms.ToArray());
}

And my XML:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ApplicationsBatch xmlns="http://www.myApps.co.uk/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <MessageHeader>
    <MessageID>00000003</MessageID>
    <Body>11223344556</Body>
    <Timestamp>2011-08-02T09:00:00</Timestamp>
    <MessageCheck>?</MessageCheck>
  </MessageHeader>
  <Applications>
    <Application>
      <ApplicantDetails>
        <Title>MR</Title>
        <Forename>HOMER</Forename>
        <Middlenames>
          <Middlename></Middlename>
        </Middlenames>
        <PresentSurname>SIMPSON</PresentSurname>
        <CurrentAddress>
          <Address>
            <AddressLine1>ADDRESS LINE1</AddressLine1>
            <AddressLine2>ADDRESS LINE2</AddressLine2>
            <AddressTown>ADDRESS Town</AddressTown>
            <AddressCounty>COUNTY</AddressCounty>
            <Postcode>POST CODE</Postcode>
            <CountryCode>GB</CountryCode>
          </Address>
          <ResidentFromGyearMonth>2007-01</ResidentFromGyearMonth>
        </CurrentAddress>
      </ApplicantDetails>
    </Application>
    <Application>
      <ApplicantDetails>
        <Title>MR</Title>
        <Forename>BART</Forename>
        <Middlenames>
          <Middlename></Middlename>
        </Middlenames>
        <PresentSurname>SIMPSON</PresentSurname>
        <CurrentAddress>
          <Address>
            <AddressLine1>ADDRESS LINE1</AddressLine1>
            <AddressLine2>ADDRESS LINE2</AddressLine2>
            <AddressTown>ADDRESS Town</AddressTown>
            <AddressCounty>COUNTY</AddressCounty>
            <Postcode>POST CODE</Postcode>
            <CountryCode>GB</CountryCode>
          </Address>
          <ResidentFromGyearMonth>2007-01</ResidentFromGyearMonth>
        </CurrentAddress>
      </ApplicantDetails>
    </Application>
  </Applications>
</ApplicationsBatch>

I've read a few other topics around the area and came across this Gem but it's not solved the problem.

Using the XPath Visualiser shows the required nodes should be selected but my code fails to select any.


回答1:


I've found a partial answer to my problem.

When a new namespace is added to the manager it appears that the default namespace can't be an empty string. This is what I ended up with:

//Instantiate an XmlNamespaceManager object. 
System.Xml.XmlNamespaceManager xmlnsManager = new System.Xml.XmlNamespaceManager(xDoc.NameTable);

//Add the namespaces used to the XmlNamespaceManager.
xmlnsManager.AddNamespace("x", "http://www.myApps.co.uk/");

I then needed to modify the XPath to reflect the namespace identifier like this:

// Create a list of nodes to have the Canonical treatment
    //Execute the XPath query using the SelectNodes method of the XmlDocument.
    //Supply the XmlNamespaceManager as the nsmgr parameter.
    //The matching nodes will be returned as an XmlNodeList.
XmlNodeList nodeList = xDoc.SelectNodes("/x:ApplicationsBatch/x:Applications|/x:ApplicationsBatch/x:Applications//*", xmlnsManager);

The nodes are now selected and ready for transformation... although that returns the correct structure of XML but all the values have been removed but that is a problem for another question.



来源:https://stackoverflow.com/questions/6910253/using-xpath-with-default-namespace-in-c-sharp-for-canonicalisation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!