【问题标题】:MarkLogic SwitchCase code for XML transformation removing root node namespace declarations用于 XML 转换的 MarkLogic SwitchCase 代码删除根节点命名空间声明
【发布时间】:2018-06-24 03:32:09
【问题描述】:

我的 XML 结构如下所示(示例 XML)。我想更改 img 标签值并将它们更改为相对路径。每个 XML 文档可以包含 100 多个 img 标签。我的代码在大部分情况下都有效,除了我在根节点中的命名空间声明被添加到引用命名空间的各个节点中,我不希望这种情况发生。

示例 XML:

    <?xml version="1.0" encoding="UTF-8"?>
<test:document transformVersion="0.0.25" xmlns:test="test.data" xmlns:csp="test.csp" xmlns:cfg="test.cfg">
    <data>
        <table>
            <tr>
                <td>
                    <p class="DataboxTitle">Test Image</p>
                </td>
                <td>
                    <p>
                        <img src="https://www.google.com/images/document/1234.jpg" data-stl="height:107px;width:223px;" srcset="https://www.google.com/images/document/1234.jpg 320w" data-image-title="Test Image"/>
                    </p>
                </td>
            </tr>
        </table>
        <table>
            <tr>
                <td>
                    <p class="DataboxTitle">Test Image</p>
                </td>
                <td>
                    <p>
                        <img src="https://www.google.com/images/document/1234.jpg" data-stl="height:107px;width:223px;" srcset="https://www.google.com/images/document/1234.jpg 320w" data-image-title="Test Image"/>
                    </p>
                </td>
            </tr>
        </table>
        <table>
            <tr>
                <td>
                    <p class="DataboxTitle">Test Image</p>
                </td>
                <td>
                    <p>
                        <img src="https://www.google.com/images/document/1234.jpg" data-stl="height:107px;width:223px;" srcset="https://www.google.com/images/document/1234.jpg 320w" data-image-title="Test Image"/>
                    </p>
                </td>
            </tr>
        </table>
        <p>
            <img src="https://www.google.com/images/document/1234.jpg" data-stl="height:107px;width:223px;" srcset="https://www.google.com/images/document/1234.jpg 320w" data-image-title="Test Image"/>
        </p>
    </data>
    <test:volumes>
        <test:test>test</test:test>
    </test:volumes>
    <csp:volumes>tested</csp:volumes>
</test:document>

