1

如何解析一个类似 xml 的字符串并将其转换为一个单独的列表?

我正在尝试转换以下字符串:

<Categories>
  <Category Assigned="0">
    6 Level
    <Category Assigned="1">
      6.2 Level
      <Category Assigned="0">
        6.3 Level
        <Category Assigned="0">
          6.4 Level
          <Category Assigned="1">
            6.5 Level
          </Category>
        </Category>
      </Category>
    </Category>
  </Category>
</Categories>

到一个单独的列表,如:

6 Level/6.2 Level/6.3 Level/6.4 Level/6.5 Level, 6 Level/6.2 Level

exiv2 的 Robin Mills 提供了一个 perl 脚本: http ://dev.exiv2.org/boards/3/topics/1912?r=1923#message-1923

那还需要解析Assigned="1". 这如何在 C++ 中完成以在digikam中使用,内部dmetadata.cpp结构如下:

    QStringList ntp = tagsPath.replaceInStrings("<Category Assigned="0">", "/");

我没有足够的编程背景来解决这个问题,也没有在网上找到任何类似的代码示例。我还想将代码包含在 exiv2 本身中,以便其他应用程序可以受益。

工作代码将包含在 digikam 中:https ://bugs.kde.org/show_bug.cgi?id=345220

4

2 回答 2

0

Maik Qualmann为 digikam 提供了一个工作补丁!

QString xmlACDSee = getXmpTagString("Xmp.acdsee.categories", false);
if (!xmlACDSee.isEmpty())
{
    xmlACDSee.remove("</Categories>");
    xmlACDSee.remove("<Categories>");
    xmlACDSee.replace("/", "|");

    QStringList tagsXml = xmlACDSee.split("<Category Assigned");
    int category        = 0;
    int length;
    int count;

    foreach(const QString& tags, tagsXml)
    {
        if (!tags.isEmpty())
        {
            count  = tags.count("<|Category>");
            length = tags.length() - (11 * count) - 5;

            if (category == 0)
            {
                tagsPath << tags.mid(5, length);
            }
            else
            {
                tagsPath.last().append(QString("/") + tags.mid(5, length));
            }

            category = category - count + 1;

            if (tags.left(5) == QString("=\"1\">") && category > 0)
            {
                tagsPath << tagsPath.value(tagsPath.size() - count - 1);
            }
        }
    }

    if (!tagsPath.isEmpty())
    {
        return true;
    }
}
于 2015-04-18T14:49:28.727 回答
0

The code you have linked makes use of Perl's XML::Parser::Expat module, which is a glue layer on top of James Clark's Expat XML parser.

If you want to follow the same route you should write C++ that uses the same library, but it can be clumsy to use as the API is via callbacks that you specify to be called when certain events in the incoming XML stream occur. You can see them in the Perl code, commented process an start-of-element event etc.

Once you have linked to the library, it should be simple to write C code that is equivalent to the Perl in the callbacks — they are only a single line each. Please open a new question if you are having problems with understanding the Perl

Note also that Expat is a non-validating parser, which will let through malformed data without comment

Given that the biggest task is to parse the XML data in the first place, you may prefer a different solution that allows you to build an in-memory document structure from the XML data, and interrogate it using the Document Object Model (DOM). The libxml library allows you to do that, and has its own Perl glue layer in the XML::LibXML module

于 2015-04-11T19:54:16.753 回答