2008-10-08 29 views
35

मैं एक्सएसएलटी का उपयोग करते हुए, dokuwiki द्वारा उपयोग किए गए मार्कअप में एक एक्सएमएल फ़ाइल को परिवर्तित करने की कोशिश कर रहा हूं। यह वास्तव में कुछ डिग्री के लिए काम करता है, लेकिन एक्सएसएल फ़ाइल में इंडेंटेशन परिणामों में डाला जा रहा है। फिलहाल, मेरे पास दो विकल्प हैं: इस एक्सएसएलटी चीज को पूरी तरह से छोड़ दें, और एक्सएमएल से डॉक्यूविकी मार्कअप में कनवर्ट करने के लिए एक और तरीका ढूंढें, या एक्सएसएल फ़ाइल से व्हाइटस्पेस के लगभग 9 5% को हटा दें, जिससे इसे ना-अपठनीय और रखरखाव दुःस्वप्न बना दिया जा सके।एक्सएमएल को सादा पाठ में कनवर्ट करना - एक्सएसएलटी में व्हाइटस्पेस को कैसे अनदेखा/संभालना चाहिए?

क्या अंतिम दस्तावेज़ पर उस व्हाइटस्पेस को पार किए बिना एक्सएसएल फ़ाइल में इंडेंटेशन रखने का कोई तरीका है?

पृष्ठभूमि: मैं स्थैतिक HTML पृष्ठों से dokuwiki पर एक ऑटोडोक टूल माइग्रेट कर रहा हूं, इसलिए सर्वर टीम द्वारा विकसित एपीआई को एप्लिकेशन टीम द्वारा आगे दस्तावेज किया जा सकता है जब भी ऐप टीम खराब-दस्तावेज कोड में चलाती है। तर्क यह है कि ऑटोडोक टूल के लिए अलग-अलग सेट किए गए प्रत्येक पृष्ठ का एक अनुभाग है, और इस ब्लॉक के बाहर कहीं भी टिप्पणियों की अनुमति देना है। मैं एक्सएसएलटी का उपयोग कर रहा हूं क्योंकि हमारे पास पहले से एक्सएसएल फ़ाइल एक्सएमएल से एक्सएचटीएमएल में परिवर्तित करने के लिए है, और मुझे लगता है कि एक्सएसएल को स्क्रैच से अपना खुद का समाधान रोल करने के बजाय इसे फिर से लिखना तेज होगा।

संपादित करें: आह, सही, मूर्ख मुझे, मैंने इंडेंट विशेषता को उपेक्षित किया। (अन्य पृष्ठभूमि नोट: मैं एक्सएसएलटी के लिए नया हूं।) दूसरी तरफ, मुझे अभी भी न्यूलाइन से निपटना होगा। Dokuwiki तालिका कॉलम के बीच अंतर करने के लिए पाइप का उपयोग करता है, जिसका अर्थ है कि एक तालिका रेखा में मौजूद सभी डेटा एक पंक्ति पर होना चाहिए। आउटपुट किए जाने वाले न्यूलाइन को दबाने का कोई तरीका है (केवल कभी-कभी), इसलिए मैं कुछ टेबल सेल के लिए कुछ हद तक जटिल तर्क कर सकता हूं?

उत्तर

75

वहाँ एक XSLT परिवर्तन के परिणाम में अवांछित खाली स्थान के प्राप्त करने के लिए तीन कारण हैं:

  1. खाली स्थान के उस स्रोत दस्तावेज़ में नोड्स के बीच से आता है
  2. खाली स्थान के उस स्रोत दस्तावेज़ में नोड्स के भीतर से आता है
  3. खाली स्थान के कि स्टाइलशीट

मैं सभी तीन के बारे में बात करने जा रहा हूँ से आता है क्योंकि यह कहना मुश्किल हो सकता है कि व्हाइटस्पेस कहां से आता है ताकि आपको कई रणनीतियों का उपयोग करने की आवश्यकता हो।

खाली स्थान के अपने स्रोत दस्तावेज़ में नोड्स के बीच है कि समाधान के लिए, आप <xsl:strip-space> का उपयोग करना चाहिए कोई श्वेत रिक्ति कि दो नोड्स के बीच प्रकट होता है को निकाल देते हैं, और फिर <xsl:preserve-space> का उपयोग महत्वपूर्ण खाली स्थान के कि मिश्रित सामग्री के भीतर प्रकट हो सकता है की रक्षा करने के।उदाहरण के लिए, अपने स्रोत दस्तावेज़ लग रहा है, तो जैसे:

<ul> 
    <li>This is an <strong>important</strong> <em>point</em></li> 
</ul> 

तो आप <ul> और <li> के बीच और </li> और </ul> है, जो महत्वपूर्ण नहीं है के बीच खाली स्थान के ध्यान न दें, लेकिन बीच खाली स्थान के सुरक्षित रखना चाहते हैं जाएगा <strong> और <em> तत्व, जो महत्वपूर्ण है (अन्यथा आपको "यह एक ** महत्वपूर्ण *** बिंदु *" प्राप्त होगा)। इस प्रयोग के

<xsl:strip-space elements="*" /> 
<xsl:preserve-space elements="li" /> 

<xsl:preserve-space> पर elements विशेषता मूल रूप से सामग्री मिश्रित है कि अपने दस्तावेज़ में सभी तत्वों को सूचीबद्ध करना चाहिए ऐसा करने के लिए।

एक तरफ: <xsl:strip-space> का उपयोग कर भी स्मृति में स्रोत पेड़ के आकार को कम कर देता है, और अपने स्टाइलशीट अधिक कुशल बनाता है, इसलिए भले ही आप इस तरह की खाली स्थान के समस्या नहीं है यह कर योग्य है।

अपने स्रोत दस्तावेज़ में नोड्स के भीतर दिखाई देने वाली व्हाइटस्पेस को संबोधित करने के लिए, आपको normalize-space() का उपयोग करना चाहिए। उदाहरण के लिए, यदि आपके पास:

<dt> 
    a definition 
</dt> 

और आप यह सुनिश्चित करें कि <dt> तत्व आप जिन तत्वों को साथ कुछ करना चाहता हूँ पकड़ नहीं होगा हो सकता है, तो आप कर सकते हैं:

<xsl:template match="dt"> 
    ... 
    <xsl:value-of select="normalize-space(.)" /> 
    ... 
</xsl:template> 

अग्रणी और पिछली सफेद जगह <dt> तत्व के मान से अलग हो जाएगी और आपको केवल स्ट्रिंग "a definition" मिल जाएगी।

खाली स्थान के स्टाइलशीट, जो शायद एक आप अनुभव कर रहे है से आ रही करने के लिए, जब आप इस तरह एक टेम्पलेट के भीतर पाठ है:

<xsl:template match="name"> 
    Name: 
    <xsl:value-of select="." /> 
</xsl:template> 

XSLT स्टाइलशीट के रूप में एक ही तरीके से पार्स कर रहे हैं स्रोत दस्तावेज़ जो वे संसाधित करते हैं, इसलिए उपर्युक्त एक्सएसएलटी को एक पेड़ के रूप में व्याख्या किया जाता है जिसमें तत्व match विशेषता वाला होता है जिसका पहला बच्चा एक टेक्स्ट नोड होता है और जिसका दूसरा बच्चा विशेषता वाला <xsl:value-of> तत्व है। टेक्स्ट नोड में अग्रणी और पीछे की जगह है (लाइन ब्रेक सहित); चूंकि यह स्टाइलशीट में शाब्दिक पाठ है, इसलिए यह सभी प्रमुख और पिछली सफेद जगहों के साथ, परिणामस्वरूप सचमुच कॉपी हो जाता है।

