Как скопировать определенный атрибут с помощью XSLT? - PullRequest
7 голосов
/ 09 мая 2011

Извиняюсь за основную природу этих вопросов - я новичок в XSLT (и в Stack Overflow тоже).

Мне нужно преобразовать следующий XML, возвращаемый веб-службой Sharepoint:

<GetGroupCollectionFromUser xmlns=
   "http://schemas.microsoft.com/sharepoint/soap/directory/">
   <Groups>
      <Group ID="3" Name="Group1" Description="Description" OwnerID="1" 
         OwnerIsUser="False" />
      <Group ID="15" Name="Group2" Description="Description" 
         OwnerID="12" OwnerIsUser="True" />
      <Group ID="16" Name="Group3" Description="Description" 
         OwnerID="7" OwnerIsUser="False" />
   </Groups>
</GetGroupCollectionFromUser>

в это:

<GetGroupCollectionFromUser xmlns=
   "http://schemas.microsoft.com/sharepoint/soap/directory/">
   <Groups>
      <Group Name="Group1" />
      <Group Name="Group2" />
      <Group Name="Group3" />
   </Groups>
</GetGroupCollectionFromUser>

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

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

<xsl:output method="xml" encoding="utf-8" indent="no"/>

<xsl:template match="/GetGroupCollectionFromUser">
    <xsl:copy>                  
        <xsl:apply-templates select="Groups" />
    </xsl:copy>
</xsl:template>

<xsl:template match="Groups">
    <xsl:copy>
        <xsl:apply-templates select="Group" />
    </xsl:copy>
</xsl:template> 

<xsl:template match="Group">
    <xsl:copy>
        <xsl:apply-templates select="@Name" />
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Однако вместо имениПриведенный выше атрибут дает мне значение атрибута Name, вставленного в виде текста в элемент Group, например:

<GetGroupCollectionFromUser>
    <Groups>
        <Group>Group1</Group>
        <Group>Group2</Group>
        <Group>Group3</Group>
    </Groups>
</GetGroupCollectionFromUser>

В конечном итоге это будет использоваться сторонним приложением, которое ожидает XML, ориентированный на атрибуты.Я уверен, что упускаю что-то смущающее очевидное, но независимо от того, что я делаю с этим, я не могу использовать только атрибут Name.Два вопроса:

Как изменить XSLT так, чтобы он возвращал атрибут Name для каждого элемента Group вместо его значения в виде текста?

И как правильно обрабатывать пространство имен?Когда я включил его в XSLT, попробовав несколько методов на основе примеров, которые я нашел здесь и в других местах в Интернете, я ничего не получил обратно.

Заранее благодарим за любые советы.

Ответы [ 4 ]

3 голосов
/ 09 мая 2011

Способ справиться с этими ситуациями - переопределить Identity Transform:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msft="http://schemas.microsoft.com/sharepoint/soap/directory/">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="msft:Group">
        <xsl:copy>
            <xsl:apply-templates select="@Name" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Выход:

<GetGroupCollectionFromUser
    xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
    <Groups>
        <Group Name="Group1" />
        <Group Name="Group2" />
        <Group Name="Group3" />
    </Groups>
</GetGroupCollectionFromUser>

Обратите внимание, что выходные данные правильно распределены по именам.

Это решение является предпочтительным из-за его простоты и гибкости. Все узлы и атрибуты копируются как есть, если только не существует переопределения, которое указывает альтернативное поведение.

2 голосов
/ 10 мая 2011

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

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="@*[not(name()='Name')]"/>
</xsl:stylesheet>

При применении к предоставленному документу XML :

<GetGroupCollectionFromUser xmlns=
"http://schemas.microsoft.com/sharepoint/soap/directory/">
    <Groups>
        <Group ID="3" Name="Group1" Description="Description" OwnerID="1"           OwnerIsUser="False" />
        <Group ID="15" Name="Group2" Description="Description"           OwnerID="12" OwnerIsUser="True" />
        <Group ID="16" Name="Group3" Description="Description"           OwnerID="7" OwnerIsUser="False" />
    </Groups>
</GetGroupCollectionFromUser>

желаемый, правильный результат получен :

<GetGroupCollectionFromUser xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
   <Groups>
      <Group Name="Group1"/>
      <Group Name="Group2"/>
      <Group Name="Group3"/>
   </Groups>
</GetGroupCollectionFromUser>

Пояснение :

  1. Правило идентификации (шаблон) копирует каждый узел "как есть".

  2. Существует только один шаблон, который переопределяет правило идентификации .Он соответствует любому атрибуту, имя которого не является «Имя».Тело шаблона пустое, и в результате любой сопоставленный атрибут не будет скопирован.

Использование и переопределение правила идентификации является наиболее фундаментальным и мощным шаблоном разработки XSLT.Читайте об этом здесь .

2 голосов
/ 09 мая 2011

Я думаю, вам станет легче, если вы не используете xsl:copy здесь.Попробуйте это:

<xsl:template match="Groups/*">
 <xsl:element name="Group">
     <xsl:attribute name="Name">
      <xsl:value-of select="@Name" />
     </xsl:attribute>
 </xsl:element>
</xsl:template>

Ответ на второй вопрос: FAQ .Объявите пространство имен и используйте объявленный префикс в вашем xsl.Окончательное решение:

<xsl:stylesheet version="1.0" 
    xmlns:myns="http://schemas.microsoft.com/sharepoint/soap/director/"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output method="xml" encoding="utf-8" indent="no"/>

 <xsl:template match="/myns:GetGroupCollectionFromUser">
  <Groups>                 
    <xsl:apply-templates select="myns:Groups" />
  </Groups>
 </xsl:template>

 <xsl:template match="myns:Groups/*">
  <xsl:element name="Group">
     <xsl:attribute name="Name">
      <xsl:value-of select="@Name" />
     </xsl:attribute>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>
0 голосов
/ 09 мая 2011

Мне кажется, это работает:

<xsl:template match="Group">
    <xsl:copy>
        <xsl:attribute name="Name">
            <xsl:apply-templates select="@Name" />
        </xsl:attribute>
    </xsl:copy>
</xsl:template>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...