Как исключить некоторые пространства имен из XML-файла при преобразовании

Я новичок в XSL/XML, и мне нужна помощь с преобразованием XSL. В моей задаче мне нужно преобразовать файл UBL в PUF.

Например, у меня есть этот XML:

<?xml version = "1.0" encoding = "UTF-8"?>
<Invoice xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
    xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
    xmlns:cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
   <cbc:ID>TOSL108</cbc:ID>
   <cbc:IssueDate>2011-09-22</cbc:IssueDate>
   <cac:InvoicePeriod>
      <cbc:StartDate>2011-08-01</cbc:StartDate>
      <cbc:EndDate>2011-08-31</cbc:EndDate>
   </cac:InvoicePeriod>
   <cac:AccountingSupplierParty>
      <cac:Party>
         <cac:PartyName>
            <cbc:Name>Custom Cotter Pins</cbc:Name>
         </cac:PartyName>
      </cac:Party>
   </cac:AccountingSupplierParty>
   <cac:AccountingCustomerParty>
      <cac:Party>
         <cac:PartyName>
            <cbc:Name>North American Veeblefetzer</cbc:Name>
         </cac:PartyName>
      </cac:Party>
   </cac:AccountingCustomerParty>
   <cac:LegalMonetaryTotal>
      <cbc:PayableAmount currencyID = "CAD">100.00</cbc:PayableAmount>
   </cac:LegalMonetaryTotal>
   <cac:InvoiceLine>
      <cbc:ID>1</cbc:ID>
      <cbc:LineExtensionAmount currencyID = "CAD">100.00</cbc:LineExtensionAmount>
      <cac:Item>
         <cbc:Description>Cotter pin, MIL-SPEC</cbc:Description>
      </cac:Item>
   </cac:InvoiceLine>
</Invoice>

И мне нужно создать файл с некоторыми пространствами имен pagero в корневом элементе. Мой ожидаемый результат:

<Invoice xmlns = "urn:pagero:PageroUniversalFormat:Invoice:1.0"
    xmlns:cac = "urn:pagero:CommonAggregateComponents:1.0"
    xmlns:cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
    xmlns:puf = "urn:pagero:ExtensionComponent:1.0"
    xmlns:ext = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
    <cbc:CustomizationID>urn:pagero.com:puf:billing:2.0</cbc:CustomizationID>
    <cbc:ProfileID>urn:pagero.com:puf:billing:1.0</cbc:ProfileID>
    <cbc:ID>TOSL108</cbc:ID>
    <cbc:IssueDate>2011-09-22</cbc:IssueDate>
    <cac:InvoicePeriod>
        <cbc:StartDate>2011-08-01</cbc:StartDate>
        <cbc:EndDate>2011-08-31</cbc:EndDate>
    </cac:InvoicePeriod>
    <cac:AccountingSupplierParty>
        <cac:Party>
            <cac:PartyName>
                <cbc:Name>Custom Cotter Pins</cbc:Name>
            </cac:PartyName>
        </cac:Party>
    </cac:AccountingSupplierParty>
    <cac:AccountingCustomerParty>
        <cac:Party>
            <cac:PartyName>
                <cbc:Name>North American Veeblefetzer</cbc:Name>
            </cac:PartyName>
        </cac:Party>
    </cac:AccountingCustomerParty>
    <cac:LegalMonetaryTotal>
        <cbc:PayableAmount currencyID = "CAD">100.00</cbc:PayableAmount>
    </cac:LegalMonetaryTotal>
    <cac:InvoiceLine>
        <cbc:ID>1</cbc:ID>
        <cbc:LineExtensionAmount currencyID = "CAD">100.00</cbc:LineExtensionAmount>
        <cac:Item>
            <cbc:Description>Cotter pin, MIL-SPEC</cbc:Description>
        </cac:Item>
    </cac:InvoiceLine>
</Invoice>

Для этого я использую шаблон XSL, такой как UBLtoPUF.xsl. Проблема в том, что результирующий файл выглядит так:

<Invoice xmlns = "urn:pagero:PageroUniversalFormat:Invoice:1.0"
    xmlns:cac = "urn:pagero:CommonAggregateComponents:1.0"
    xmlns:cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
    xmlns:puf = "urn:pagero:ExtensionComponent:1.0"
    xmlns:ext = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
    <cbc:CustomizationID>urn:pagero.com:puf:billing:2.0</cbc:CustomizationID>
    <cbc:ProfileID>urn:pagero.com:puf:billing:1.0</cbc:ProfileID>
    <cbc:ID xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
        xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">TOSL108</cbc:ID>
    <cbc:IssueDate xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
        xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
        2011-09-22</cbc:IssueDate>
    <cac:InvoicePeriod
        xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
        xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
        <cbc:StartDate>2011-08-01</cbc:StartDate>
        <cbc:EndDate>2011-08-31</cbc:EndDate>
    </cac:InvoicePeriod>
    <cac:AccountingSupplierParty
        xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
        xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
        <cac:Party>
            <cac:PartyName>
                <cbc:Name>Custom Cotter Pins</cbc:Name>
            </cac:PartyName>
        </cac:Party>
    </cac:AccountingSupplierParty>
    <cac:AccountingCustomerParty
        xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
        xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
        <cac:Party>
            <cac:PartyName>
                <cbc:Name>North American Veeblefetzer</cbc:Name>
            </cac:PartyName>
        </cac:Party>
    </cac:AccountingCustomerParty>
    <cac:LegalMonetaryTotal
        xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
        xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
        <cbc:PayableAmount currencyID = "CAD">100.00</cbc:PayableAmount>
    </cac:LegalMonetaryTotal>
    <cac:InvoiceLine
        xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
        xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
        <cbc:ID>1</cbc:ID>
        <cbc:LineExtensionAmount currencyID = "CAD">100.00</cbc:LineExtensionAmount>
        <cac:Item>
            <cbc:Description>Cotter pin, MIL-SPEC</cbc:Description>
        </cac:Item>
    </cac:InvoiceLine>
</Invoice>

На xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" дочерних узлах появились <Invoice> пространства имен. Эти пространства имен распространяются ТОЛЬКО через прямые /Invoice дочерние узлы, но не через другие дочерние узлы и т. д. Так что я делаю все правильно (как-то) на всех детях детей и т. д., но НЕ на прямых детях /Invoice.

Есть шаблон, который я использую:

