WordprocessingDocument отделяет текст (без необходимости)
Я пытаюсь заменить определенные места в моем текстовом документе, который действует как шаблон. Эти места отмечены как слова, начинающиеся с @
, Например @Name
, Я выбираю все тексты, пробегаю их со своей функцией и заменяю. Вся логика за этим работает нормально. Однако по неизвестной мне причине тексты, которые определяются просто так:
List<Text> texts = w.MainDocumentPart.Document.Descendants<Text>().ToList();
не так, как я ожидаю. Например (краткий список текстов, где по одному тексту в каждой строке):
Document date:
@
date
, written by:
@Name
@
Surname
хотя это должно было быть в одной строке, как это: Document date: @date, written by: @Name @Surname
, Как видите, в таких случаях @
а также date
ИЛИ ЖЕ @
а также Surname
Я не могу правильно использовать метод замены, потому что нет @date
ни @Surname
активно на месте. Так что я улучшил свой код, но теперь я вижу много недостатков в этом, так что он соединяется без учета @
к следующему тексту. К сожалению, я пришел к одному тексту в таблице, который полностью уничтожил весь мой алгоритм. Это было так:
(@
sum_
words)
хотя я специально не форматировал его разными стилями. Итак, как вы можете видеть, это должно было быть (@sum_words)
, который, в этом случае, мой алгоритм легко заменить. К сожалению, я не могу. Таким образом, мои вопросы будут такими:
- Почему он разделяется на части, хотя я не отличал части слова?
- Есть ли способ решить эту проблему, чтобы мои тексты не были повреждены?
ОБНОВИТЬ
Лучшее, что я смог сделать, это:
for (int i = texts.Count - 1; i > 0; i--)
{
if (texts[i - 1].Text.EndsWith("@") || texts[i - 1].Text.EndsWith("_"))
{
texts[i - 1].Text = texts[i - 1].Text + texts[i].Text;
texts[i].Text = "";
}
}
который связывает тексты, если они разделены на полпути (из того, что я видел, они разделяются только на символы, которые соответствуют моим потребностям, которые @
а также _
, Цикл перевернут, потому что имеет больше смысла сохранять свойства первой текстовой части в группе, а не последней (например, сохранять интервал перед элементами).
ОБНОВЛЕНИЕ 2
Вот запрашиваемая ячейка таблицы:
<w:tc>
<w:tcPr>
<w:tcW w:w="2410" w:type="dxa"/>
<w:tcBorders>
<w:top w:val="single" w:sz="4" w:space="0" w:color="auto"/>
<w:left w:val="single" w:sz="4" w:space="0" w:color="auto"/>
<w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto"/>
<w:right w:val="single" w:sz="4" w:space="0" w:color="auto"/>
</w:tcBorders>
<w:shd w:val="clear" w:color="auto" w:fill="auto"/>
</w:tcPr>
<w:p w:rsidR="009D473B" w:rsidRDefault="00385754" w:rsidP="00385754">
<w:pPr>
<w:jc w:val="center"/>
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
<w:t>@sum</w:t>
</w:r>
<w:r w:rsidR="009D473B">
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
<w:t xml:space="preserve">(@</w:t>
</w:r>
<w:r>
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
<w:t>sum_</w:t>
</w:r>
<w:r w:rsidR="009D473B">
<w:rPr>
<w:lang w:val="lt-LT"/>
</w:rPr>
<w:t>words)</w:t>
</w:r>
</w:p>
</w:tc>
1 ответ
Единственные проблемы, которые у меня возникали при замене переменных в документах WordML, были вызваны модулем орфографии и грамматики, который, как правило, вставляет специальные теги, которые ломают имена переменных, что решается путем деактивации полной проверки и маркировки грамматических ошибок в Word во время редактирования шаблона.
Мой метод замены выглядит примерно так (мое соглашение о присвоении имен переменным немного отличается, этот адаптируется к вашему):
public static void Assign(XElement xe, string name, string value)
{
XElement el = xe.Descendants()
.FirstOrDefault(e => e.Name.LocalName == "t" && e.Value.Contains("(@" + name + ")"));
if (el != null)
{
el.Value = el.Value.Replace("(@" + name + ")", value);
}
else
{
AssignFallback(xe, name, value);
}
}
РЕДАКТИРОВАТЬ 2
Я написал запасной метод замены переменной в случае, если вышеприведенное не работает (случай el == null) выше. Абзац w:p может содержать несколько прогонов, и имя нашей переменной может быть разбито на непрерывную серию прогонов. Поэтому мы хотим идентифицировать их и заменить значение только в первую очередь, удаляя остальные. Мы должны быть осторожны, чтобы сохранить текст, который мог появиться до имени переменной de и после (префикс будет в первом запуске и суффикс в последнем).
public static void AssignFallback(XElement xe, string name, string value)
{
string varName = "(@" + name + ")";
XElement xep = xe.Descendants()
.FirstOrDefault(x => x.Name.LocalName == "p" && x.Value.Contains(varName));
if (xep == null)
{
return;
}
string prefix = "", sufix = "";
List<XElement> truns = new List<XElement>();
List<XElement> allruns = xep.Descendants().Where(x => x.Name.LocalName == "r").ToList();
for (int i = 0; i < allruns.Count; i++)
{
if (!allruns[i].Value.Contains("(@"))
{
continue;
}
int index = allruns[i].Value.IndexOf("(@");
prefix = allruns[i].Value.Substring(0, index);
truns.Clear();
truns.Add(allruns[i]);
string nameTemp = allruns[i].Value.Substring(index, allruns[i].Value.Length - index);
if (!varName.StartsWith(nameTemp))
{
continue;
}
for (int j = i + 1; j < allruns.Count; j++)
{
nameTemp += allruns[j].Value;
truns.Add(allruns[j]);
if (nameTemp.StartsWith(varName))
{
sufix = nameTemp.Substring(varName.Length);
break;
}
else if (nameTemp.Length > varName.Length)
{
break;
}
}
if (nameTemp.StartsWith(varName))
{
XElement xet = truns[0].Descendants().FirstOrDefault(x => x.Name.LocalName == "t");
xet.Value = prefix + value + sufix;
for (int j = 1; j < truns.Count; j++)
{
truns[j].Remove();
}
}
}
}