简体   繁体   English

如何更改某些元素的XML命名空间

[英]How To change XML namespace of certain element

I have some set of xml generated via xmlserialization of some WCF messages. 我有一些xml通过一些WCF消息的xmlserialization生成。 Now I want to make a generic method in which I will provide an xml filename and a prefix like mailxml12 . 现在我想制作一个通用的方法,我将提供一个xml文件名和一个像mailxml12这样的前缀。 Then in xml file those elements that don't have any namespace prefix in their name should be replaced with mailxml12: 然后在xml文件中,名称中没有任何名称空间前缀的元素应替换为mailxml12:

Like source file is: 像源文件是:

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

After the desired method it should be changed into all element name which doesn't have prefix with mailxml: . 在所需的方法之后,应将其更改为所有没有mailxml:前缀的元素名称mailxml: Like DeliveryApptCreateRequest should become mailxml:DeliveryApptCreateRequest while element like d2p1:CompanyName should remain as it is. DeliveryApptCreateRequest应该成为mailxml:DeliveryApptCreateRequest而像d2p1:CompanyName这样的元素应保持原样。

I have tried with following code 我试过以下代码

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

only problem with it is that root element remain as it is while all are changed as i needed 唯一的问题是根元素保持原样,而所有根据我的需要进行更改

You can just parse the whole XML as a string and insert namespaces where appropriate. 您可以将整个XML解析为字符串,并在适当的位置插入名称空间。 This solution, however, can create lots of new strings only used within the algorithm, which is not good for the performance. 但是,此解决方案可以创建许多仅在算法中使用的新字符串,这对性能不利。 However, I've written a function parsing it in this manner and it seems to run quite fast for sample XML you've posted ;). 但是,我已经编写了一个以这种方式解析它的函数,它似乎对你发布的样本XML运行得非常快;)。 I can post it if you would like to use it. 如果你想使用它,我可以发布它。

Another solution is loading XML as XmlDocument and taking advantage of the fact it's a tree-like structure. 另一个解决方案是将XML作为XmlDocument加载,并利用它是树状结构的事实。 This way, you can create a method recursively adding appropriate namespaces where appropriate. 这样,您可以在适当的位置以递归方式添加适当的名称空间。 Unfortunately, XmlNode.Name attribute is read-only and that's why you have to manually copy the entire structure of the xml to change names of some nodes. 不幸的是, XmlNode.Name属性是只读的,这就是为什么你必须手动复制xml的整个结构来更改某些节点的名称的原因。 I don't have time to write the code right now, so I just let you write it. 我现在没有时间编写代码,所以我只是让你写它。 If you encounter any issues with it, just let me know. 如果您遇到任何问题,请告诉我。

Update 更新

I've tested your code and code suggested by Jeff Mercado and both of them seem to work correctly, at least in the sample XML you've posted in the question. 我已经测试了Jeff Mercado建议的代码和代码,并且它们似乎都正常工作,至少在您在问题中发布的示例XML中。 Make sure the XML you are trying to parse is the same as the one you've posted. 确保您尝试解析的XML与您发布的XML相同。

Just to make it work and solve adding namespace issue originally asked, you can use the code, which handles the whole XML as a String and parses it manually: 只是为了使它工作并解决最初提出的添加命名空间问题,您可以使用代码,它将整个XML作为String并手动解析:

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

You can check this code out in order to make you app working, however, I strongly encourage you to determine why the other solutions suggested didn't work. 您可以检查此代码以使应用程序正常工作,但是,我强烈建议您确定其他解决方案建议无效的原因。

Since in this case you have a default namespace defined, you could just remove the default namespace declaration and add a new declaration for your new prefix using the old namespace name, effectively replacing it. 由于在这种情况下您定义了默认命名空间,因此您可以删除默认命名空间声明,并使用旧命名空间名称为新前缀添加新声明,从而有效地替换它。

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

@JeffMercado's solution didn't work for me (probably since I didn't have a default namespace). @ JeffMercado的解决方案对我不起作用(可能因为我没有默认命名空间)。

I ended up using: 我最终使用:

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

To change the namespace of a whole document I used: 要更改我使用的整个文档的命名空间:

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 HTH

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM