2012-06-19 18 views
6

Ho alcuni set di xml generati tramite xmlserialization di alcuni messaggi WCF. Ora voglio creare un metodo generico in cui fornirò un nome file xml e un prefisso come mailxml12. Poi, nel file XML gli elementi che non hanno alcun prefisso namespace in loro nome dovrebbe essere sostituito con mailxml12:Come modificare lo spazio dei nomi XML di determinati elementi

come file sorgente è:

<DeliveryApptCreateRequest d2p1:ApptType="Pallet" d2p1:PickupOrDelivery="Delivery" d2p1:ShipperApptRequestID="4490660303D5" d2p1:SchedulerCRID="234234" xmlns:d2p1="http://idealliance.org/Specs/mailxml12.0a/mailxml_defs" xmlns="http://idealliance.org/Specs/mailxml12.0a/mailxml_tm"> 
<SubmittingParty d2p1:MailerID6="123446" d2p1:CRID="342343" d2p1:MaildatUserLicense="A123" /> 
<SubmittingSoftware d2p1:SoftwareName="asds" d2p1:Vendor="123" d2p1:Version="12" /> 
<SubmitterTrackingID>2CAD3F71B4405EB16392</SubmitterTrackingID> 
<DestinationEntry>No</DestinationEntry> 
<OneTimeAppt> 
    <PreferredAppt>2012-06-29T09:00:00Z</PreferredAppt> 
</OneTimeAppt>  
<TrailerInfo> 
    <Trailer> 
    <TrailerNumber>A</TrailerNumber> 
    <TrailerLength>20ft</TrailerLength> 
    </Trailer> 
    <Carrier> 
    <CarrierName>N/A</CarrierName> 
    <URL>http://test.com</URL> 
    </Carrier> 
    <BillOfLadingNumber>N/A</BillOfLadingNumber> 
</TrailerInfo> 
</DeliveryApptCreateRequest> 

Dopo il metodo desiderato dovrebbe essere cambiato in tutti gli elementi nome che non ha il prefisso mailxml:. Come DeliveryApptCreateRequest dovrebbe diventare mailxml:DeliveryApptCreateRequest mentre l'elemento come d2p1:CompanyName dovrebbe rimanere così com'è.

ho provato con seguente codice

private void RepalceFile(string xmlfile) 
    { 
     XmlDocument doc = new XmlDocument(); 
     doc.Load(xmlfile); 
     var a = doc.CreateAttribute("xmlns:mailxml12tm"); 
     a.Value = "http://idealliance.org/Specs/mailxml12.0a/mailxml_tm"; 
     doc.DocumentElement.Attributes.Append(a); 
     doc.DocumentElement.Prefix = "mailxml12tm"; 

     foreach (XmlNode item in doc.SelectNodes("//*")) 
     { 
      if (item.Prefix.Length == 0) 
       item.Prefix = "mailxml12tm"; 
     } 
     doc.Save(xmlfile); 
    } 

unico problema è che elemento principale rimane così com'è, mentre tutti sono cambiato come ho avuto bisogno

+0

Vuoi dire solo tag anche gli attributi o gli attributi? –

+0

Ho pubblicato il codice che ha analizzato il tuo xml come una stringa, quindi dovrebbe funzionare nonostante i problemi con le dichiarazioni dello spazio dei nomi ecc. Tuttavia, dovresti provare a determinare perché l'altra soluzione suggerita non ha funzionato nella tua applicazione. –

risposta

2

Si può solo analizzare l'intero XML come una stringa e inserire spazi dei nomi dove appropriato. Questa soluzione, tuttavia, può creare molte nuove stringhe utilizzate solo nell'algoritmo, il che non è positivo per le prestazioni. Tuttavia, ho scritto una funzione analizzandola in questo modo e sembra che sia abbastanza veloce per l'XML di esempio che hai pubblicato;). Posso postarlo se vuoi usarlo.

Un'altra soluzione sta caricando XML come XmlDocument e sfruttando il fatto che si tratta di una struttura ad albero. In questo modo, è possibile creare un metodo in modo ricorsivo aggiungendo spazi dei nomi appropriati laddove appropriato. Sfortunatamente, l'attributo XmlNode.Name è di sola lettura ed è per questo che è necessario copiare manualmente l'intera struttura di xml per cambiare i nomi di alcuni nodi. Non ho tempo di scrivere il codice adesso, quindi ti lascio solo scrivere. Se incontri qualche problema, fammelo sapere.

Aggiornamento

Ho provato il codice e il codice suggerito da Jeff Mercado ed entrambi sembrano funzionare correttamente, almeno nel XML di esempio che hai postato nella domanda. Assicurati che l'XML che stai cercando di analizzare sia lo stesso di quello che hai pubblicato.

Proprio per farlo funzionare e risolvere aggiungendo problema namespace originariamente chiesto, è possibile utilizzare il codice, che gestisce l'intero XML come String e lo analizza manualmente:

