Получить фрагмент XML и снова отобразить его как XML - PullRequest
2 голосов
/ 21 марта 2019

Ищу возможность извлечь часть из XML-файла.Файл загружается в программу по имени, текст может отличаться, но структура и узел останутся прежними.XML выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<n0:Content>
    <n1:Subnode1>
        <n1:Subnode2>
            <n1:Subnode3>
                <n1:Subnode4 xml:lang="en">
                        <head></head>
                        <body>
                            <p style="texttext">
                                <b>Text (EN)</b>
                            </p>
                        </body>
                </n1:Subnode4>
                <n1:Subnode4 xml:lang="it">
                        <head></head>
                        <body>
                            <p style="texttext">
                                <b>Text (IT)</b>
                            </p>
                        </body>
                </n1:Subnode4>
                <n1:Subnode4 xml:lang="fr">
                        <head></head>
                        <body>
                            <p style="texttext">
                                <b>Text (FR)</b>
                            </p>
                        </body>
                </n1:Subnode4>
            </n1:Subnode3>
        </n1:Subnode2>
    </n1:Subnode1>
</n0:Content>

Это структура XML, которая загружается в отчет.Я хочу извлечь с помощью lang = "" и отобразить только ту часть с заголовком <?xml version="1.0" encoding="UTF-8"?> как XML.Таким образом, результат должен выглядеть следующим образом после того, как я решил, например, "en":

<?xml version="1.0" encoding="UTF-8"?>
            <n1:Subnode4 xml:lang="en">
                    <head></head>
                    <body>
                        <p style="texttext">
                            <b>Text (EN)</b>
                        </p>
                    </body>
            </n1:Subnode4>

Я уже некоторое время пытался найти что-то полезное, поэтому я был бы очень благодарен за некоторые вводные данные.Спасибо.

Ответы [ 2 ]

2 голосов
/ 21 марта 2019

1.Проверьте XML

Сделайте ваш XML действительным.вот один из вариантов:

<?xml version="1.0" encoding="UTF-8"?>
<n0:Content xmlns:n0="http://www.yourspace.com/n0" xmlns:n1="http://www.yourspace.com/n1" xmlns:n2="http://www.yourspace.com/n1">
    <n1:Subnode1>
        <n1:Subnode2>
            <n1:Subnode3>
                <n1:Subnode4 xml:lang="en">
                        <head></head>
                        <body>
                            <p style="texttext">
                                <b>Text (EN)</b>
                            </p>
                        </body>
                </n1:Subnode4>
                <n1:Subnode4 xml:lang="it">
                        <head></head>
                        <body>
                            <p style="texttext">
                                <b>Text (IT)</b>
                            </p>
                        </body>
                </n1:Subnode4>
                <n1:Subnode4 xml:lang="fr">
                        <head></head>
                        <body>
                            <p style="texttext">
                                <b>Text (FR)</b>
                            </p>
                        </body>
                </n1:Subnode4>
            </n1:Subnode3>
        </n1:Subnode2>
    </n1:Subnode1>
</n0:Content>

Повторите то же самое для результата (назначения) XML.

XSD Generation

Генерируйте XSD из него (используя такие инструменты, как this ).Возможный результат:

