1

iPhone アプリで xml ドキュメントを読み込んで解析しようとしています。解析を開始してから、オーバーライド メソッドを使用します。

   static void startElementSAX(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, 
                        int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes)

次に、属性を次のように文字列に変換しようとします。

   NSString *str1 = [[NSString alloc] initWithCString:attributes encoding:NSUTF8StringEncoding];

attributes パラメータの前に ** が 2 つ付いているのはなぜですか。上記のコードでデータを抽出して文字列に変換しようとすると、次の警告が表示されるのはなぜですか。

'initWithCString:encoding:' の引数 1 を互換性のないポインター型から渡しています。

4

5 に答える 5

3

libxml の開始要素コールバックのドキュメントには、ポインタは各属性に対して 5 つの値を保持する配列へのポインターであると記載されています (属性の数は nb_attributes で返されます)。これは、配列内の 5 番目ごとの値が新しい属性項目であることを意味します。

各属性の 5 つの項目は次のとおりです。

  1. localname (属性の名前)
  2. プレフィックス (属性の名前空間)
  3. URI
  4. [start of] 値 (値の xmlChar 文字列の先頭へのポインター)
  5. end [値の] (値の xmlChar 文字列の末尾へのポインター)

したがって、配列をステップスルーし、最初の属性のアイテムから各値を取得し、開始値ポインターを使用して、長さ = 終了 - 開始である xmlChar 文字列を取得する必要があります。次に、nb_attributes の値を読み取るまで、次の属性からやり直します。

それで頭が痛くなる場合は、Apple のNSXMLParserに切り替えることを強くお勧めします(リンクにはログインが必要な場合があります。または、このリンクNSXMLParserを使用してください)。その場合、属性を NSDictionary として取得します。すべての属性を取得するには、次のようにします。

for (NSString *attributeName in [attributeDict allKeys]) {
    NSString *attributeValue = [attributeDict objectForKey:attributeName];
    // do something here with attributeName and attributeValue
}

iPhone 開発者サイトにアクセスできる場合は、SeismicXMLの例を見てください。

于 2009-04-14T01:51:08.317 に答える
1

受け入れられた回答の説明は正しいですが、いくつかのサンプルコードも表示すると便利です。これは、属性から値を抽出する1つの方法にすぎません。少なくとも、テストしたときに機能します。しかし、私はCの第一人者にはほど遠いです。

for (int i = 0; i < nb_attributes; i += 5) {
    const char *attr = (const char *)attributes[i];
    const char *begin = (const char *)attributes[i + 3];
    const char *end = (const char *)attributes[i + 4];
    int vlen = strlen(begin) - strlen(end);
    char val[vlen + 1];
    strncpy(val, begin, vlen);
    val[vlen] = '\0';
    NSLog(@"attribute %s: %d = %s", attr, i, val);
}

NSXMLParserは優れていますが、私が知る限り、処理する前にXML全体をダウンロードします。libxmlを使用すると、一度にチャンクで読み取ることができます。それはより大きな柔軟性を可能にしますが、より高い学習曲線を可能にします。

于 2009-06-21T18:21:07.997 に答える
1

このサンプルは、次の 2 つの点を除いて優れています。

  • 属性ごとに 5 つの項目があるため、ループごとに 'i' を 5 ずつ増やす必要があります。
  • begin と end の両方で strlen() を実行するとコストがかかります。単純に begin から end を引く方が簡単です

for (int i = 0; i < nb_attributes*5; i += 5) 
{
    const char *attr = (const char *)attributes[i];
    const char *begin = (const char *)attributes[i + 3];
    const char *end = (const char *)attributes[i + 4];
    int vlen = end - begin;
    char val[vlen + 1];
    strncpy(val, begin, vlen);
    val[vlen] = '\0';
    NSLog(@"attribute %s = '%s'", attr, val);
}
于 2009-08-08T06:43:46.500 に答える
0

'**'表記は「ポインタへのポインタ」を意味します。C / C ++では、「文字列」は文字の配列で表されます。配列は実際には単なるポインタであるため、C /C++の文字列は実際には「char[]」または「char*」として宣言できます。[]表記は、配列へのポインターにコンパイルされます。

この一般的な例は、C /C++の典型的な「メイン」関数です。

int main(int argc, char **argv)

これは次と同等です:

int main(int argc, char *argv[])

argvは、char *「文字列」(プログラムへのコマンドライン引数)の配列です。

現時点では例を示すことはできませんが、個々の文字列にアクセスするには、属性を反復処理する必要があるようです。たとえば、attributes [0]は最初の属性文字列(xmlChar *)になります。個々の属性をNSStringに変換できるはずです。

于 2009-04-14T00:30:33.363 に答える
0

const xmlChar **namespacesCStrings の配列です (いくつあるint nb_namespacesかがわかります)。各名前空間を NSString として使用する場合は、次のようにすることができます。

NSMutableArray *namespaces = [[NSMutableArray alloc] init];

int i;
for (i = 0; i < nb_namespaces; i++) {
    NSString *namespace = [[NSString alloc] initWithCString:attributes[i] encoding:NSUTF8StringEncoding];
    [namespaces addObject:namespace];
}

このinitWithCStringメソッドは、xmlChar (CString の最初の文字)へxmlChar *のポインターである を期待しています。

xmlChar **xmlChar (最初のCString の最初の文字)へのポインターへのポインターを意味します。

于 2009-04-14T02:04:06.400 に答える