将XML标记表示为字符范围
您知道有任何基于原始未标记文本将XML标记与字符范围或偏移量信息进行转换的XML库吗?(我不太关心库的基础平台:它可以是Java、Python、Perl等。) 例如,假设我有以下未标记的文本:将XML标记表示为字符范围,xml,xml-parsing,Xml,Xml Parsing,您知道有任何基于原始未标记文本将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 我只找到了几个返回字符偏移量信息
the calico cat and the black dog
标记为
the <PET>calico</PET> cat and the <PET>black do</PET>g
在修复偏移量之后,我将重新生成XML
我只找到了几个返回字符偏移量信息的XML解析库,偏移量基于XML文本,而不是未标记的文本。偏移量也可能是错误的(cf.)。您反对.NET吗 您可能希望从HTML的角度解决这个问题。有一个名为的库可以解析HTML(不管怎样,它只是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[n]
|
+--[0]“文本节点”(文本节点)
|
+--[1]
| |
|+--[0]“印花布”(文本节点)
|
+--[2] “猫和猫”(文本节点)
|
+--[3]
| |
|+--[0]“黑色do”(文本节点)
|
+--[4] “g”(文本节点)
每个HtmlNode
对象都有一个LinePosition
属性,可以为您提供起始偏移量。可以通过增加节点文本的长度(属性InnerText
)或从下一个节点的LinePosition
中减去1来计算端点偏移
我不知道你是否认为这种方法不那么痛苦,但我会从这里开始(以前从未解决过这样的问题)
这里列出了各种语言的HTML解析库。下面介绍如何使用.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));
}
在更有趣的示例上运行时(使用嵌套标记):
我已经提供了一个.NET答案,但以下是如何使用XSLT实现这一点:
<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,
'# "', ., '"
')"/>
<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>
在该输入上运行时:
<n>the <PET>calico</PET> cat and the <PET>black do</PET>g</n>
<n>the <PET><COLOR>calico</COLOR></PET> cat and the <PET><COLOR>bla</COLOR>ck do</PET>g</n>
从长远来看,.Net可能不是我们的正确选择,但感谢您的回答。我已经用Java库编写了类似.NETXMLReader的解决方案,但是由于库错误,位置信息不准确。
PET: 4-10 # "calico"
COLOR: 4-10 # "calico"
PET: 23-31 # "black do"
COLOR: 23-26 # "bla"
<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,
'# "', ., '"
')"/>
<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>
<n>the <PET>calico</PET> cat and the <PET>black do</PET>g</n>
PET 4-10 # "calico"
PET 23-31 # "black do"
<n>the <PET><COLOR>calico</COLOR></PET> cat and the <PET><COLOR>bla</COLOR>ck do</PET>g</n>
PET 4-10 # "calico"
COLOR 4-10 # "calico"
PET 23-31 # "black do"
COLOR 23-26 # "bla"