<?xml version="1.0" encoding="UTF-8"?>
   <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
         <!-- XML Schema Generated from XML Document on Thu Mar 21 2019 16:04:11 GMT+0200 (Israel Standard Time) -->
         <!-- with XmlGrid.net Free Online Service http://xmlgrid.net -->
         <xs:element name="n0:Content">
               <xs:complexType>
                     <xs:sequence>
                           <xs:element name="n1:Subnode1">
                                 <xs:complexType>
                                       <xs:sequence>
                                             <xs:element name="n1:Subnode2">
                                                   <xs:complexType>
                                                         <xs:sequence>
                                                               <xs:element name="n1:Subnode3">
                                                                     <xs:complexType>
                                                                           <xs:sequence>
                                                                                 <xs:element name="n1:Subnode4" maxOccurs="unbounded">
                                                                                       <xs:complexType>
                                                                                             <xs:sequence>
                                                                                                   <xs:element name="head"></xs:element>
                                                                                                   <xs:element name="body">
                                                                                                         <xs:complexType>
                                                                                                               <xs:sequence>
                                                                                                                     <xs:element name="p">
                                                                                                                           <xs:complexType>
                                                                                                                                 <xs:sequence>
                                                                                                                                       <xs:element name="b" type="xs:string"></xs:element>
                                                                                                                                 </xs:sequence>
                                                                                                                                 <xs:attribute name="style" type="xs:string"></xs:attribute>
                                                                                                                           </xs:complexType>
                                                                                                                     </xs:element>
                                                                                                               </xs:sequence>
                                                                                                         </xs:complexType>
                                                                                                   </xs:element>
                                                                                             </xs:sequence>
                                                                                             <xs:attribute name="xml:lang" type="xs:string"></xs:attribute>
                                                                                       </xs:complexType>
                                                                                 </xs:element>
                                                                           </xs:sequence>
                                                                     </xs:complexType>
                                                               </xs:element>
                                                         </xs:sequence>
                                                   </xs:complexType>
                                             </xs:element>
                                       </xs:sequence>
                                 </xs:complexType>
                           </xs:element>
                     </xs:sequence>
                     <xs:attribute name="xmlns:n0" type="xs:string"></xs:attribute>
                     <xs:attribute name="xmlns:n1" type="xs:string"></xs:attribute>
                     <xs:attribute name="xmlns:n2" type="xs:string"></xs:attribute>
               </xs:complexType>
         </xs:element>
   </xs:schema>

Сохраните результаты в файле XSD, скажем texts_source.xsd.

Повторите то же самое для XML результата (назначения).

Сохраните результаты в файле XSD, скажем, en_text_destination.xsd.

Прокси-объект для создания словаря данных

Сгенерируйте прокси-объект и данныетолковый словарь.Я делаю это с помощью программы SPROX_XSD2PROXY (если это делается часто, вы можете заключить ее в транзакцию в SE93, я назвал ее ZXSD_GEN).Параметры:

  1. Полный путь к указанному файлу XSD, скажем d:\schemas\texts.xsd.
  2. Пакет, который соответствует префиксу (zsomthing или /something/).
  3. Префикс zsomthing_anothersomthing или /something/anothersomthing
  4. Установите флажок активации

Повторите то же самое для результата (пункт назначения) XSD.

Программа

Вы можете реализовать ее с помощью класса с четырьмя методами:

  1. READ
  2. TRANSFORM
  3. WRITE
  4. ВЫПОЛНИТЬ

ЧИТАТЬ

Получить данные XML из любого места, а затем вернуть их как XSTRING.

TRANSFORM

DATA: ls_source, ls_dest.  "a data of the root structure type of source XML

Вызов метода CL_PROXY_XML_TRANSFORM=>XML_XSTRING_TO_ABAP.

Параметры:

DDIC_TYPE - имя корневой структуры источника, сгенерированного в Прокси-объект, секция словаря данных раздел.XML - чтение данных XML.ABAP_DATA - ls_source th

Выполните необходимые манипуляции, заполнив целевую корневую структуру.

Вызов CL_PROXY_XML_TRANSFORM=>ABAP_TO_XML_XSTRING Метод

Параметры:

ABAP_DATA - ls_dest

DDIC_TYPE - имя корневой структуры места назначения, которое вы генерируете в Прокси-объект, секция словаря данных section.

return XML результаты (XSTRING)

НАПИСАТЬ

Сохранить данные XML в любом месте.

ВЫПОЛНИТЬ

Позвоните READ, затем передайте его результаты TRANSFORM, затем передайте его WRITE.

1 голос
/ 23 марта 2019

Вот решение исключительно с iXML (что довольно сложно по сравнению с использованием преобразования XSLT, как сказал Джаггер).

iXML может обрабатывать узлы с пространствами имен, только если они объявлены (xmlns: prefix = "URI").

iXML выдает ошибку, как только изменение дерева DOM приводит к тому, что префикс пространства имен не объявляется (или не используется вне области его объявления).

