【问题标题】:Sort Nodes in XmlDocument by Attribute in C++, XPath, Windows Forms在 C++、XPath、Windows 窗体中按属性对 XmlDocument 中的节点进行排序
【发布时间】:2012-10-28 16:47:09
【问题描述】:

我想按子节点的属性对 XML 文档进行排序。我正在使用 Visual C++ 中的 Windows 窗体。我尝试使用here on Stackoverflow 提出的解决方案。但不知何故,它不起作用。

我的未排序 XML-Doc 如下所示:

<Message-List>
  <Message sendTime="0"></Message>
  <Message sendTime="20"></Message>
  <Message sendTime="5"></Message>
</Message-List>

我的排序 XML-Doc 应该如下所示:

<Message-List>
  <Message sendTime="0"></Message>
  <Message sendTime="5"></Message>
  <Message sendTime="20"></Message>
</Message-List>

我尝试遵循代码,但返回的 checkme-String 是 0205。所以排序甚至不起作用。

System::Xml::XmlDocument^ sourceXmlDoc = gcnew XmlDocument;
sourceXmlDoc->LoadXml("<Message-List><Message sendTime=\"0\"></Message><Message sendTime=\"20\"></Message><Message sendTime=\"5\"></Message></Message-List>");
System::Xml::XPath::XPathNavigator^ navigator = sourceXmlDoc->CreateNavigator();
System::Xml::XPath::XPathExpression^ selectExpression = navigator->Compile("Message-List/Message");
System::Xml::XPath::XPathExpression^ sortExpr = navigator->Compile("@sendTime");
selectExpression->AddSort(sortExpr, XmlSortOrder::Ascending, XmlCaseOrder::None, "", XmlDataType::Text);
System::Xml::XPath::XPathNodeIterator^ nodeIterator = navigator->Select(selectExpression);
String^ checkMe;
while (nodeIterator->MoveNext())
{
    if (nodeIterator->Current->MoveToFirstAttribute())
    {
        checkMe = checkMe + nodeIterator->Current->Value;
    }
}

此外,我被困在如何在 while 循环中进行。如何将使用过的 xmlDoc 保存为 XmlDocument?

【问题讨论】:

    标签: sorting attributes c++-cli xmldocument


    【解决方案1】:

    我可能完全错了,因为 .NET 不是我的东西,但不是你在导航器中的 xpath->编译错误和你在 selectExpression->AddSort 中的 XML 数据类型错误

    System::Xml::XPath::XPathExpression^ selectExpression = navigator->Compile("Message-List/Message");
    
    selectExpression->AddSort(sortExpr, XmlSortOrder::Ascending, XmlCaseOrder::None, "", XmlDataType::Number);
    

    【讨论】:

    • 哦,我的错。那么示例中的编译是错误的。但在实际使用的代码中,它适合真正的 XML 节点。我更新了代码。我将看看 selectExpression->AddSort。但是看看我发布的链接中发布的解决方案,它应该确实有效。正确的?至少 discorax 是这么说的:stackoverflow.com/questions/344737/…
    【解决方案2】:

    最后,我设法对 XML-Message 进行了排序。

    @John:是的,你是对的,我错过了更改 XmlDataType。感谢您的提示。

    以下解决方案制作一个 XmlDocument 的副本,并按数字属性“sendTime”对其进行排序。

    // Create Source-Document for Testing
    System::Xml::XmlDocument^ sourceXmlDoc = gcnew XmlDocument;
    sourceXmlDoc->LoadXml("<Message-List><Message sendTime=\"0\"></Message><Message sendTime=\"20\"></Message><Message sendTime=\"5\"></Message></Message-List>");
    
    // Create a copy of the input XmlDocument
    System::Xml::XmlDocument^ xmlDocCopy = gcnew XmlDocument;
    xmlDocCopy = safe_cast<XmlDocument^>(sourceXmlDoc->Clone());
    
    // Only needs to be resorted if there are Messages to be sorted
    if ( xmlDocCopy->HasChildNodes )
    {
        // Remove the unsorted Children
        xmlDocCopy->FirstChild->RemoveAll();
    
        // Create a sorted Navigator
        System::Xml::XPath::XPathNavigator^ navigator = sourceXmlDoc->CreateNavigator();
        System::Xml::XPath::XPathExpression^ selectExpression = navigator->Compile("Message-List/Message");
        System::Xml::XPath::XPathExpression^ sortExpr = navigator->Compile("@sendTime");
        selectExpression->AddSort(sortExpr, XmlSortOrder::Ascending, XmlCaseOrder::None, "", XmlDataType::Number);
        System::Xml::XPath::XPathNodeIterator^ nodeIterator = navigator->Select(selectExpression);
    
        String^ checkMe;
        String^ test = nodeIterator->Current->OuterXml;
    
        while (nodeIterator->MoveNext())
        {
            XmlTextReader^ xmlChildReader = gcnew XmlTextReader(gcnew StringReader(nodeIterator->Current->OuterXml));
            XmlNode^ newNode = xmlDocCopy->ReadNode(xmlChildReader);
            xmlDocCopy->FirstChild->AppendChild(newNode);
        }
    }
    

    【讨论】:

    • 很高兴你能成功。也许你可以接受我的回答?声誉就是这个网站的全部意义所在!
    【解决方案3】:

    我刚刚看到了这个解决方案,但在 .NET 4.0 中,您可以改用 linq。我不会将它移植到 C++,但你会明白的!它是一个按属性排序的静态函数,调用此方法将旧节点替换为排序后的节点。

        public static XmlElement OrderChildrenByAttribute(XmlElement originalElement, string attributeName)
        {
            // Sorting products
            var enumList = originalElement.ChildNodes.Cast<XmlElement>();
            var sortedList = enumList.OrderBy(p => p.GetAttribute(attributeName).Trim().ToLower());
            XmlElement result = originalElement.OwnerDocument.CreateElement(originalElement.Name, originalElement.NamespaceURI);
            foreach (var childElem in sortedList)
                result.AppendChild(childElem);
            return result;
        }
    

    对于通话,我使用这个:

            // Sort by "name" attribute
            XmlElement elem_params_Products_sorted = XmlTools.OrderChildrenByAttribute(elem_params_Products, "name");
            elem_params_Products.ParentNode.ReplaceChild(elem_params_Products_sorted, elem_params_Products);
    

    【讨论】:

      猜你喜欢
      • 2015-06-18
      • 2010-09-25
      • 1970-01-01
      • 2010-10-22
      • 2011-08-09
      • 1970-01-01
      • 1970-01-01
      • 2015-12-18
      • 2021-03-23
      相关资源
      最近更新 更多