在 C++、XPath、Windows 窗体中按属性对 XmlDocument 中的节点进行排序

发布于 2024-11-29 08:38:04 字数 1951 浏览 0 评论 0原文

我想按子节点的属性对 XML 文档进行排序。我正在 Visual C++ 中使用 Windows 窗体。我尝试使用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?

I want to sort a XML-Document by attributes of an Child-Node. I am working with Windows Forms in Visual C++. I tried to use the solution proposed here on Stackoverflow. But somehow it won't work.

My unsorted XML-Doc looks like the following:

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

My sorted XML-Doc should look like this:

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

I tried following Code, but the checkme-String returned is 0205. So the sorting doesn't even work.

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

Furthermore, I am stuck on how to proceed in the while-loop. How can I save the resorted xmlDoc as XmlDocument?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陈年往事 2024-12-06 08:38:04

我可能完全错了,因为 .NET 不是我的事,但是你的 navigator->Compile 中的 xpath 不是错误的,selectExpression->AddSort 中的 XML 数据类型是错误的吗

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

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

I might be completely wrong since .NET is not my thing, but isn't your xpath in navigator->Compile wrong and your XML data type in selectExpression->AddSort wrong

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

selectExpression->AddSort(sortExpr, XmlSortOrder::Ascending, XmlCaseOrder::None, "", XmlDataType::Number);
智商已欠费 2024-12-06 08:38:04

最后,我成功地对 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);
    }
}

Finally, I managed to sort the XML-Message.

@John: yes you were right, I missed to change the XmlDataType. Thanks for the hint.

The following Solution makes a Copy of a XmlDocument and sorts it by the numerical Attribute "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);
    }
}
日暮斜阳 2024-12-06 08:38:04

我刚刚看到这个解决方案,但在 .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);

I just saw this solution, but in .NET 4.0 you could use linq instead. I won't port it to C++, but you'll get the idea! It is a static function that sorts by attribute and the call to this method that replaces the old node with the sorted node.

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

And for the call, I use this:

        // 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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文