获取所有前/后兄弟文本内容

时间:2013-11-22 15:30:57

标签: xml xslt xpath xpath-2.0 schematron

考虑以下XML:

<paratext ID="p34"><bold>pass</bold> <bold>pass</bold></paratext>
<paratext ID="p35"><bold>pass</bold></paratext>
<paratext ID="p36">foo <bold>pass</bold> bar</paratext>
<paratext ID="p37">foo<bold> pass </bold>bar</paratext>
<paratext ID="p38"><bold>fail</bold><bold>fail</bold></paratext>
<paratext ID="p39">foo<bold>fail</bold>bar</paratext>

p34应该通过,因为粗体标签的字母之间存在非字母 p35应该通过,因为粗体标签外面没有alpha字符 p36应该通过,因为粗体文本和其他文本之间存在非字母 p37应该通过,因为粗体文本和其他文本之间存在非字母 p38应该失败,因为粗体alpha字符之间没有alpha字符 p39应该失败,因为粗体文本和“foo”或“bar”之间没有alpha字符

我尝试通过schematron做到这一点:

<iso:rule context="//jd:csc|//jd:bold|//jd:ital|//jd:underscore">
 <iso:assert test="   
    string-length(preceding-sibling::text()) = 0
    or      
    matches(substring(preceding-sibling::text(), string-length(preceding-sibling::text())), '[^a-zA-Z]')
    or
    matches(substring(.,1,1), '[^a-zA-Z]')
    ">
    {WS1046} An .alpha character cannot both immediately preceed and follow &lt;<iso:value-of select="name()"/>&gt; tag
 </iso:assert>
 <iso:assert test="  
    string-length(following-sibling::text()) = 0
    or
    matches(substring(following-sibling::text(), 1,1), '[^a-zA-Z]')
    or
    matches(substring(., string-length(.)), '[^a-zA-Z]')
    ">
    {WS1046} An .alpha character cannot both immediately preceed and follow &lt;/<iso:value-of select="name()"/>&gt; tag
 </iso:assert>
</iso:rule>

这个问题是它只查看当前上下文的父项的直接子文本节点。因此,p38不会失败,因为没有直接的子文本节点。此外,b<foo>bar <bold>pass</bold>之类的内容会失败,因为它只会在preceding-sibling::text()中看到“b”,而不会看到"foo "

我也尝试了::*/text()而不是::text(),但后来我遇到了类似的问题,因为我只看到兄弟元素中的文本而没有得到直接的兄弟文本节点。我需要把两件事情放在一起,有谁知道怎么做?


例如,在这个xml中:

<paratext ID="p1">hello <foo>bar</foo> <bold>THIS</bold> <foo>bar</foo>goodbye</paratext>

当上下文规则点击<bold>THIS</bold>并且之前正在检查时,我希望看到"hello bar ",并且在检查以下内容时我希望看到" bargoodbye"

1 个答案:

答案 0 :(得分:2)

使用XPath 2.0(您似乎在使用matches时使用),您可以使用:

string-join(preceding-sibling::node(), '') 

获取"hello bar ",并且:

string-join(following-sibling::node(), '') 

获取" bargoodbye"

以上几行假设您只有元素和文本节点作为兄弟节点。如果可以提供评论和/或处理说明,并且您希望忽略这些规则的内容,则可以使用:

string-join(preceding-sibling::* | preceding-sibling::text(), '')