लेकिन कुछ एक्सएसएलटी स्टाइलशीट में व्हाइटस्पेस स्वचालित रूप से नोड्स के बीच छीन लिया जाता है। आपको अपने परिणाम में लाइन ब्रेक नहीं मिलता है क्योंकि <xsl:value-of> और <xsl:template> के बीच एक लाइन ब्रेक है।

केवल पाठ आप परिणाम में चाहते हैं पाने के लिए, <xsl:text> तत्व इस तरह का उपयोग करें:

<xsl:template match="name"> 
    <xsl:text>Name: </xsl:text> 
    <xsl:value-of select="." /> 
</xsl:template> 

XSLT प्रोसेसर लाइन टूट जाता है और खरोज कि नोड्स के बीच दिखाई देते हैं पर ध्यान नहीं देगा, और केवल उत्पादन पाठ के भीतर <xsl:text> तत्व।

+0

यह बेहद सहायक था! धन्यवाद। – Black

+0

जो वास्तव में सहायक था, लेकिन मैं "नोड्स के बीच" वाक्यांश के उपयोग से परेशान हूं। क्या यह सच नहीं है कि सभी व्हाइटस्पेस टेक्स्ट नोड्स में निहित है? "नोड्स के बीच" का क्या मतलब है? अगर मैंने आपका नाम पहचाना नहीं है तो मुझे लगता होगा कि आपको XML दस्तावेज़ संरचना पर एक व्याख्यान की आवश्यकता है। – LarsH

+0

अच्छा लेख, धन्यवाद! लेकिन कड़ाई से बोलते हुए, आप 'नोड' शब्द का उपयोग कर रहे हैं जहां आप वास्तव में 'तत्व' का अर्थ रखते हैं। – rustyx

4

क्या आप अपने आउटपुट टैग में इंडेंट = "नहीं" का उपयोग कर रहे हैं?

<xsl:output method="text" indent="no" /> 

इसके अलावा, आप XSL उपयोग कर रहे हैं: क्या आप-का मूल्य अक्षम-उत्पादन-एस्केपिंग = उपयोग कर सकते हैं "हाँ" कुछ खाली स्थान के मुद्दों के साथ मदद करने के लिए। इस उदाहरण लाइन की जगह

<xsl:template name="replace.string.section"> 
    <xsl:param name="in.string"/> 
    <xsl:param name="in.characters"/> 
    <xsl:param name="out.characters"/> 
    <xsl:choose> 
    <xsl:when test="contains($in.string,$in.characters)"> 
     <xsl:value-of select="concat(substring-before($in.string,$in.characters),$out.characters)"/> 
     <xsl:call-template name="replace.string.section"> 
     <xsl:with-param name="in.string" select="substring-after($in.string,$in.characters)"/> 
     <xsl:with-param name="in.characters" select="$in.characters"/> 
     <xsl:with-param name="out.characters" select="$out.characters"/> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="$in.string"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

यह इस प्रकार कॉल (:

+4

अधिकांश समय, 'अक्षम-आउटपुट-एस्केपिंग' का उपयोग करना चीजों को करने का गलत तरीका है। यह केवल बहुत सीमित स्थितियों के लिए है। ऐसे किसी सामान्य तरीके से डी-ओ-ई की वकालत करना जो बेहतर नहीं जानता है, शायद मददगार से अधिक हानिकारक है। देखें http://www.dpawson.co.uk/xsl/sect2/N2215.html#d3702e223 – LarsH

0

नई लाइनों के बारे में अपनी संपादित करें के बारे में, आप रिकर्सिवली एक और स्ट्रिंग के भीतर एक स्ट्रिंग को बदलने के लिए इस टेम्पलेट का उपयोग कर सकते हैं, और आप लाइन ब्रेक के लिए उपयोग कर सकते हैं एक स्थान के साथ $ some.string चर में टूट जाता है):

<xsl:call-template name="replace.string.section"> 
     <xsl:with-param name="in.string" select="$some.string"/> 
     <xsl:with-param name="in.characters" select="'&#xA;'"/> 
     <xsl:with-param name="out.characters" select="' '"/> 
    </xsl:call-template> 
