5

So I want to list all the child nodes with name and text of Specs node.

<Item-Request model="MZ-7TE1T0BW" Supplier-Code="TOMSAM1TB">
    <DisplayItem>
        <Item href="SAM1TBMZ7TE1T0BW.jpg" model="MZ-7TE1T0BW">
            <Name>Samsung SSD MZ-7TE1T0BW 1 TB 2.5 inch</Name>
            <Price>630.99</Price>
            <SupplierCode>TOMSAM1TB</SupplierCode>
            <Description/>
            <Specs>
                <Capacity>1 TB</Capacity>
                <Reading>540 MB/s</Reading>
                <Writing>520 MB/s</Writing>
                <FormFactor>2.5 "</FormFactor>
                <Connecor>Sata III</Connecor>
                <Size>
                    <Width>70 mm</Width>
                    <Height>7 mm</Height>
                </Size>
                <Weight>53 g</Weight>
            </Specs>
            <Supplier>TOM001</Supplier>
            <SupplierName>Tom PC Hardware</SupplierName>
            <Manufacturer>Samsung</Manufacturer>
        </Item>
    </DisplayItem>
</Item-Request>

I cannot do this hard-coded as these are not values that I have readily available and can be added or removed. So I need something that could dynamically list them.

So far what I've been able to do is

<xsl:for-each select="DisplayItem/Item/Specs">
                                <xsl:for-each select="node()">
                                    <xsl:value-of select="."/>
                                    <br/>
                                </xsl:for-each>
                            </xsl:for-each>

The above lists the values on a separate line now I need to be able to display the element name.

Enzero
  • 1,141
  • 2
  • 17
  • 36

3 Answers3

3

The solution that I found for this was

<xsl:for-each select="DisplayItem/Item/Specs">
    <xsl:for-each select="node()">
        <xsl:value-of select="name()"/>
        <xsl:value-of select="."/>
        <br/>
    </xsl:for-each>
</xsl:for-each>

I am unsure if it is the correct way.

Enzero
  • 1,141
  • 2
  • 17
  • 36
2

Instead of cycling through all children you should rather use templates for the Specs elements you find and turn each into text.

I would use the following stylesheet (it seems you want to generate HTML):

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" 
                              xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes"/>  

  <xsl:template match="/">
    <xsl:text disable-output-escaping='yes'>&lt;!DOCTYPE html></xsl:text>
      <html>
      <body>
        <xsl:apply-templates/>
      </body>
      </html>
  </xsl:template>

  <xsl:template match="Specs">
      <xsl:for-each select="*"> <!-- take all descendants of Specs -->
        <p>
          <xsl:value-of select="name()"/>
          <xsl:text> = </xsl:text>

          <!-- this just copies the text() of possible descendants! -->
          <xsl:value-of select="."/> 
        </p>
      </xsl:for-each>
  </xsl:template>

  <!-- do nothing for unmatched text or attribute nodes -->
  <xsl:template match="text()|@*"/>

</xsl:stylesheet>

You will still face a problem with nested Specs like <Size> for example. With this template, the output is (minus some additional whitespace):

<p>Size = 70 mm 7 mm</p>
mwil.me
  • 1,134
  • 1
  • 19
  • 33
0

You can try this too.

XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output indent="yes" />

   <xsl:template match="/">
     <xsl:copy-of select="//Specs"/>
   </xsl:template>
</xsl:stylesheet>

Applied to your input XML will;

Output:

<?xml version="1.0" encoding="UTF-8"?>
<Specs>
   <Capacity>1 TB</Capacity>
   <Reading>540 MB/s</Reading>
   <Writing>520 MB/s</Writing>
   <FormFactor>2.5 "</FormFactor>
   <Connecor>Sata III</Connecor>
   <Size>
      <Width>70 mm</Width>
      <Height>7 mm</Height>
   </Size>
   <Weight>53 g</Weight>
</Specs>
Hash
  • 7,726
  • 9
  • 34
  • 53