首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将XML标记表示为字符范围

将XML标记表示为字符范围
EN

Stack Overflow用户
提问于 2013-04-23 03:47:58
回答 3查看 60关注 0票数 1

您知道有什么XML库可以基于原始的未标记文本在XML标记与字符范围或偏移信息之间进行相互转换吗?(我不太关心这些库的基础平台:它可以是Java、Python、Perl等)。

例如,假设我有这样一个未标记的文本:

代码语言:javascript
复制
the calico cat and the black dog

它被标记为

代码语言:javascript
复制
the <PET>calico</PET> cat and the <PET>black do</PET>g

标记有位置错误(如上所述)。我知道如何修复这些错误:这不是这里的问题。但是使用传统的具有层次结构的XML解析器来做这件事是相当痛苦的。如果将XML标记转换为我可以轻松调整的带外字符范围,将会更容易:

代码语言:javascript
复制
PET: 4-10    # "calico"  (should be 4-14 "calico cat" )
PET: 23-31   # "black do" (should be 23-32 "black dog" )

在修复偏移量之后,我将重新生成XML。

我只找到了几个返回字符偏移量信息的XML解析库,偏移量是基于XML文本的,而不是未标记的文本。此外,偏移量也可能是错误的(参见Java, XMLEvent location Characters)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-23 04:50:48

下面是如何在.NET中使用XmlReader来完成此操作:

代码语言:javascript
复制
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));
}

在样例输入上运行时,结果为:

代码语言:javascript
复制
PET: 4-10     # "calico"
PET: 23-31    # "black do"

当在一个更有趣的例子上运行时(带有嵌套标签):

代码语言:javascript
复制
the <PET><COLOR>calico</COLOR></PET> cat and the <PET><COLOR>bla</COLOR>ck do</PET>g

结果是:

代码语言:javascript
复制
PET: 4-10     # "calico"
COLOR: 4-10   # "calico"
PET: 23-31    # "black do"
COLOR: 23-26  # "bla"
票数 1
EN

Stack Overflow用户

发布于 2013-04-23 03:56:17

你反对.NET吗?

您可能希望从HTML的角度来处理这个问题。有一个叫做HtmlAgilityPack的库可以解析超文本标记语言(不管怎么说,它只是一个XML )。这样,您的示例看起来就像一个节点列表,分为文本节点和超文本标记语言( PET )节点:

代码语言:javascript
复制
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属性)或从下一个节点的LinePosition中减去1来计算。

我不知道您是否认为这种方法不那么痛苦,但这是我要开始的地方(我以前从未解决过这样的问题)。

这里有各种语言的的超文本标记语言解析库。

票数 1
EN

Stack Overflow用户

发布于 2013-04-23 05:11:45

我已经提供了一个.NET的答案,但下面是如何使用XSLT实现的:

代码语言:javascript
复制
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" />
  <xsl:variable name="space" select="'                  '" />
  <xsl:variable name="spaceLen" select="string-length($space)" />

  <xsl:template match="text()" />

  <xsl:template match="*/*">
    <xsl:param name="parentLeading" select="0" />
    <xsl:variable name="leadingText">
      <xsl:apply-templates select="preceding-sibling::node()" mode="value" />
    </xsl:variable>

    <xsl:variable name="leading" select="$parentLeading + 
                                             string-length($leadingText)" />

    <xsl:variable name="nameAndRange" 
                  select="concat(local-name(), ' ', $leading, 
                                 '-', $leading + string-length())" />
    <xsl:variable name="spacing"
                  select="substring($space, 1, 14 - string-length($nameAndRange))" />
    <xsl:value-of select="concat($nameAndRange, $spacing, 
                                 '# &quot;', ., '&quot;&#xA;')"/>
    <xsl:apply-templates>
      <xsl:with-param name="parentLeading" select="$leading" />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="node()" mode="value">
    <xsl:value-of select="." />
  </xsl:template>
</xsl:stylesheet>

在此输入上运行时:

代码语言:javascript
复制
<n>the <PET>calico</PET> cat and the <PET>black do</PET>g</n>

结果是:

代码语言:javascript
复制
PET 4-10      # "calico"
PET 23-31     # "black do"

在此输入上运行时:

代码语言:javascript
复制
<n>the <PET><COLOR>calico</COLOR></PET> cat and the <PET><COLOR>bla</COLOR>ck do</PET>g</n>

结果是:

代码语言:javascript
复制
PET 4-10      # "calico"
COLOR 4-10    # "calico"
PET 23-31     # "black do"
COLOR 23-26   # "bla"
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16155481

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档