3

@ जेनीटी का जवाब बहुत अच्छा है, मैं सिर्फ व्हाइटस्पेस के प्रबंधन के लिए एक चाल को इंगित करना चाहता हूं। मुझे यकीन नहीं है कि यह सबसे अच्छा तरीका है (या यहां तक ​​कि एक अच्छा तरीका), लेकिन यह मेरे लिए अभी काम करता है।

<?xml version="1.0" encoding="UTF-8"?> 
<foo bar="bar" baz="baz" abc="abc" xyz="xyz"></foo> 

आउटपुट:

(। अंतरिक्ष के लिए "एस", खाली लिए "e", "n" न्यू लाइन के लिए)

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE xsl:transform [ 
    <!ENTITY s "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> </xsl:text>" > 
    <!ENTITY s2 "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> </xsl:text>" > 
    <!ENTITY s4 "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> </xsl:text>" > 
    <!ENTITY s6 "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>  </xsl:text>" > 
    <!ENTITY e "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'></xsl:text>" > 
    <!ENTITY n "<xsl:text xmlns:xsl='http://www.w3.org/1999/XSL/Transform'> 
</xsl:text>" > 
]> 

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
<xsl:output method="text"/> 
<xsl:template match="/"> 
    &e;Flush left, despite the indentation.&n; 
    &e; This line will be output indented two spaces.&n; 

     <!-- the blank lines above/below won't be output --> 

    <xsl:for-each select="//foo"> 
    &e; Starts with two blanks: <xsl:value-of select="@bar"/>.&n; 
    &e; <xsl:value-of select="@baz"/> The 'e' trick won't work here.&n; 
    &s2;<xsl:value-of select="@baz"/> Use s2 instead.&n; 
    &s2; <xsl:value-of select="@abc"/> <xsl:value-of select="@xyz"/>&n; 
    &s2; <xsl:value-of select="@abc"/>&s;<xsl:value-of select="@xyz"/>&n; 
    </xsl:for-each> 
</xsl:template> 
</xsl:transform> 

लागू

Flush left, despite the indentation. 
    This line will be output indented two spaces. 
    Starts with two blanks: bar. 
baz The 'e' trick won't work here. 
    baz Use s2 instead. 
    abcxyz 
    abc xyz 

'ई' चाल कम से कम एक गैर-व्हाइटस्पेस वर्ण वाले टेक्स्ट नोड से पहले काम करती है क्योंकि यह इस तक फैली हुई है:

<xsl:template match="/"> 
    <xsl:text></xsl:text>Flush left, despite the indentation.<xsl:text> 
</xsl:text> 

rules for stripping whitespace के बाद का कहना है कि खाली स्थान के केवल-पाठ नोड्स छीन करें, NEWLINE और खरोज < XSL के बीच: टेम्पलेट > और < XSL: पाठ > छीन हो (अच्छा)। चूंकि नियम कहते हैं कि कम से कम एक व्हाइटस्पेस चरित्र के साथ एक टेक्स्ट नोड संरक्षित है, " This line will be output indented two spaces." युक्त अंतर्निहित टेक्स्ट नोड अपने अग्रणी व्हाइटस्पेस को रखता है (लेकिन मुझे लगता है कि यह स्ट्रिप/संरक्षित/सामान्यीकृत करने के लिए सेटिंग्स पर भी निर्भर करता है)। "& एन;" लाइन के अंत में एक नई लाइन डालें, लेकिन यह भी सुनिश्चित करता है कि किसी भी निम्नलिखित व्हाइटस्पेस को अनदेखा कर दिया जाए, क्योंकि यह दो नोड्स के बीच दिखाई देता है।

