Сортировка узлов в XmlDocument по атрибутам в C ++, XPath, Windows Forms - PullRequest
1 голос
/ 11 августа 2011

Я хочу отсортировать XML-документ по атрибутам дочернего узла.Я работаю с Windows Forms в Visual C ++.Я попытался использовать предложенное решение здесь, на 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 - 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?

Ответы [ 3 ]

1 голос
/ 11 августа 2011

Я могу быть совершенно не прав, поскольку .NET - это не мое, но не ваш xpath в навигаторе-> Неправильная компиляция и ваш тип данных XML в selectExpression-> AddSort неправильно

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

selectExpression->AddSort(sortExpr, XmlSortOrder::Ascending, XmlCaseOrder::None, "", XmlDataType::Number);
0 голосов
/ 23 января 2012

Я только что видел это решение, но в .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);
0 голосов
/ 11 августа 2011

Наконец, мне удалось отсортировать XML-сообщение.

@ Джон: да, вы были правы, я пропустил изменение XmlDataType .Спасибо за подсказку.

Следующее Solution создает копию 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);
    }
}
...