开发者

How can I combine child nodes across two or more XML files using XSL?

开发者 https://www.devze.com 2023-03-30 06:27 出处:网络
I am trying to combine XML files using XSL. I\'ve looked on stackoverflow, google, and elsewhere for clues. I\'ve found similar questions or topics, but nothing that exactly matches what I\'m trying t

I am trying to combine XML files using XSL. I've looked on stackoverflow, google, and elsewhere for clues. I've found similar questions or topics, but nothing that exactly matches what I'm trying to do.

I've tried leveraging what I can glean from these sources but I can't seem to quite get the result I'm looking for. So...to S/O for a quick consult!

Here is my current approach:

Input file1.xml

<?xml version="1.0" encoding="UTF-8"?>
<protocol>
  <message_exchanges>
    <message_exchange id="1"/>
    <message_exchange id="2"/>
  </message_exchanges>
  <message_types>
    <message_type id="1"/>
    <message_type id="2"/>
    <message_type id="3"/>
  </message_types>
</protocol>

Input file2.xml

<?xml version="1.0" encoding="UTF-8"?>
<protocol>
  <message_exchanges>
    <message_exchange id="3"/>
    <message_exchange id="4"/>
  </message_exchanges>
  <message_types>
    <message_type id="4"/>
    <message_type id="5"/>
    <message_type id="6"/>
  </message_types>
</protocol>

Input index.xml

<?xml version="1.0" encoding="UTF-8"?>
<index>
  <component>file1.xml</component>
  <component开发者_运维百科>file2.xml</component>
</index>

combine.xsl

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

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

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

<xsl:template match="component">
  <xsl:apply-templates select="document(.)"/>
</xsl:template>

.....help me fix / finish this file

</xsl:stylesheet>

desired_result.xml

<?xml version="1.0" encoding="UTF-8"?>
<protocol>
  <message_exchanges>
    <message_exchange id="1"/>
    <message_exchange id="2"/>
    <message_exchange id="3"/>
    <message_exchange id="4"/>
  </message_exchanges>
  <message_types>
    <message_type id="1"/>
    <message_type id="2"/>
    <message_type id="3"/>
    <message_type id="4"/>
    <message_type id="5"/>
    <message_type id="6"/>
  </message_types>
</protocol>

1,000 bonus points if you can help me add an attribute on the fly:

<message_type id="1" src="file1.xml"/>
<message_type id="4" src="file2.xml"/>

I am loading and applying the XSL file to the XML index file using PHP's XSLTProcessor, so I could load the source file names into the processor as a parameter if that would be useful / easier to achieve adding the src attribute.

Thanks! Let me know if I can clarify anything further.

The most useful link I've found so far and the basis of my current approach


This is a case where template parameters becomes useful. This is the shortest and simplest transform I'm actually able to produce. It handles two or more files.

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

    <xsl:template match="index">
        <protocol>
            <message_exchanges>
                <xsl:apply-templates select="component">
                    <xsl:with-param name="message" select="'message_exchanges'"/>
                </xsl:apply-templates>
            </message_exchanges>
            <message_types>
                <xsl:apply-templates select="component">
                    <xsl:with-param name="message" select="'message_types'"/>
                </xsl:apply-templates>
            </message_types>
        </protocol>
    </xsl:template>

    <xsl:template match="component">
        <xsl:param name="message"/>
        <xsl:apply-templates select="document(.)/*/*[name()=$message]/*">
            <xsl:with-param name="comp" select="."/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="message_type|message_exchange">
        <xsl:param name="comp" select="''"/>
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:attribute name="src">
                <xsl:value-of select="$comp"/>
            </xsl:attribute>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

with output:

<protocol>
   <message_exchanges>
      <message_exchange id="1" src="file1.xml"/>
      <message_exchange id="2" src="file1.xml"/>
      <message_exchange id="3" src="file2.xml"/>
      <message_exchange id="4" src="file2.xml"/>
   </message_exchanges>
   <message_types>
      <message_type id="1" src="file1.xml"/>
      <message_type id="2" src="file1.xml"/>
      <message_type id="3" src="file1.xml"/>
      <message_type id="4" src="file2.xml"/>
      <message_type id="5" src="file2.xml"/>
      <message_type id="6" src="file2.xml"/>
   </message_types>
</protocol>


This transformation:

<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:variable name="vFilename1" select="/*/component[1]"/>
 <xsl:variable name="vFilename2" select="/*/component[2]"/>

 <xsl:template match="index">
  <protocol>
    <xsl:apply-templates select="document($vFilename1)"/>
  </protocol>
 </xsl:template>

 <xsl:template match="message_exchanges|message_types">
  <xsl:copy>
   <xsl:apply-templates/>

   <xsl:apply-templates select=
       "document($vFilename2)/*/*[name()=name(current())]/*">
     <xsl:with-param name="pFilename" select="$vFilename2"/>
   </xsl:apply-templates>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="message_exchanges/* | message_types/*">
  <xsl:param name="pFilename" select="$vFilename1"/>

  <xsl:copy>
   <xsl:copy-of select="@*"/>
   <xsl:attribute name="src">
    <xsl:value-of select="$pFilename"/>
   </xsl:attribute>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<index>
  <component>file1.xml</component>
  <component>file2.xml</component>
</index>

produces the wanted, correct result:

<protocol>
   <message_exchanges>
      <message_exchange id="1" src="file1.xml"/>
      <message_exchange id="2" src="file1.xml"/>
      <message_exchange id="3" src="file2.xml"/>
      <message_exchange id="4" src="file2.xml"/>
   </message_exchanges>
   <message_types>
      <message_type id="1" src="file1.xml"/>
      <message_type id="2" src="file1.xml"/>
      <message_type id="3" src="file1.xml"/>
      <message_type id="4" src="file2.xml"/>
      <message_type id="5" src="file2.xml"/>
      <message_type id="6" src="file2.xml"/>
   </message_types>
</protocol>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号