मेरी समस्या यह है कि जब मैं < xsl से शुरू होने वाली इंडेंट लाइन आउटपुट करना चाहता हूं: > का मान। उस स्थिति में, "& ई;" मदद नहीं करेगा, क्योंकि इंडेंटेशन व्हाइटस्पेस किसी भी गैर-व्हाइटस्पेस वर्णों से "संलग्न" नहीं है। तो उन मामलों के लिए, मैं "& एस 2 का उपयोग करता हूं;" या "& एस 4;", इस पर निर्भर करता है कि मैं कितना इंडेंटेशन चाहता हूं।

यह एक बदसूरत हैक मुझे यकीन है, लेकिन कम से कम मैं वर्बोज़ "< XSL: पाठ >" की जरूरत नहीं है टैग मेरी XSLT कचरा, और कम से कम मैं अभी भी XSLT ही इंडेंट कर सकते हैं तो यह सुपाठ्य है। मुझे लगता है कि मैं एक्सएसएलटी का दुरुपयोग कर रहा हूं जिसके लिए इसे डिजाइन नहीं किया गया था (पाठ प्रसंस्करण) और यह सबसे अच्छा है जो मैं कर सकता हूं।


संपादित करें: टिप्पणियों के जवाब में, यह है कि क्या यह "मैक्रो" बिना की तरह लग रहा है:

<xsl:template match="/"> 
    <xsl:text>Flush left, despite the indentation.</xsl:text> 
    <xsl:text> This line will be output indented two spaces.</xsl:text> 
    <xsl:for-each select="//foo"> 
    <xsl:text> Starts with two blanks: </xsl:text><xsl:value-of select="@bar"/>.<xsl:text> 
</xsl:text> 
    <xsl:text> </xsl:text><xsl:value-of select="@abc"/><xsl:text> </xsl:text><xsl:value-of select="@xyz"/><xsl:text> 
</xsl:text> 
    </xsl:for-each> 
</xsl:template> 

मुझे लगता है कि यह इरादा उत्पादन खरोज को देखने के लिए कम स्पष्ट करता है, और यह एक्सएसएल के इंडेंटेशन को ही खराब कर देता है क्योंकि </xsl:text> एंड टैग को एक्सएसएल फ़ाइल के कॉलम 1 पर दिखाना पड़ता है (अन्यथा आपको आउटपुट फाइल में अवांछित व्हाइटस्पेस मिलता है)।

+0

@Dan: सबसे पहले, 'xsl: text' यह verbose नहीं है, और आप हमेशा' xsl: value पर concat का उपयोग कर सकते हैं दूसरा।, आप पाठ संसाधित नहीं कर रहे हैं, आपका आउटपुट सादा पाठ है। –

+0

@ डैन: आखिरी। आपका समाधान एक्सएसएलटी के खिलाफ है क्योंकि उन संस्थाओं (ठीक से घोषित) एक्सएमएल दस्तावेज़ की सतह वाक्यविन्यास का हिस्सा हैं (स्टाइलशीट, इस मामले में)। इसलिए, प्रतिस्थापन को एक्सएसएलटी प्रोसेसर तक पहुंचने से पहले पार्सिंग फेज में समय लगता है। एक बार प्रतिस्थापन किया गया था और स्टाइलशीट में ** नए तत्व ** हैं, व्हाइटस्पेस को अलग करने/संरक्षित करने के नियम केवल टेक्स्ट नोड्स लागू होते हैं। पाठक के दृष्टिकोण से, यह स्पष्ट नहीं होगा कि आपका स्टाइलशीट परिणाम क्या होगा। –

+0

@Alejandro: प्रतिक्रिया के लिए धन्यवाद। मुझे लगता है कि यह वर्बोज़ नहीं है यदि आप पहले ही एक्सएमएल के आदी हैं ... मेरी पृष्ठभूमि अधिक लेक्स/yacc/सी ++ है इसलिए मैं निश्चित रूप से महसूस कर रहा हूँ यहां मेरे तत्व का। मुझे लगता है कि एक एक्सएमएल संपादक बनाम एक टेक्स्ट एडिटर का उपयोग करने में मदद मिल सकती है। – Dan