在下面的 SwitchCase 代码中,我知道命名空间是由于 $doc 变量声明中的代码“/*”而被单独添加的,但如果没有这个,我将需要一个 for each 循环,这会破坏其他逻辑。我只想改变img标签属性值而不改变输出xml中的任何其他内容,请提出出路。

XQUERY 代码:

xquery version "1.0-ml";
declare variable $doc := fn:doc("/c/temp/test.xml")/*;
declare variable $docId := '1928862612025434112';

declare function local:createTag($docId,$imagePath)
{
let $srcOld := fn:data($imagePath/@src)
let $imageName := fn:tokenize($srcOld,"/")[fn:last()]
return fn:concat("/",$docId,"/media/",$imageName)
};

declare function local:createSrcSetTag($docId,$imagePath)
{
let $srcSetsOld := fn:data($imagePath/@srcset)
for $srcSet in fn:tokenize($srcSetsOld, ",")
let $imageLength := fn:tokenize($srcSet," ")[fn:last()]
let $imageName := fn:tokenize($srcSet,"/")[fn:last()]
let $imageNewPath := fn:concat("/",$docId,"/media/",$imageName)
return fn:concat($imageNewPath,"," )
};

declare function local:change($node as node()*) as node()*
{
  typeswitch($node)
  case element(img) return
    element { xs:QName(fn:local-name($node)) } 
    {
    let $image := $node
    let $path := xdmp:path($image)
    let $data-stl := fn:data($image/@data-stl)
    let $data-image-title := fn:data($image/@data-image-title)
    let $srcOld := fn:data($image/@src)
    let $srcSetsOld := fn:data($image/@srcset)
    let $srcNew := local:createTag($docId,$image) 
    let $srcSetsNew := local:createSrcSetTag($docId,$image) 
    return (attribute {'src'}{$srcNew}, attribute {'data-stl'}{$data-stl},attribute {'srcset'}{$srcSetsNew}, attribute {'data-image-title'}{$data-image-title} )
    }  
  case element() return 
    element {fn:node-name($node) } {
      $node/@*,
      $node/node() ! local:change(.)
    }   
  default return $node
};
 local:change(($doc))  

这是我转换后的输出:

<test:document transformVersion="0.0.25" xmlns:test="test.data">
<data>
    <table>
        <tr>
            <td>
                <p class="DataboxTitle">Test Image</p>
            </td>
            <td>
                <p>
                    <img src="/1928862612025434112/media/1234.jpg" data-stl="height:107px;width:223px;" srcset="/1928862612025434112/media/1234.jpg 320w," data-image-title="Test Image"/>
                </p>
            </td>
        </tr>
    </table>
    <table>
        <tr>
            <td>
                <p class="DataboxTitle">Test Image</p>
            </td>
            <td>
                <p>
                    <img src="/1928862612025434112/media/1234.jpg" data-stl="height:107px;width:223px;" srcset="/1928862612025434112/media/1234.jpg 320w," data-image-title="Test Image"/>
                </p>
            </td>
        </tr>
    </table>
    <table>
        <tr>
            <td>
                <p class="DataboxTitle">Test Image</p>
            </td>
            <td>
                <p>
                    <img src="/1928862612025434112/media/1234.jpg" data-stl="height:107px;width:223px;" srcset="/1928862612025434112/media/1234.jpg 320w," data-image-title="Test Image"/>
                </p>
            </td>
        </tr>
    </table>
    <p>
        <img src="/1928862612025434112/media/1234.jpg" data-stl="height:107px;width:223px;" srcset="/1928862612025434112/media/1234.jpg 320w," data-image-title="Test Image"/>
    </p>
</data>
<test:volumes>
    <test:test>test</test:test>
</test:volumes>
<csp:volumes xmlns:csp="test.csp">tested</csp:volumes>

【问题讨论】:

  • 为什么会出现这个问题?尽管名称空间格式不同,但您的输出在功能上似乎是等效的。
  • 这不是问题,因为内容保持不变,但我们想将苹果与苹果进行比较,有没有办法做到这一点而不以任何方式转换 xml?从长远来看,我们不确定这种方法是否会破坏其他产品。

标签: marklogic marklogic-9


【解决方案1】:

将命名空间声明保留在它们出现的元素上并不难,只需确保将它们与属性和元素一起复制。为此,您可以使用$node/namespace::*

declare function local:change($node as node()*) as node()*
{
  typeswitch($node)
  case element(img) return
    element { xs:QName(fn:local-name($node)) } 
    {
    let $image := $node
    let $path := xdmp:path($image)
    let $data-stl := fn:data($image/@data-stl)
    let $data-image-title := fn:data($image/@data-image-title)
    let $srcOld := fn:data($image/@src)
    let $srcSetsOld := fn:data($image/@srcset)
    let $srcNew := local:createTag($docId,$image) 
    let $srcSetsNew := local:createSrcSetTag($docId,$image) 
    return (attribute {'src'}{$srcNew}, attribute {'data-stl'}{$data-stl},attribute {'srcset'}{$srcSetsNew}, attribute {'data-image-title'}{$data-image-title} )
    }  
  case element() return 
    element {fn:node-name($node) } {
      $node/namespace::*,
      $node/@*,
      $node/node() ! local:change(.)
    }   
  default return $node
};

HTH!

【讨论】:

    【解决方案2】:

    您发布的实现也是测试您的其他代码的一个很好的示例 - 通常* XML 处理代码不应依赖于命名空间的特定声明样式,而应仅依赖于内部 XDM 模型中的命名空间属性。如果仅由于格式更改而导致代码中断,那将是一个很好的注入单元测试以查找和修复此类代码。

    ** 当然,代码显式依赖格式或命名空间声明差异是有原因的,例如实现上述单元测试的代码——它需要显式控制结果格式以及检测语义上相同的格式差异,与外部服务交互,或者特别乏味,从 XML 中提取子节点并保留所需的(并且仅是所需的)命名空间、文本序列化优化等,或者 --

    &lt;expletive deleted&gt;

    -- 生成 XHTML。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-30
      • 2019-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多