перемещение атрибута в дочерний элемент xml с помощью xsl

#xml #xslt

#xml #xslt

Вопрос:

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

У меня есть следующее

 <wrapper>
 <Person ID="1">
  <Person InfoName="bob" Gender="male" />
  <Purchase Reference = "1" Item="book"/>
  <Purchase Reference = "2" Item="shoes"/>
 </Person>
 <Person ID="2">
  <Person InfoName="Jane" Gender="female"/>
  <Purchase Reference = "1" Item="pen"/>
  <Purchase Reference = "2" Item="hat"/>
 </Person>
</wrapper>
 

и мне нужно иметь следующее (я не беспокоюсь о сохранении, поскольку все записи будут иметь идентификатор):

 <wrapper>
 <Person ID="1">
  <Person InfoName="bob" Gender="male" ID = "1"/>
  <Purchase Reference = "1" Item="book" ID="1"/>
  <Purchase Reference = "2" Item="shoes" ID="1"/>
 </Person>
 <Person ID="2">
  <Person InfoName="Jane" Gender="female" ID="2"/>
  <Purchase Reference = "1" Item="pen" ID="2"/>
  <Purchase Reference = "2" Item="hat" ID="2"/>
 </Person>
</wrapper>
 

Я пробовал несколько разных XSLT с разной степенью успеха. Следующее создает новый дочерний узел.

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>

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

   <xsl:template match="*[@ID]">
      <xsl:copy>
         <xsl:apply-templates select="@*[name() != 'ID']" />
         <xsl:element name="{name()}ID">
            <xsl:value-of select="@ID" />
         </xsl:element>
         <xsl:apply-templates select="node()"/>
      </xsl:copy>
   </xsl:template>
 

Комментарии:

1. Ваш ввод не является правильно сформированным XML!

2. Большое вам спасибо за ответ, который ценится …. цель преобразования заключалась в том, чтобы я мог импортировать и XML-файл в access для дальнейшего изучения, с тех пор я использовал XML Spy для этого, и поэтому XSLT больше не требуется…

3. И.Алам, посмотрите решение, в котором добавленный ID атрибут является последним — как и требовалось в вашем вопросе. Два других решения помещают его в качестве первого …

4. В спецификации XML явно указано, что порядок атрибутов не имеет значения. Процессор XSLT может выводить их в любом порядке. Пытаться контролировать порядок с помощью таблицы стилей XSLT бессмысленно; то, что работает с одним процессором, может не работать с другим.

Ответ №1:

(1) Позаботьтесь о допустимом xml. Атрибуты должны быть парой Ключ-значение, например info="a" (значение должно быть в " ). XML чувствителен к регистру.

(2) Ваше решение намного проще:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" indent="yes"/>

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

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

</xsl:stylesheet>
 

Выберите свои элементы для копирования в via wrapper/Person/* и grep атрибут ID родительского via .. .

Комментарии:

1. Большое вам спасибо за ответ, который ценится …. цель преобразования заключалась в том, чтобы я мог импортировать и XML-файл в access для дальнейшего изучения, с тех пор я использовал XML Spy для этого, и поэтому XSLT больше не требуется

Ответ №2:

Попробуйте сделать это так:

XSLT 1.0

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

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

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

</xsl:stylesheet>
 

Применяется к следующему правильно сформированному вводу:

 <Wrapper>
<Person ID ="1">
 <Person Name="bob" Gender="male" />
 <Purchase Reference = "1" Item="book"/>
 <Purchase Reference = "2" Item="shoes"/>
</Person>

<Person ID ="2">
 <Person Name="Jane" Gender="female"/>
 <Purchase Reference = "1" Item="pen"/>
 <Purchase Reference = "2" Item="hat"/>
</Person>
</Wrapper>
 

результатом будет:

 <?xml version="1.0" encoding="UTF-8"?>
<Wrapper>
   <Person ID="1">
      <Person ID="1" Name="bob" Gender="male"/>
      <Purchase ID="1" Reference="1" Item="book"/>
      <Purchase ID="1" Reference="2" Item="shoes"/>
   </Person>
   <Person ID="2">
      <Person ID="2" Name="Jane" Gender="female"/>
      <Purchase ID="2" Reference="1" Item="pen"/>
      <Purchase ID="2" Reference="2" Item="hat"/>
   </Person>
</Wrapper>
 

Ответ №3:

Пока это единственное решение, которое помещает ID атрибут последним — как требуется:

 <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="Person/*">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="../@ID"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
 

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

 <wrapper>
    <Person ID="1">
        <Person InfoName="bob" Gender="male" />
        <Purchase Reference = "1" Item="book"/>
        <Purchase Reference = "2" Item="shoes"/>
    </Person>
    <Person ID="2">
        <Person InfoName="Jane" Gender="female"/>
        <Purchase Reference = "1" Item="pen"/>
        <Purchase Reference = "2" Item="hat"/>
    </Person>
</wrapper>
 

Получен точный (не похожий на результаты других решений) желаемый результат:

 <wrapper>
   <Person ID="1">
      <Person InfoName="bob" Gender="male" ID="1"/>
      <Purchase Reference="1" Item="book" ID="1"/>
      <Purchase Reference="2" Item="shoes" ID="1"/>
   </Person>
   <Person ID="2">
      <Person InfoName="Jane" Gender="female" ID="2"/>
      <Purchase Reference="1" Item="pen" ID="2"/>
      <Purchase Reference="2" Item="hat" ID="2"/>
   </Person>
</wrapper>