xquery自动换行

xquery自动换行,xquery,Xquery,我需要使用XQuery将长字符串包装为100个字符。换言之,将一些空格改为换行符,使非语法行短于100个字符。有一种简单的方法吗?如果一行长度超过100个字符,则需要用换行符替换前101个字符中的最后一组连续空格。如果前101个字符中没有空格,则只需替换行中的第一个空格,然后可以在字符串的其余行上递归应用相同的逻辑 可以这样做: declare function local:wrap-line($str) { if (string-length($str) < 100 or not(c

我需要使用XQuery将长字符串包装为100个字符。换言之,将一些空格改为换行符,使非语法行短于100个字符。有一种简单的方法吗?

如果一行长度超过100个字符,则需要用换行符替换前101个字符中的最后一组连续空格。如果前101个字符中没有空格,则只需替换行中的第一个空格,然后可以在字符串的其余行上递归应用相同的逻辑

可以这样做:

declare function local:wrap-line($str)
{
  if (string-length($str) < 100 or not(contains($str," ")))
  then $str
  else 
    let $wrapped := if (contains(substring($str,1,101)," "))
                    then replace($str, "^(.{0,99}[^ ]) +", "$1&#10;")
                    else replace($str, "^(.*?) ", "$1&#10;")
    return concat(substring-before($wrapped, "&#10;"), "&#10;",
                  local:wrap-line(substring-after($wrapped, "&#10;")))
};

declare function local:word-wrap($str)
{
  string-join(
    for $line in tokenize($str,"&#10;")
    return local:wrap-line($line),
    "&#10;")
};
声明函数本地:换行($str)
{
如果(字符串长度($str)<100或不小于100(包含($str,“”))
然后是$str
其他的
let$wrapped:=if(包含(子字符串($str,1101),“”)
然后替换($str,“^(.{0,99}[^])+”,“$1
;”)
否则替换($str,“^(.*?”,“$1
;”)
返回concat(($wrapped,
;“”,
;“”)之前的子字符串,
;“,
局部:换行(($wrapped,
;“”)后的子字符串)
};
声明函数local:wordwrap($str)
{
串接(
对于标记化中的$line($str,
;)
返回本地:换行($line),
"
")
};
这是可行的,因为
(.{0,99}[^])+
匹配不以空格结尾的最长可能的100个字符序列,然后是多个空格,
(.*)
匹配以空格结尾的最短可能的字符序列


代码很难达到最佳效果,对于退化情况(例如,一行以几个空格结尾的文本,但它确实有效。

我对XQuery了解不够,无法在XQuery中表达此XSLT解决方案,但我认为提供它可能会有所帮助

请注意,在典型的现实世界中,单词由多个分隔符分隔。以下解决方案将参数中指定的所有字符视为分隔符,并以最大长度边界拆分每一行。它是XSLT 1.0或2.0的FXSL函数/模板库的一部分

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:ext="http://exslt.org/common"
xmlns:str-split2lines-func="f:str-split2lines-func"
exclude-result-prefixes="xsl f ext str-split2lines-func"
>


   <xsl:import href="dvc-str-foldl.xsl"/>

   <str-split2lines-func:str-split2lines-func/>

   <xsl:output indent="yes" omit-xml-declaration="yes"/>

    <xsl:template match="/">
      <xsl:call-template name="str-split-to-lines">
        <xsl:with-param name="pStr" select="/*"/>
        <xsl:with-param name="pLineLength" select="60"/>
        <xsl:with-param name="pDelimiters" select="' &#9;&#10;&#13;'"/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template name="str-split-to-lines">
      <xsl:param name="pStr"/>
      <xsl:param name="pLineLength" select="60"/>
      <xsl:param name="pDelimiters" select="' &#9;&#10;&#13;'"/>

      <xsl:variable name="vsplit2linesFun"
                    select="document('')/*/str-split2lines-func:*[1]"/>

      <xsl:variable name="vrtfParams">
       <delimiters><xsl:value-of select="$pDelimiters"/></delimiters>
       <lineLength><xsl:copy-of select="$pLineLength"/></lineLength>
      </xsl:variable>

      <xsl:variable name="vResult">
          <xsl:call-template name="dvc-str-foldl">
            <xsl:with-param name="pFunc" select="$vsplit2linesFun"/>
            <xsl:with-param name="pStr" select="$pStr"/>
            <xsl:with-param name="pA0" select="ext:node-set($vrtfParams)"/>
          </xsl:call-template>
      </xsl:variable>
      <xsl:for-each select="ext:node-set($vResult)/line">
        <xsl:for-each select="word">
          <xsl:value-of select="concat(., ' ')"/>
        </xsl:for-each>
        <xsl:value-of select="'&#xA;'"/>
      </xsl:for-each>
    </xsl:template>

    <xsl:template match="str-split2lines-func:*" mode="f:FXSL">
      <xsl:param name="arg1" select="/.."/>
      <xsl:param name="arg2"/>

      <xsl:copy-of select="$arg1/*[position() &lt; 3]"/>
      <xsl:copy-of select="$arg1/line[position() != last()]"/>

      <xsl:choose>
        <xsl:when test="contains($arg1/*[1], $arg2)">
          <xsl:if test="string($arg1/word) or string($arg1/line/word)">
             <xsl:call-template name="fillLine">
               <xsl:with-param name="pLine" select="$arg1/line[last()]"/>
               <xsl:with-param name="pWord" select="$arg1/word"/>
               <xsl:with-param name="pLineLength" select="$arg1/*[2]"/>
             </xsl:call-template>
          </xsl:if>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="$arg1/line[last()]"/>
          <word><xsl:value-of select="concat($arg1/word, $arg2)"/></word>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>

      <!-- Test if the new word fits into the last line -->
    <xsl:template name="fillLine">
      <xsl:param name="pLine" select="/.."/>
      <xsl:param name="pWord" select="/.."/>
      <xsl:param name="pLineLength" />

      <xsl:variable name="vnWordsInLine" select="count($pLine/word)"/>
      <xsl:variable name="vLineLength" 
       select="string-length($pLine) + $vnWordsInLine"/>
      <xsl:choose>
        <xsl:when test="not($vLineLength + string-length($pWord) 
                           > 
                            $pLineLength)">
          <line>
            <xsl:copy-of select="$pLine/*"/>
            <xsl:copy-of select="$pWord"/>
          </line>
        </xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="$pLine"/>
          <line>
            <xsl:copy-of select="$pWord"/>
          </line>
          <word/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

我想您只需要这个XPath 2.0表达式:

replace(concat(normalize-space(text),' '),'(.{0,60}) ','$1&#xA;')
使用Dimitre的输入,输出:

Dec. 13 — As always for a presidential inaugural, security
and surveillance were extremely tight in Washington, DC,
last January. But as George W. Bush prepared to take the
oath of office, security planners installed an extra layer
of protection: a prototype software system to detect a
biological attack. The U.S. Department of Defense, together
with regional health and emergency-planning agencies,
distributed a special patient-query sheet to military
clinics, civilian hospitals and even aid stations along the
parade route and at the inaugural balls. Software quickly
analyzed complaints of seven key symptoms — from rashes to
sore throats — for patterns that might indicate the early
stages of a bio-attack. There was a brief scare: the system
noticed a surge in flulike symptoms at military clinics.
Thankfully, tests confirmed it was just that — the flu.

尝试使用下面的XQuery功能:这可以对任何文本进行自动换行

要传递的参数: 1.$Text-文字到文字换行 2.50字-换行字符串长度 3. " “-换行符后-换行符 4.0-起始位置

declare function xf:wrap-string($str as xs:string,
                                $wrap-col as xs:integer,
                                $break-mark as xs:string,
                                $pos as xs:integer)
    as xs:string {
       if(fn:contains( $str, ' ' )) then 
        let $first-word := fn:substring-before( $str, ' ' )
        let $pos-now := xs:integer($pos + 1 + string-length($first-word))
        return
            if ($pos>0 and $pos-now>=$wrap-col) then
                 concat($break-mark,
                 xf:wrap-string($str,$wrap-col,$break-mark,xs:integer(0)))
            else
                concat($first-word,' ',
                 xf:wrap-string(substring-after( $str, ' ' ),
                               $wrap-col,
                               $break-mark,
                               $pos-now))
       else(
        if ($pos+string-length($str)>$wrap-col) then
            concat($break-mark,$str)
        else ($str)
       )
};

    declare function xf:wrap-test($str as xs:string,
                                    $wrap-col as xs:integer,
                                    $break-mark as xs:string,
                                    $pos as xs:integer)
     as xs:string {
            let $Result := xf:wrap-string($str,$wrap-col,$break-mark,$pos)
            return
            if (fn:contains($Result,'&#10;')) then
                fn:string-join(for $line in tokenize($Result, '&#10;')
                                return
                                if (fn:string-length($line)<50) then
                                    xf:pad-string-to-length(string($line),50)
                                else ($line),
                '')
            else $Result 
     }; 

    xf:wrap-test($Text,50,"&#10;",0)

Parameters to pass: 
1. $Text - Text to word wrap
2. 50 -Word wrap string length
3. "&#10;" - After word wrap - new line character
4. 0 - Starting position
声明函数xf:wrap string($str作为xs:string,
$wrap col为xs:integer,
$break标记为xs:string,
$pos作为xs:integer)
as xs:string{
如果(fn:contains($str,,)),那么
让$first word:=fn:substring位于($str,'')之前
现在让$pos:=xs:integer($pos+1+字符串长度($first word))
返回
如果($pos>0和$pos now>=$wrap col),则
康卡特($break mark,
xf:wrap字符串($str,$wrap col,$break mark,xs:integer(0)))
其他的
concat($第一个单词,'',
xf:wrap字符串(在($str,,)之后的子字符串,
$wrap col,
$break mark,
$pos(现在)
否则(
如果($pos+字符串长度($str)>$wrap col),则
concat($break mark,$str)
其他(str)
)
};
声明函数xf:wrap test($str为xs:string,
$wrap col为xs:integer,
$break标记为xs:string,
$pos作为xs:integer)
as xs:string{
let$Result:=xf:wrap字符串($str、$wrap col、$break mark、$pos)
返回
如果(fn:包含($Result,
;')),则
fn:字符串联接(用于标记化($Result,
;')中的$line)
返回

if(fn:字符串长度($line)@奥利弗·哈勒姆:这是一个很好的解决方案,但是,根据数据的不同,它可能会创建一个由一条长线组成的系列,然后是一条很短的第二条线。这不是很美观,是吗?要实现很好的线拆分,最好先用一个空格替换每个NL——在这种情况下,结果将包括几乎相等的长度--大约100行字符,只有最后一行较短。好问题(+1)。请参阅我的答案,了解另一种选择,XSLT 1.0解决方案,该解决方案可能可以转换为XQuery——特别是在XQuery 3.0中,其中可能会有高阶函数,折叠可能是标准函数库的一部分。当然,@Oliver Hallam的解决方案是一个很好的解决方案,并且可以立即使用。它可以稍加修改以生成正如我在对他的回答的评论中提到的,结果看起来更好。你能定义“非专利”吗?我在网上找不到一个定义。
Dec. 13 — As always for a presidential inaugural, security
and surveillance were extremely tight in Washington, DC,
last January. But as George W. Bush prepared to take the
oath of office, security planners installed an extra layer
of protection: a prototype software system to detect a
biological attack. The U.S. Department of Defense, together
with regional health and emergency-planning agencies,
distributed a special patient-query sheet to military
clinics, civilian hospitals and even aid stations along the
parade route and at the inaugural balls. Software quickly
analyzed complaints of seven key symptoms — from rashes to
sore throats — for patterns that might indicate the early
stages of a bio-attack. There was a brief scare: the system
noticed a surge in flulike symptoms at military clinics.
Thankfully, tests confirmed it was just that — the flu.
declare function xf:wrap-string($str as xs:string,
                                $wrap-col as xs:integer,
                                $break-mark as xs:string,
                                $pos as xs:integer)
    as xs:string {
       if(fn:contains( $str, ' ' )) then 
        let $first-word := fn:substring-before( $str, ' ' )
        let $pos-now := xs:integer($pos + 1 + string-length($first-word))
        return
            if ($pos>0 and $pos-now>=$wrap-col) then
                 concat($break-mark,
                 xf:wrap-string($str,$wrap-col,$break-mark,xs:integer(0)))
            else
                concat($first-word,' ',
                 xf:wrap-string(substring-after( $str, ' ' ),
                               $wrap-col,
                               $break-mark,
                               $pos-now))
       else(
        if ($pos+string-length($str)>$wrap-col) then
            concat($break-mark,$str)
        else ($str)
       )
};

    declare function xf:wrap-test($str as xs:string,
                                    $wrap-col as xs:integer,
                                    $break-mark as xs:string,
                                    $pos as xs:integer)
     as xs:string {
            let $Result := xf:wrap-string($str,$wrap-col,$break-mark,$pos)
            return
            if (fn:contains($Result,'&#10;')) then
                fn:string-join(for $line in tokenize($Result, '&#10;')
                                return
                                if (fn:string-length($line)<50) then
                                    xf:pad-string-to-length(string($line),50)
                                else ($line),
                '')
            else $Result 
     }; 

    xf:wrap-test($Text,50,"&#10;",0)

Parameters to pass: 
1. $Text - Text to word wrap
2. 50 -Word wrap string length
3. "&#10;" - After word wrap - new line character
4. 0 - Starting position