Код MarkLogic SwitchCase для преобразования XML, удаляющего объявления пространств имен корневых узлов

У меня есть структура 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, но без этого мне понадобится для каждого цикла, который портит другую логику. Я просто хочу, чтобы значения атрибутов тегов 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>


person Amit Gope    schedule 24.06.2018    source источник
comment
Почему это проблема? Несмотря на то, что в другом формате пространства имен, ваш результат выглядит функционально эквивалентным.   -  person Rob S.    schedule 25.06.2018
comment
Само собой, это не проблема, поскольку содержимое остается прежним, но мы хотим сравнить яблоки с яблоками, есть ли способ сделать это, а не преобразовывать xml каким-либо образом? Мы не уверены, что этот подход сломает что-нибудь еще в продукте в долгосрочной перспективе.   -  person Amit Gope    schedule 25.06.2018


Ответы (2)


Не так сложно сохранить объявления пространств имен для элементов, которые они возникли, просто убедитесь, что скопировали их вместе с атрибутами и элементами. Для этого можно использовать $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!

person grtjn    schedule 25.06.2018

Опубликованная вами реализация также является хорошим примером для тестирования вашего другого кода - в целом * код обработки XML не должен зависеть от конкретного стиля объявления для пространств имен, а только от атрибута пространства имен во внутренней модели XDM. Если код ломается только из-за изменений в форматировании, это было бы отличным модульным тестом для внедрения, чтобы найти и исправить такой код.

** Конечно, есть причины, по которым код явно зависит от различий в объявлении формата или пространства имен, например, код, который будет реализовывать вышеуказанный модульный тест - ему потребуется явно контролировать форматы результатов, а также обнаруживать семантически идентичные различия форматов, взаимодействуя с внешними службами или, что особенно утомительно, извлечение подузлов из XML и сохранение желаемых (и только желаемых) пространств имен, оптимизации текстовой сериализации и т. д., или -

<expletive deleted>

- создание XHTML.

person DALDEI    schedule 05.09.2019