2012-06-19 26 views
6

Tengo un conjunto de xml generado mediante xmlserialization de algunos mensajes WCF. Ahora quiero hacer un método genérico en el que proporcione un nombre de archivo xml y un prefijo como mailxml12. Luego, en fichero XML aquellos elementos que no tienen ningún prefijo de espacio en su nombre debería ser sustituida por mailxml12:Cómo cambiar el espacio de nombres XML de cierto elemento

Al igual que el archivo de origen es:

<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> 

Después de que el método deseado debe ser cambiado por todo elemento nombre que no tiene prefijo con mailxml:. Me gusta DeliveryApptCreateRequest debe convertirse en mailxml:DeliveryApptCreateRequest mientras que el elemento como d2p1:CompanyName debe permanecer como está.

me han tratado con el siguiente código

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); 
    } 

único problema con él es que elemento raíz permanecer como está, mientras que todos se cambian ya que necesitaba

+0

Sólo significa ¿etiquetar elementos o atributos también? –

+0

He publicado un código que analizó su xml como una cadena, por lo que debería funcionar a pesar de los problemas con las declaraciones de espacios de nombres, etc. Sin embargo, debe tratar de determinar por qué la otra solución sugerida no funcionó en su aplicación. –

Respuesta

2

Usted sólo puede analizar todo el XML como una cadena e inserte espacios de nombres cuando corresponda. Sin embargo, esta solución puede crear muchas cadenas nuevas que solo se usan dentro del algoritmo, lo que no es bueno para el rendimiento. Sin embargo, he escrito una función que lo analiza de esta manera y parece funcionar bastante rápido para el XML de muestra que has publicado;). Puedo publicarlo si quieres usarlo.

Otra solución es cargar XML como XmlDocument y aprovechando el hecho de que es una estructura tipo árbol. De esta forma, puede crear un método recursivamente agregando espacios de nombres apropiados donde corresponda. Desafortunadamente, el atributo XmlNode.Name es de solo lectura y es por eso que debe copiar manualmente toda la estructura del xml para cambiar los nombres de algunos nodos. No tengo tiempo para escribir el código ahora mismo, así que simplemente te dejo escribirlo. Si encuentra algún problema con él, solo hágamelo saber.

actualización

He probado el código y el código sugerido por Jeff Mercado y ambos parecen funcionar correctamente, al menos en el XML de ejemplo que has publicado en la pregunta. Asegúrese de que el XML que intenta analizar sea el mismo que el que publicó.

sólo para hacer que funcione y resolver añadiendo cuestión de espacio de nombres pidió originalmente, puede utilizar el código, que se ocupa de todo el XML como un String y lo analiza de forma manual:

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; 
    } 

Puede comprobar este código en Para que su aplicación funcione, sin embargo, le recomiendo encarecidamente que determine por qué las otras soluciones sugeridas no funcionaron.

+0

¿Quiere decir "espacio de nombres" o "prefijo del espacio de nombres"? –

+0

Lucas por favor publíquelo –

+0

Su código es significativamente más corto, así que lo probé y parece funcionar correctamente. Agregó un prefijo al elemento raíz y los otros elementos sin el espacio de nombre previamente definido. Usé XML que está disponible en tu pregunta como muestra de prueba. Además, eche un vistazo a la respuesta de * Jeff Mercando *, ya que puede ser satisfactorio en este caso. Si esto no te ayuda, házmelo saber, entonces buscaremos otras soluciones. –

1

Dado que en este caso tiene definido un espacio de nombres predeterminado, puede eliminar la declaración de espacio de nombres predeterminada y agregar una nueva declaración para su nuevo prefijo usando el nombre del espacio de nombres anterior, reemplazándolo efectivamente.

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

Agradable y el código es realmente corto :). –

+0

Pero no funcionó. Después de ejecutar y guardar el elemento raíz del documento, permanezca como DeliveryApptCreateRequest en lugar de convertirse en mailxml: DeliveryApptCreateRequest –

+0

@KamranShahid: No lo creo. Si su XML miró cómo nos ha mostrado, entonces debería haber funcionado, esto ciertamente funciona para su ejemplo. Es el XML _realmente_ como lo que has mostrado en tu ejemplo? –

0

@ solución de JeffMercado no funcionó para mí (probablemente ya no tenía un espacio de nombres por defecto).

Terminé usando:

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

Para cambiar el espacio de nombres de un documento completo utilicé:

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); 
} 

Uso:

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

HTH

Cuestiones relacionadas