2008-11-12 10 views
12

que tienen un documento XML algo así como :::¿Cómo 'seleccionar' desde XML con espacios de nombres?

<?xml version="1.0" encoding="utf-8"?> 
<?mso-application progid="Excel.Sheet"?> 
<Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" 
      xmlns:o="urn:schemas-microsoft-com:office:office" 
      xmlns:x="urn:schemas-microsoft-com:office:excel" 
      xmlns="urn:schemas-microsoft-com:office:spreadsheet"> 
    <Worksheet ss:Name="Worksheet1"> 
    <Table> 
     <Column ss:Width="100"></Column> 

     <Row> 
     <Cell ss:Index="1" ss:StyleID="headerStyle"> 
      <Data ss:Type="String">Submitted By</Data> 
     </Cell> 
     </Row> 
     <Row> 
     <Cell ss:Index="1" ss:StyleID="alternatingItemStyle"> 
      <Data ss:Type="String">Value1-0</Data> 
     </Cell> 
     </Row> 
    </Table> 
    <AutoFilter xmlns="urn:schemas-microsoft-com:office:excel" 
       x:Range="R1C1:R1C5"></AutoFilter> 
    </Worksheet> 
</Workbook> 

El problema es cuando se trata de seleccionar filas con

<xsl:for-each select="//Row"> 
    <xsl:copy-of select="."/> 
    </xsl:for-each> 

No es coincidente. Eliminé todo el espaciado entre nombres y funciona bien. Entonces, ¿cómo obtengo el 'seleccionar' para que coincida con Row?

Respuesta

28

declarar un prefijo de espacio de nombres para el espacio de nombres en su XSLT y luego select usando ese prefijo:

<xsl:stylesheet ... xmlns:os="urn:schemas-microsoft-com:office:spreadsheet"> 
    ... 
    <xsl:for-each select="//os:Row"> 
    ... 
    </xsl:for-each> 
    ... 
</xsl:stylesheet> 

Esto usualmente resulta en XPaths que son fáciles de leer. Sin embargo, las herramientas XSLT/XPath generan la siguiente, código equivalente:

<xsl:for-each select="//*[local-name()='Row' = and namespace-uri()='urn:schemas-microsoft-com:office:spreadsheet']"> 
    ... 
</xsl:for-each> 
+2

Este último parece ser más conciso. Gracias. –

10

Si no se preocupan por el espacio de nombres, puede utilizar el `local-name XPath) función (':

<xsl:for-each select="//*[local-name() = 'Row']"> 
    <xsl:copy-of select="."/> 
</xsl:for-each> 

Alternativamente, el mismo lo mismo se puede expresar como este. No estoy seguro de si esto es XPath estándar y si todas las implementaciones de XPath lo admiten (ColdFusion sí, por lo que probablemente Java también lo haga). Tal vez alguien sepa si esto se ajusta a cualquier estándar.

<xsl:for-each select="//:Row"> 
    <xsl:copy-of select="."/> 
</xsl:for-each> 
+1

Esta prueba QName '*: local name' es válida sólo en XSLT/XPath 2.0 –

+0

Esta solución es un poco sucio, pero eficaz. También resolvió mi problema (de tratar de seleccionar un nodo hijo resbaladizo con espacios de nombres). –

+0

@Kevin ¿Qué parte de esto? ¿Primero o segundo? – Tomalak

7

Tomalek y ckarras dar buenas respuestas, pero quiero aclarar las razones detrás de ellos.

Los elementos que no son coincidentes están en el espacio de nombres predeterminado del alcance en que se producen en el doc, es decir, que están en el espacio de nombres declarado para que alcance sin un prefijo (por ejemplo

xmlns="urn:schemas-microsoft-com:office:spreadsheet" 

en el elemento Workbook). Aunque los nombres de etiqueta carecen de un prefijo de espacio de nombres, están en un espacio de nombres.

Sin embargo, XPath requiere que todos los nombres de elementos en un espacio de nombres se califiquen con un prefijo, o que el espacio de nombre se especifique explícitamente con namespace-uri() en un predicado. Por lo tanto, debe utilizar la función local-name() en un predicado para que coincida con el nombre del elemento (y utilizar la función namespace-uri() así si hay un peligro de conflictos de nombres entre espacios de nombre), o debe declarar cada espacio de nombres en el que desea para que coincida con los elementos en XPaths con un prefijo, y califique los nombres de los elementos con sus prefijos de espacio de nombres en las expresiones XPath.

Cuestiones relacionadas