1

元のマークされていないテキストに基づいて、XML マークアップを文字範囲またはオフセット情報との間で変換する XML ライブラリを知っていますか? (ライブラリのベース プラットフォームについてはあまり気にしません。Java、Python、Perl などである可能性があります。)

たとえば、次のマークのないテキストがあるとします。

the calico cat and the black dog

としてマークアップされています

the <PET>calico</PET> cat and the <PET>black do</PET>g

マークアップに位置エラーがあります (上で示したように)。私はそれらのエラーを修正する方法を知っています: それはここでの質問ではありません. しかし、これを行うために従来の階層志向の XML パーサーを使用するのはかなり面倒です。XML マークアップが帯域外の文字範囲に変換されていれば、簡単に調整できます。

PET: 4-10    # "calico"  (should be 4-14 "calico cat" )
PET: 23-31   # "black do" (should be 23-32 "black dog" )

オフセットを修正したら、XML を再生成します。

文字オフセット情報を返す XML 解析ライブラリをいくつか見つけただけです。オフセットは、マークのないテキストではなく、XML テキストに基づいています。また、オフセットが間違っている可能性もあります (cf. Java, XMLEvent location Characters )。

4

3 に答える 3

1

.NET に反対ですか?

HTML の観点からこれに取り組みたいと思うかもしれません。HTMLを解析できるHtmlAgilityPackと呼ばれるライブラリがあります(とにかくXMLです)。そうすることで、例はノードのリストのようになり、テキスト ノードと HTML (XML)PETノードに分割されます。

HtmlNode[n]
|
+--[0] "the " (text node)
|
+--[1] <PET>
|   |
|   +--[0] "calico" (text node)
|
+--[2] " cat and the " (text node)
|
+--[3] <PET>
|   |
|   +--[0] "black do" (text node)
|
+--[4] "g" (text node)

HtmlNodeオブジェクトには、LinePosition開始オフセットを提供するプロパティがあります。InnerText終了オフセットは、ノードのテキスト (プロパティ)の長さを加算するか、次のノードの から 1 を減算することによって計算できますLinePosition

このアプローチの方が痛みが少ないと思われるかどうかはわかりませんが、はここから始めます (これまでこのような問題に取り組んだことがありませんでした)。

ここには、さまざまな言語の HTML 解析ライブラリのリストがあります。

于 2013-04-22T19:56:16.600 に答える
1

.NET で XmlReader を使用してこれを実現する方法を次に示します。

class MarkupSpan
{
    internal string Name;
    internal int Start;
    internal int Stop;
    internal List<object> ChildItems;

    internal MarkupSpan(string name, int start)
    {
        Name = name;
        Start = start;
        ChildItems = new List<object>();
    }

    public override string ToString()
    {
        return string.Concat(ChildItems);
    }
}


private static string ProcessMarkup(string text)
{
    Stack<MarkupSpan> inputStack = new Stack<MarkupSpan>();

    StringReader sr = new StringReader("<n>" + text + "</n>");

    XmlReader xr = XmlReader.Create(sr);
    int pos = 0;
    StringBuilder output = new StringBuilder();

    while (xr.Read())
    {
        if (xr.Depth > 0)
        {
            switch (xr.NodeType)
            {
                case XmlNodeType.Text:
                    pos += xr.Value.Length;
                    if (inputStack.Count != 0)
                    {
                        inputStack.Peek().ChildItems.Add(xr.Value);
                    }
                    break;
                case XmlNodeType.Element:
                    MarkupSpan ms = new MarkupSpan(xr.LocalName, pos);
                    if (inputStack.Count != 0)
                    {
                        inputStack.Peek().ChildItems.Add(ms);
                    }
                    inputStack.Push(ms);
                    break;
                case XmlNodeType.EndElement:
                    ms = inputStack.Pop();
                    ms.Stop = pos;
                    if (inputStack.Count == 0)
                    {
                        output.Append(OutputSpan(ms));
                    }
                    break;
            }
        }
    }

    return output.ToString();
}

private static string OutputSpan(MarkupSpan ms)
{
    string nameAndRange = string.Format("{0}: {1}-{2}",
                                        ms.Name, ms.Start, ms.Stop);
    return string.Format("{0,-14}# \"{1}\"", nameAndRange, ms) +
           Environment.NewLine +
           string.Concat(ms.ChildItems.OfType<MarkupSpan>().Select(OutputSpan));
}

サンプル入力で実行すると、結果は次のようになります。

PET: 4-10     # "calico"
PET: 23-31    # "black do"

より興味深い例 (ネストされたタグを使用) で実行すると、次のようになります。

the <PET><COLOR>calico</COLOR></PET> cat and the <PET><COLOR>bla</COLOR>ck do</PET>g

結果は次のとおりです。

PET: 4-10     # "calico"
COLOR: 4-10   # "calico"
PET: 23-31    # "black do"
COLOR: 23-26  # "bla"
于 2013-04-22T20:50:48.450 に答える