private static String UpdateNodesWithDefaultNamespace(String xml, String defaultNamespace) 
    { 
     if (!String.IsNullOrEmpty(xml) && !String.IsNullOrEmpty(defaultNamespace)) 
     { 
      int currentIndex = 0; 

      while (currentIndex != -1) 
      { 
       //find index of tag opening character 
       int tagOpenIndex = xml.IndexOf('<', currentIndex); 

       //no more tag openings are found 
       if (tagOpenIndex == -1) 
       { 
        break; 
       } 

       //if it's a closing tag 
       if (xml[tagOpenIndex + 1] == '/') 
       { 
        currentIndex = tagOpenIndex + 1; 
       } 
       else 
       { 
        currentIndex = tagOpenIndex; 
       } 

       //find corresponding tag closing character 
       int tagCloseIndex = xml.IndexOf('>', tagOpenIndex); 
       if (tagCloseIndex <= tagOpenIndex) 
       { 
        throw new Exception("Invalid XML file."); 
       } 

       //look for a colon within currently processed tag 
       String currentTagSubstring = xml.Substring(tagOpenIndex, tagCloseIndex - tagOpenIndex); 
       int firstSpaceIndex = currentTagSubstring.IndexOf(' '); 
       int nameSpaceColonIndex; 
       //if space was found 
       if (firstSpaceIndex != -1) 
       { 
        //look for namespace colon between tag open character and the first space character 
        nameSpaceColonIndex = currentTagSubstring.IndexOf(':', 0, firstSpaceIndex); 
       } 
       else 
       { 
        //look for namespace colon between tag open character and tag close character 
        nameSpaceColonIndex = currentTagSubstring.IndexOf(':'); 
       } 

       //if there is no namespace 
       if (nameSpaceColonIndex == -1) 
       { 
        //insert namespace after tag opening characters '<' or '</' 
        xml = xml.Insert(currentIndex + 1, String.Format("{0}:", defaultNamespace)); 
       } 

       //look for next tags after current tag closing character 
       currentIndex = tagCloseIndex; 
      } 
     } 

     return xml; 
    } 

È possibile controllare questo codice in Per far sì che la tua app funzioni, ti incoraggio vivamente a determinare perché le altre soluzioni suggerite non hanno funzionato.

+0

Intendi "spazio dei nomi" o "prefisso del namespace"? –

+0

Lucas per favore postalo –

+0

Il tuo codice è significativamente più corto, quindi l'ho provato e sembra funzionare correttamente. Aggiunge un prefisso all'elemento radice e gli altri elementi senza spazio dei nomi precedentemente definito. Ho usato l'XML che è disponibile nella tua domanda come campione di prova. Inoltre, dai un'occhiata a una risposta di * Jeff Mercando * che potrebbe essere soddisfacente in questo caso. Se questo non ti aiuta, fammelo sapere, quindi cercheremo altre soluzioni. –

1

Poiché in questo caso è stato definito uno spazio dei nomi predefinito, è possibile rimuovere la dichiarazione dello spazio dei nomi predefinita e aggiungere una nuova dichiarazione per il nuovo prefisso utilizzando il nome del vecchio spazio dei nomi, sostituendolo efficacemente.

var prefix = "mailxml"; 
var content = XElement.Parse(xmlStr); 
var defns = content.GetDefaultNamespace(); 
content.Attribute("xmlns").Remove(); 
content.Add(new XAttribute(XNamespace.Xmlns + prefix, defns.NamespaceName)); 
+0

Bello e il codice è davvero breve :). –

+0

Ma non ha funzionato. Dopo l'esecuzione e il salvataggio dell'elemento root del documento rimane come DeliveryApptCreateRequest invece di diventare mailxml: DeliveryApptCreateRequest –

+0

@KamranShahid: Non ci credo. Se il tuo XML ha visto come ci hai mostrato, allora avrebbe dovuto funzionare, questo sicuramente funziona per il tuo esempio. L'XML è veramente simile a quello che hai mostrato nel tuo esempio? –

0

@ La soluzione di JeffMercado non ha funzionato per me (probabilmente poiché non avevo uno spazio dei nomi predefinito).

ho finito per usare:

XNamespace ns = Constants.Namespace; 
el.Name = (ns + el.Name.LocalName) as XName; 

Per modificare lo spazio dei nomi di un documento complesso che ho usato:

private void rewriteNamespace(XElement el) 
{ 
    // Change namespace 
    XNamespace ns = Constants.Namespace; 
    el.Name = (ns + el.Name.LocalName) as XName; 

    if (!el.HasElements) 
     return; 

    foreach (XElement d in el.Elements()) 
     rewriteNamespace(d); 
} 

Usage:

var doc = XDocument.parse(xmlStr); 
rewriteNamespace(doc.Root) 

HTH

Problemi correlati