<?xml version = "1.0" encoding = "utf-8"?>
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
    xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
    xmlns:cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
    xmlns:puf = "urn:pagero:ExtensionComponent:1.0"
    xmlns:ext = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"
    xmlns = "urn:pagero:PageroUniversalFormat:Invoice:1.0">

    <xsl:output method = "xml" indent = "yes" />

    <xsl:template match = "/">
        <Invoice xmlns:cac = "urn:pagero:CommonAggregateComponents:1.0"
            xmlns:cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
            xmlns:puf = "urn:pagero:ExtensionComponent:1.0"
            xmlns:ext = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
            <cbc:CustomizationID>urn:pagero.com:puf:billing:2.0</cbc:CustomizationID>
            <cbc:ProfileID>urn:pagero.com:puf:billing:1.0</cbc:ProfileID>
            <xsl:apply-templates
                select = "//*[local-name() = 'Invoice']/*[not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2')]" />
        </Invoice>
    </xsl:template>

    <xsl:template
        match = "//*[local-name() = 'Invoice']/*[namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2']">
        <xsl:element name = "{name()}" namespace = "">
            <xsl:apply-templates
                select = "node()/*[not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2')]" />
        </xsl:element>
    </xsl:template>

    <!-- Suppress the UBLVersionID element -->
    <xsl:template match = "//*[local-name() = 'UBLVersionID']" />

    <!-- Copy attributes as-is, except for the namespace attributes -->
    <xsl:template
        match = "@*[not(namespace-uri() = 'http://www.w3.org/2001/XMLSchema-instance')]
                       [not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2')]
                       [not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2')]
                       [not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2')]
                       [not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2')]">
        <xsl:copy />
    </xsl:template>

    <!-- Copy elements as-is -->
    <xsl:template match = "node()">
        <xsl:copy>
            <xsl:apply-templates
                select = "@*[not(namespace-uri() = 'http://www.w3.org/2001/XMLSchema-instance')]
                       [not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2')]
                       [not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2')]
                       [not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2')]
                       [not(namespace-uri() = 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2')]" />
            <xsl:apply-templates
                select = "node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Пробовал менять <xsl:template match = "node()"> но не помогает. Я не нашел вопросов, как исключить пространства имен с помощью шаблона. Пожалуйста, помогите мне, как я могу изменить свой шаблон, чтобы избавиться от этих пространств имен <Invoice> дочерних элементов?

Пожалуйста, отредактируйте свой вопрос и добавьте точный ожидаемый результат.

michael.hor257k 26.04.2023 10:47

Также я не вижу элемента UBLVersionID во входных данных?

michael.hor257k 26.04.2023 11:01

@ michael.hor257k michael.hor257k Я редактировал, ожидаемый результат - второй блок xml.

KillLaKill 26.04.2023 11:06
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

AFAICT, вы хотите сделать просто:

XSLT 1.0

<xsl:stylesheet version = "1.0" 
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:cac = "urn:pagero:CommonAggregateComponents:1.0"
xmlns:cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:puf = "urn:pagero:ExtensionComponent:1.0"
xmlns:ext = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"
           
xmlns:inv = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac0 = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
exclude-result-prefixes = "inv cac0">
<xsl:output method = "xml" version = "1.0" encoding = "UTF-8" indent = "yes"/>
<xsl:strip-space elements = "*"/>

<xsl:template match = "*"> 
    <xsl:element name = "{name()}">
        <xsl:copy-of select = "@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template> 

<xsl:template match = "/inv:Invoice"> 
    <Invoice xmlns = "urn:pagero:PageroUniversalFormat:Invoice:1.0">
        <xsl:apply-templates/>
    </Invoice>
</xsl:template>  

<xsl:template match = "cac0:*"> 
    <xsl:element name = "cac:{local-name()}">
        <xsl:copy-of select = "@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template> 

</xsl:stylesheet>

Я пропустил эту часть:

   <!-- Suppress the UBLVersionID element -->
    <xsl:template match = "//*[local-name() = 'UBLVersionID']" />

потому что я не вижу элемента UBLVersionID во входных данных. Плохая практика — полагаться исключительно на локальное имя элемента — esp. в XML с большим пространством имен, таком как ваш ввод. Вы должны использовать полное имя.

Вам необходимо понять правила для пространств имен для сконструированных элементов.

Во-первых, помните, что модель данных полностью посвящена пространствам имен в области видимости, а не объявлениям пространств имен. Элемент имеет набор привязок пространства имен (сопоставления префикса и uri), которые находятся в области действия этого элемента; не имеет значения, было ли пространство имен объявлено для этого элемента или для какого-либо предка. Таким образом, избыточное объявление пространства имен в элементе Invoice таблицы стилей, когда оно уже объявлено в элементе xsl:stylesheet, бессмысленно.

Когда придет время сериализовать результирующее дерево, сериализатор сгенерирует объявления пространств имен, чтобы были объявлены все пространства имен в области видимости (и только пространства имен в области видимости) для элементов результирующего дерева, устраняя избыточные объявления.

Существует три способа создания элементов, и у них есть разные правила того, какие привязки пространства имен в области видимости будут присутствовать в новом элементе:

  • Буквальный элемент результата (например, <Invoice>) копирует все привязки пространств имен в области видимости из таблицы стилей в дерево результатов, кроме тех, которые исключены в силу exclude-result-prefixes. Он также добавляет любые пространства имен, которые могут понадобиться для имен атрибутов элемента.

  • Инструкция xsl:element создает новый элемент с минимальным набором пространств имен в области видимости, необходимых для имен элемента и его атрибутов.

  • Инструкция xsl:copy или xsl:copy-of копирует привязки пространства имен в области действия из исходного элемента, который вы копируете.

Итак, если вы посмотрите на пространства имен, которые вы получаете для элемента cbc:ID в вашем результирующем документе (например), мне кажется, что этот элемент был создан с использованием инструкции xsl:copy, поэтому вам нужно понимать, что xsl:copy копирует пространства имен в области видимости. копируемого элемента исходного дерева.

В XSLT 2.0 есть атрибут <xsl:copy copy-namespaces = "no">, но в 1.0, если вы хотите отказаться от привязки пространств имен, вам нужно переключиться с xsl:copy на xsl:element.

Спасибо за пояснение, теперь мне стало понятнее!

KillLaKill 26.04.2023 12:54

Другие вопросы по теме