2011-08-10 16 views
1

我想按照子節點的屬性對XML文檔進行排序。我正在使用Visual C++中的Windows窗體。我試圖使用建議的解決方案here on Stackoverflow。但不知何故,它不會工作。按C++,XPath,Windows Forms中的屬性對XmlDocument中的節點排序

無序 XML的文檔如下所示:

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

分類 XML的文件應該是這樣的:

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

我嘗試下面的代碼,但checkme - 返回的字符串是。所以排序甚至不起作用。

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?

回答

1

,因爲.NET是不是我的事,但不在navigator-您的XPath>編譯錯誤,我可能是完全錯誤的selectExpression-> AddSort錯誤的XML數據類型

System::Xml::XPath::XPathExpression^ selectExpression = navigator->Compile("Message-List/Message"); 

selectExpression->AddSort(sortExpr, XmlSortOrder::Ascending, XmlCaseOrder::None, "", XmlDataType::Number); 
+0

哦,我的錯。那麼編譯在這個例子中是錯誤的。但在實際使用的代碼中,它適合真正的XML節點。我更新了守則。我將看看selectExpression-> AddSort。 但看看我發佈的鏈接中發佈的解決方案,它應該實際上工作。對?至少這就是discorax在這裏所說的:http://stackoverflow.com/questions/344737/sorting-xml-nodes-based-on-datetime-attribute-c-xpath – EliteTUM

0

最後,我設法對XML消息進行排序。

@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); 
    } 
} 
+0

很高興你的工作。也許你可以接受我的回答?聲譽是這個網站的全部內容! – john

+0

當然,感謝您的幫助:) – EliteTUM

0

我剛剛看到了這個解決方案,但在.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);