Переименовать узлы с помощью XSLT - PullRequest
6 голосов
/ 07 ноября 2008

Я пытаюсь что-то очень простое, но по какой-то причине это не работает. По сути, мне нужно переименовать некоторые узлы в документе XML. Таким образом, я создал XSLT-файл для преобразования.

Вот пример XML:

РЕДАКТИРОВАТЬ: Адреса и элементы адреса встречаются на многих уровнях. Это то, что заставило меня попытаться применить XSLT. Функция типизированных наборов данных Visual Studio, которая создает типизированные наборы данных из файлов XSD, не позволяет иметь вложенные ссылки на одну и ту же таблицу. Таким образом, наличие Бизнес / Бизнес / Адреса и Бизнес / Бизнес / Контакт / Адреса приводит к сбою Load (). Это известная проблема, и все, что они говорят вам, это что-то вроде «Не иметь вложенных ссылок на таблицы ... отредактируйте свой XSD, чтобы прекратить иметь это». К сожалению, это означает, что мы должны применить XSLT, чтобы XML соответствовал «взломанному» XSD, поскольку файлы поступают от стороннего поставщика.

Итак, мы очень близки с помощью, оказанной здесь. Последняя пара вещей такова:

1.) Как я могу использовать ссылку на пространство имен в атрибуте соответствия шаблона xsl:, чтобы указать, что я хочу переименовать Бизнес / Бизнес / Адреса в BusinessAddresses, но переименовать Бизнес / Бизнес / Контакты / Контакт / Адреса связаться с адресами?

2.) Как я могу помешать XSLT загромождать каждый новый элемент явными ссылками на пространство имен? Это вызывает чрезмерное вздутие на выходе.

Я создал пространство имен под названием «steel» и добился большого успеха:

<xsl:template match="steel:Addresses>
  <xsl:element name="BusinessAddresses>
</xsl:template>

Очевидная проблема здесь заключается в том, что он переименовывает ALL элементов Addresses в BusinessAddresses, хотя я хочу, чтобы некоторые из них назывались ContactAddresses и так далее. Бесполезное добавление явных ссылок на пространство имен ко всем переименованным узлам также создает проблемы.

Я пробовал подобные вещи, но как только я добавляю косые черты в атрибут match, это синтаксическая ошибка в XSLT, например:

<xsl:template match="steel:/Businesses/Business/Addresses">

Я чувствую себя очень близко, но мне нужно несколько советов о том, как смешать использование пространства имен и способ использования косой черты для выбора ЛЮБЫХ узлов под определенными путями.

<?xml version="1.0"?>
<Businesses>
  <Business>
    <BusinessName>Steel Stretching</BusinessName>
    <Addresses>
      <Address>
        <City>Pittsburgh</City>
      </Address>
      <Address>
        <City>Philadelphia</City>
      </Address>
    </Addresses>
    <Contacts>
      <Contact>
        <FirstName>Paul</FirstName>
        <LastName>Jones</LastName>
        <Addresses>
          <Address>
            <City>Pittsburgh</City>
          </Address>
        </Addresses>
      </Contact>
    </Contacts>
  </Business>
  <Business>
    <BusinessName>Iron Works</BusinessName>
    <Addresses>
      <Address>
        <City>Harrisburg</City>
      </Address>
      <Address>
        <City>Lancaster</City>
      </Address>
    </Addresses>
  </Business>
</Businesses>

Мне нужно переименовать адреса в BusinessAddresses, и мне нужно переименовать адрес в BusinessAddress для каждого экземпляра адресов и адресов непосредственно в бизнес-узле. Мне также нужно переименовать адреса в ContactAddress, и мне нужно переименовать адрес в ContactAddress, для каждого экземпляра адресов и адресов непосредственно под контактным узлом.

Я пробовал несколько решений, но ни одно из них не работает. Все они в конечном итоге создают тот же XML, что и исходный файл.

Вот пример того, что я пробовал:

  <xsl:template match="/">
    <xsl:apply-templates select="@*|node()" />
  </xsl:template>

  <xsl:template match="@*|*">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Addresses">
    <BusinessAddresses>
      <xsl:apply-templates select="@*|node()" />
    </BusinessAddresses>
  </xsl:template>

Это было опробовано, по крайней мере, в 6 различных вариантах, включая пошаговый отладчик XSLT в VB.Net. Он никогда не выполняет сопоставление шаблона для адресов.

Почему?

Ответы [ 2 ]

10 голосов
/ 07 ноября 2008

Почему XSLT может выйти из строя?

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

В следующем примере добавляется атрибут xmlns:business, который объявляет, что элементы с префиксом business принадлежат пространству имен mynamespace.uri. Затем я использовал этот префикс для определения соответствия шаблонов адресов и адресов. Конечно, вам нужно будет изменить URI пространства имен на тот, который соответствует пространству имен по умолчанию вашего XML-файла.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:business="mynamespace.uri"
                exclude-result-prefixes="msxsl">
  <xsl:template match="/">
    <xsl:apply-templates select="@*|node()"/>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="business:Addresses">
    <xsl:element name="BusinessAddresses">
      <xsl:apply-templates select="@*|node()" />
    </xsl:element>
  </xsl:template>

  <xsl:template match="business:Address">
    <xsl:element name="BusinessAddress">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Как вы сопоставляете шаблоны на основе расположения элемента, а также имени?

Существует несколько способов достижения этой последней части вашей проблемы, BusinessAddress или ContactAddress, но проще всего изменить атрибуты шаблона match для учета родительских узлов. Если вы рассматриваете атрибут match как путь в XML для узла, эта опция становится более понятной (содержимое шаблонов опущено для краткости):

<xsl:template match="business:Business/business:Addresses>
</xsl:template>

<xsl:template match="business:Business/business:Addresses/business:Address">
</xsl:template>

<xsl:template match="business:Contact/business:Addresses">
</xsl:template>

<xsl:template match="business:Contact/business:Addresses/business:Address">
</xsl:template>

Существуют другие методы для достижения этой цели, если match остается основанным только на имени элемента, но их сложнее реализовать, отслеживать и поддерживать, поскольку они включают использование условных проверок в иерархии родительских узлов элемента в процессе обработки, все в шаблоне.

0 голосов
/ 08 ноября 2008

Может быть, если данные, которые вы показываете, действительно похожи на те, с которыми вы работали

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="Businesses">
 <Businesses>
  <xsl:apply-templates/>
 </Businesses>
</xsl:template>

<xsl:template match="*">
 <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="Addresses">
 <BusinessAddresses>
  <xsl:apply-templates/>
 </BusinessAddresses>
</xsl:template>

<xsl:template match="Addresses/Address">
 <BusinessAddress>
  <xsl:value-of select="."/>
 </BusinessAddress>
</xsl:template>

</xsl:stylesheet>      
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...