Итак, ваш XML должен иметь следующие объявления пространств имен, чтобы он был действительным XML (как сказал Dorad) и мог быть проанализирован iXML, и обратите внимание, что xmlns:n1=... также можно перемещать внутри <n1:Subnode1>:

<?xml ...?>
<n0:Content xmlns:n0="http://www.yourspace.com/n0" xmlns:n1="http://www.yourspace.com/n1">
  <n1:Subnode1>
    ...
</n0:Content>

Результат также должен иметь это минимальное объявление пространства имен:

<?xml ...?>
<n1:Subnode4 xmlns:n1="http://www.yourspace.com/n1" xml:lang="en">
    ...
</n1:Subnode4>

Кстати, вы не сказали, может ли быть несколько узлов с xml:lang="en". Я предполагаю, что ответ НЕТ, или должен быть выбран только первый соответствующий узел.

Код:

DATA(xmlstr) = `<?xml version="1.0" encoding="utf-8"?>`
&& `<n0:Content xmlns:n0="http://n0" xmlns:n1="http://n1">`
&& `  <n1:Subnode1>`
&& `    <n1:Subnode4 xml:lang="en"><p style="texttext"><b>Text (EN)</b></p></n1:Subnode4>`
&& `    <n1:Subnode4 xml:lang="it"><p style="texttext"><b>Text (IT)</b></p></n1:Subnode4>`
&& `    <n1:Subnode4 xml:lang="fr"><p style="texttext"><b>Text (FR)</b></p></n1:Subnode4>`
&& `  </n1:Subnode1>`
&& `</n0:Content>`.

DATA lo_document TYPE REF TO if_ixml_document.
CALL FUNCTION 'SDIXML_XML_TO_DOM'
  EXPORTING xml      = cl_proxy_service=>cstring2xstring( xmlstr )
  IMPORTING document = lo_document.

DATA(lo_element) = CAST if_ixml_element( lo_document->create_iterator_filtered(
                   lo_document->create_filter_attribute_ns( name = 'lang'
                   value = 'en' uri = 'xml' ) )->get_next( ) ).
DATA(lo_xmlns) = lo_element->get_namespace_context( ).
DATA(i) = 1.
WHILE i <= lo_xmlns->num_bindings( ) AND lo_xmlns->get_binding_prefix( i ) IS NOT INITIAL.
  lo_element->set_attribute_ns( prefix = 'xmlns'
        name = lo_xmlns->get_binding_prefix( i ) value = lo_xmlns->get_binding_uri( i ) ).
  i = i + 1.
ENDWHILE.

DATA(lo_new_document) = cl_ixml=>create( )->create_document( ).
lo_new_document->set_version( lo_document->get_version( ) ).
lo_new_document->set_encoding( lo_document->get_encoding( ) ).

DATA(lo_fragment) = lo_new_document->create_document_fragment( ).
lo_fragment->append_child( lo_element ).
lo_new_document->append_child( lo_fragment ).

DATA(lo_doc) = NEW cl_xml_document( ). lo_doc->create_with_dom( lo_new_document ).
lo_doc->display( ).

Результат:

enter image description here

Примечания к коду:

  • Существует метод get_namespace_context, но ничего не предназначено для «установки контекста пространства имен», поэтому метод set_attribute_ns используется для установки атрибутов xmlns.
  • Чтобы упростить код, я установил все атрибуты xmlns непосредственно в исходном элементе вместо первого клонирования; Я должен был лучше сделать DATA(lo_new_element) = lo_element->clone( ) и затем изменить только lo_new_element.
  • iXML не обрабатывает заголовок XML как узел iXML, существуют специальные методы для его инициализации, поэтому я моделирую копию методами set_version, set_encoding, ...
  • Я использовал фиктивный узел типа if_ixml_document_fragment, поскольку корнем нового документа может быть только узел, созданный из самого этого документа, т. Е. Невозможно установить lo_element (из исходного документа) в качестве корня новый документ.
  • Чтобы упростить демонстрацию, я не обработал ошибки.
...