XQuery 中的 URI 相对化

发布于 2024-12-08 02:55:39 字数 255 浏览 0 评论 0原文

如何将一个 URI 与另一个 URI 相对化?

uri1

file:/folder1/file2.txt

uri2

file:/folder1/folder2/file1.txt

需要结果

relativize-method($uri1, $uri2) == '../file2.txt'

How to relativize an URI to another URI?

uri1

file:/folder1/file2.txt

uri2

file:/folder1/folder2/file1.txt

needed result

relativize-method($uri1, $uri2) == '../file2.txt'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

葬花如无物 2024-12-15 02:55:39

类似这样的(将在 XQuery 中重写):

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:my="my:my">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
 <xsl:template match="/*">
     <xsl:sequence select="my:RelativeUrl(url[1], url[2])"/>
 </xsl:template>
 
 <xsl:function name="my:RelativeUrl" as="xs:string">
  <xsl:param name="pUrl" as="xs:string"/>
  <xsl:param name="pBase" as="xs:string"/>
  
  <xsl:variable name="vurlSegments" select="tokenize($pUrl, '/')"/>
  <xsl:variable name="vbaseSegments" select="tokenize($pBase, '/')"/>
  
  <xsl:variable name="vCommonPrefixLength" select=
   "(for $i in 1 to count($vbaseSegments)
      return
        if($vbaseSegments[$i] ne $vurlSegments[$i])
          then $i -1
          else ()
     )[1]
   "/>
   
   <xsl:variable name="vUpSteps" select=
   "count($vbaseSegments) -$vCommonPrefixLength "/>
   
   <xsl:sequence select=
    "string-join
       (
               (
                (for $i in 1 to $vUpSteps
                    return
                      '..'
                  ),
                 (for $k in 1 to count($vurlSegments) - $vCommonPrefixLength 
                   return
                     $vurlSegments[$vCommonPrefixLength + $k]
                  )
                 ),
                  
                  '/'
        )
    "/>
 </xsl:function>
</xsl:stylesheet>

应用于此 XML 文档时

<t>
 <url>file:/folder1/file2.txt</url>
 <url>file:/folder1/folder2/file1.txt</url>
</t>

生成所需的正确结果

../../file2.txt

更新

下面是一个纯XPath 3.0解决方案:

let $pUrl := "file:/folder1/file2.txt",
    $pBase := "file:/folder1/folder2/folder3/file1.txt",
    $urlSegments := tokenize($pUrl, '/'),
    $baseSegments := tokenize($pBase, '/'),
    $idiff := (for $ind in 1 to max((count($urlSegments), count($baseSegments)))
                return $ind[$urlSegments[$ind] ne $baseSegments[$ind]]
             ) [1]
  return
   string-join(
                ((1 to count($baseSegments) - count($urlSegments)) ! '..',
                 $urlSegments[position() ge $idiff])
               , '/')

Something like this (will rewrite it in XQuery):

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:my="my:my">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
 <xsl:template match="/*">
     <xsl:sequence select="my:RelativeUrl(url[1], url[2])"/>
 </xsl:template>
 
 <xsl:function name="my:RelativeUrl" as="xs:string">
  <xsl:param name="pUrl" as="xs:string"/>
  <xsl:param name="pBase" as="xs:string"/>
  
  <xsl:variable name="vurlSegments" select="tokenize($pUrl, '/')"/>
  <xsl:variable name="vbaseSegments" select="tokenize($pBase, '/')"/>
  
  <xsl:variable name="vCommonPrefixLength" select=
   "(for $i in 1 to count($vbaseSegments)
      return
        if($vbaseSegments[$i] ne $vurlSegments[$i])
          then $i -1
          else ()
     )[1]
   "/>
   
   <xsl:variable name="vUpSteps" select=
   "count($vbaseSegments) -$vCommonPrefixLength "/>
   
   <xsl:sequence select=
    "string-join
       (
               (
                (for $i in 1 to $vUpSteps
                    return
                      '..'
                  ),
                 (for $k in 1 to count($vurlSegments) - $vCommonPrefixLength 
                   return
                     $vurlSegments[$vCommonPrefixLength + $k]
                  )
                 ),
                  
                  '/'
        )
    "/>
 </xsl:function>
</xsl:stylesheet>

when applied on this XML document:

<t>
 <url>file:/folder1/file2.txt</url>
 <url>file:/folder1/folder2/file1.txt</url>
</t>

the wanted, correct result is produced:

../../file2.txt

Update:

Below is a pure XPath 3.0 solution:

let $pUrl := "file:/folder1/file2.txt",
    $pBase := "file:/folder1/folder2/folder3/file1.txt",
    $urlSegments := tokenize($pUrl, '/'),
    $baseSegments := tokenize($pBase, '/'),
    $idiff := (for $ind in 1 to max((count($urlSegments), count($baseSegments)))
                return $ind[$urlSegments[$ind] ne $baseSegments[$ind]]
             ) [1]
  return
   string-join(
                ((1 to count($baseSegments) - count($urlSegments)) ! '..',
                 $urlSegments[position() ge $idiff])
               , '/')
心在旅行 2024-12-15 02:55:39

您可以标记化以获取目录,然后使用递归函数来计算所需的结果。类似以下内容(在 try.zorba-xquery.com 上测试):

declare function local:compute-relative-uri($absolute as xs:string,
                                            $current as xs:string)
{
  local:compute-relative-uri-aux(tokenize($absolute, "/"),
                                 tokenize($current, "/"))
};

declare function local:compute-relative-uri-aux($absolute as xs:string*,
                                                $current as xs:string*)
{
  if (head($absolute) eq head($current))
  then
    local:compute-relative-uri-aux(tail($absolute), tail($current))
  else
    let $steps := (for $dir in 1 to count($current) - 1 return "..", $absolute)
    return string-join($steps, "/")
};

let $absolute := "file:/folder1/file2.txt"
let $current := "file:/folder1/folder2/file1.txt"
return
  local:compute-relative-uri($absolute, $current)

You could tokenize to get the directories, and then use a recursive function to compute the desired result. Something like the following (tested on try.zorba-xquery.com):

declare function local:compute-relative-uri($absolute as xs:string,
                                            $current as xs:string)
{
  local:compute-relative-uri-aux(tokenize($absolute, "/"),
                                 tokenize($current, "/"))
};

declare function local:compute-relative-uri-aux($absolute as xs:string*,
                                                $current as xs:string*)
{
  if (head($absolute) eq head($current))
  then
    local:compute-relative-uri-aux(tail($absolute), tail($current))
  else
    let $steps := (for $dir in 1 to count($current) - 1 return "..", $absolute)
    return string-join($steps, "/")
};

let $absolute := "file:/folder1/file2.txt"
let $current := "file:/folder1/folder2/file1.txt"
return
  local:compute-relative-uri($absolute, $current)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文